00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "debug.h"
00008 #include "player_func.h"
00009 #include "station.h"
00010 #include "engine.h"
00011 #include "gui.h"
00012 #include "window_gui.h"
00013 #include "textbuf_gui.h"
00014 #include "command_func.h"
00015 #include "variables.h"
00016 #include "vehicle_gui.h"
00017 #include "viewport_func.h"
00018 #include "gfx_func.h"
00019 #include "train.h"
00020 #include "newgrf_callbacks.h"
00021 #include "newgrf_engine.h"
00022 #include "newgrf_text.h"
00023 #include "ship.h"
00024 #include "aircraft.h"
00025 #include "roadveh.h"
00026 #include "depot.h"
00027 #include "cargotype.h"
00028 #include "group.h"
00029 #include "group_gui.h"
00030 #include "strings_func.h"
00031 #include "functions.h"
00032 #include "window_func.h"
00033 #include "vehicle_func.h"
00034 #include "autoreplace_gui.h"
00035 #include "core/alloc_func.hpp"
00036 #include "string_func.h"
00037 #include "settings_type.h"
00038 #include "widgets/dropdown_func.h"
00039
00040 #include "table/sprites.h"
00041 #include "table/strings.h"
00042
00043 struct Sorting {
00044 Listing aircraft;
00045 Listing roadveh;
00046 Listing ship;
00047 Listing train;
00048 };
00049
00050 static Sorting _sorting;
00051
00052 static bool _internal_sort_order;
00053
00054 typedef int CDECL VehicleSortListingTypeFunction(const void*, const void*);
00055
00056 static VehicleSortListingTypeFunction VehicleNumberSorter;
00057 static VehicleSortListingTypeFunction VehicleNameSorter;
00058 static VehicleSortListingTypeFunction VehicleAgeSorter;
00059 static VehicleSortListingTypeFunction VehicleProfitThisYearSorter;
00060 static VehicleSortListingTypeFunction VehicleProfitLastYearSorter;
00061 static VehicleSortListingTypeFunction VehicleCargoSorter;
00062 static VehicleSortListingTypeFunction VehicleReliabilitySorter;
00063 static VehicleSortListingTypeFunction VehicleMaxSpeedSorter;
00064 static VehicleSortListingTypeFunction VehicleModelSorter;
00065 static VehicleSortListingTypeFunction VehicleValueSorter;
00066
00067 static VehicleSortListingTypeFunction* const _vehicle_sorter[] = {
00068 &VehicleNumberSorter,
00069 &VehicleNameSorter,
00070 &VehicleAgeSorter,
00071 &VehicleProfitThisYearSorter,
00072 &VehicleProfitLastYearSorter,
00073 &VehicleCargoSorter,
00074 &VehicleReliabilitySorter,
00075 &VehicleMaxSpeedSorter,
00076 &VehicleModelSorter,
00077 &VehicleValueSorter,
00078 };
00079
00080 const StringID _vehicle_sort_listing[] = {
00081 STR_SORT_BY_NUMBER,
00082 STR_SORT_BY_DROPDOWN_NAME,
00083 STR_SORT_BY_AGE,
00084 STR_SORT_BY_PROFIT_THIS_YEAR,
00085 STR_SORT_BY_PROFIT_LAST_YEAR,
00086 STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE,
00087 STR_SORT_BY_RELIABILITY,
00088 STR_SORT_BY_MAX_SPEED,
00089 STR_SORT_BY_MODEL,
00090 STR_SORT_BY_VALUE,
00091 INVALID_STRING_ID
00092 };
00093
00094 void RebuildVehicleLists()
00095 {
00096 Window* const *wz;
00097
00098 FOR_ALL_WINDOWS(wz) {
00099 Window *w = *wz;
00100
00101 switch (w->window_class) {
00102 case WC_TRAINS_LIST:
00103 case WC_ROADVEH_LIST:
00104 case WC_SHIPS_LIST:
00105 case WC_AIRCRAFT_LIST:
00106 WP(w, vehiclelist_d).l.flags |= VL_REBUILD;
00107 SetWindowDirty(w);
00108 break;
00109
00110 default: break;
00111 }
00112 }
00113 }
00114
00115 void ResortVehicleLists()
00116 {
00117 Window* const *wz;
00118
00119 FOR_ALL_WINDOWS(wz) {
00120 Window *w = *wz;
00121
00122 switch (w->window_class) {
00123 case WC_TRAINS_LIST:
00124 case WC_ROADVEH_LIST:
00125 case WC_SHIPS_LIST:
00126 case WC_AIRCRAFT_LIST:
00127 WP(w, vehiclelist_d).l.flags |= VL_RESORT;
00128 SetWindowDirty(w);
00129 break;
00130
00131 default: break;
00132 }
00133 }
00134 }
00135
00136 void BuildVehicleList(vehiclelist_d *vl, PlayerID owner, uint16 index, uint16 window_type)
00137 {
00138 if (!(vl->l.flags & VL_REBUILD)) return;
00139
00140 DEBUG(misc, 3, "Building vehicle list for player %d at station %d", owner, index);
00141
00142 vl->l.list_length = GenerateVehicleSortList(&vl->sort_list, &vl->length_of_sort_list, vl->vehicle_type, owner, index, window_type);
00143
00144 vl->l.flags &= ~VL_REBUILD;
00145 vl->l.flags |= VL_RESORT;
00146 }
00147
00148
00149 static const Vehicle *_last_vehicle[2] = { NULL, NULL };
00150 static char _last_name[2][64] = { "", "" };
00151
00152 void SortVehicleList(vehiclelist_d *vl)
00153 {
00154 if (!(vl->l.flags & VL_RESORT)) return;
00155
00156
00157 _last_vehicle[0] = _last_vehicle[1] = NULL;
00158
00159 _internal_sort_order = (vl->l.flags & VL_DESC) != 0;
00160 qsort((void*)vl->sort_list, vl->l.list_length, sizeof(vl->sort_list[0]),
00161 _vehicle_sorter[vl->l.sort_type]);
00162
00163 vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
00164 vl->l.flags &= ~VL_RESORT;
00165 }
00166
00167 void DepotSortList(Vehicle **v, uint16 length)
00168 {
00169 _internal_sort_order = 0;
00170 qsort((void*)v, length, sizeof(v[0]), _vehicle_sorter[0]);
00171 }
00172
00174 void DrawVehicleProfitButton(const Vehicle *v, int x, int y)
00175 {
00176 SpriteID pal;
00177
00178
00179 if (v->age <= 365 * 2) {
00180 pal = PALETTE_TO_GREY;
00181 } else if (v->GetDisplayProfitLastYear() < 0) {
00182 pal = PALETTE_TO_RED;
00183 } else if (v->GetDisplayProfitLastYear() < 10000) {
00184 pal = PALETTE_TO_YELLOW;
00185 } else {
00186 pal = PALETTE_TO_GREEN;
00187 }
00188 DrawSprite(SPR_BLOT, pal, x, y);
00189 }
00190
00191 struct RefitOption {
00192 CargoID cargo;
00193 byte subtype;
00194 uint16 value;
00195 EngineID engine;
00196 };
00197
00198 struct RefitList {
00199 uint num_lines;
00200 RefitOption *items;
00201 };
00202
00203 static RefitList *BuildRefitList(const Vehicle *v)
00204 {
00205 uint max_lines = 256;
00206 RefitOption *refit = CallocT<RefitOption>(max_lines);
00207 RefitList *list = CallocT<RefitList>(1);
00208 Vehicle *u = (Vehicle*)v;
00209 uint num_lines = 0;
00210 uint i;
00211
00212 do {
00213 uint32 cmask = EngInfo(u->engine_type)->refit_mask;
00214 byte callbackmask = EngInfo(u->engine_type)->callbackmask;
00215
00216
00217 if (u->cargo_cap == 0) continue;
00218
00219
00220 for (CargoID cid = 0; cid < NUM_CARGO && num_lines < max_lines; cid++) {
00221
00222 if (!HasBit(cmask, cid)) continue;
00223
00224
00225 if (HasBit(callbackmask, CBM_VEHICLE_CARGO_SUFFIX)) {
00226
00227
00228 CargoID temp_cargo = u->cargo_type;
00229 byte temp_subtype = u->cargo_subtype;
00230 byte refit_cyc;
00231
00232 u->cargo_type = cid;
00233
00234 for (refit_cyc = 0; refit_cyc < 16 && num_lines < max_lines; refit_cyc++) {
00235 bool duplicate = false;
00236 uint16 callback;
00237
00238 u->cargo_subtype = refit_cyc;
00239 callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, u->engine_type, u);
00240
00241 if (callback == 0xFF) callback = CALLBACK_FAILED;
00242 if (refit_cyc != 0 && callback == CALLBACK_FAILED) break;
00243
00244
00245 for (i = 0; i < num_lines && !duplicate; i++) {
00246 if (refit[i].cargo == cid && refit[i].value == callback) duplicate = true;
00247 }
00248
00249 if (duplicate) continue;
00250
00251 refit[num_lines].cargo = cid;
00252 refit[num_lines].subtype = refit_cyc;
00253 refit[num_lines].value = callback;
00254 refit[num_lines].engine = u->engine_type;
00255 num_lines++;
00256 }
00257
00258
00259 u->cargo_type = temp_cargo;
00260 u->cargo_subtype = temp_subtype;
00261 } else {
00262
00263 bool duplicate = false;
00264
00265 for (i = 0; i < num_lines && !duplicate; i++) {
00266 if (refit[i].cargo == cid && refit[i].value == CALLBACK_FAILED) duplicate = true;
00267 }
00268
00269 if (!duplicate) {
00270 refit[num_lines].cargo = cid;
00271 refit[num_lines].subtype = 0;
00272 refit[num_lines].value = CALLBACK_FAILED;
00273 refit[num_lines].engine = INVALID_ENGINE;
00274 num_lines++;
00275 }
00276 }
00277 }
00278 } while ((v->type == VEH_TRAIN || v->type == VEH_ROAD) && (u = u->Next()) != NULL && num_lines < max_lines);
00279
00280 list->num_lines = num_lines;
00281 list->items = refit;
00282
00283 return list;
00284 }
00285
00295 static RefitOption *DrawVehicleRefitWindow(const RefitList *list, int sel, uint pos, uint rows, uint delta)
00296 {
00297 RefitOption *refit = list->items;
00298 RefitOption *selected = NULL;
00299 uint num_lines = list->num_lines;
00300 uint y = 31;
00301 uint i;
00302
00303
00304 for (i = 0; i < num_lines; i++) {
00305 TextColour colour = TC_BLACK;
00306 if (sel == 0) {
00307 selected = &refit[i];
00308 colour = TC_WHITE;
00309 }
00310
00311 if (i >= pos && i < pos + rows) {
00312
00313 int last_x = DrawString(2, y, GetCargo(refit[i].cargo)->name, colour);
00314
00315
00316 if (refit[i].value != CALLBACK_FAILED) {
00317 DrawString(last_x + 1, y, GetGRFStringID(GetEngineGRFID(refit[i].engine), 0xD000 + refit[i].value), colour);
00318 }
00319 y += delta;
00320 }
00321
00322 sel--;
00323 }
00324
00325 return selected;
00326 }
00327
00328 static void VehicleRefitWndProc(Window *w, WindowEvent *e)
00329 {
00330 switch (e->event) {
00331 case WE_PAINT: {
00332 Vehicle *v = GetVehicle(w->window_number);
00333
00334 if (v->type == VEH_TRAIN) {
00335 uint length = CountVehiclesInChain(v);
00336
00337 if (length != WP(w, refit_d).length) {
00338
00339 free(WP(w, refit_d).list->items);
00340 free(WP(w, refit_d).list);
00341 WP(w, refit_d).list = BuildRefitList(v);
00342 WP(w, refit_d).length = length;
00343 }
00344 }
00345
00346 SetVScrollCount(w, WP(w, refit_d).list->num_lines);
00347
00348 SetDParam(0, v->index);
00349 DrawWindowWidgets(w);
00350
00351 WP(w, refit_d).cargo = DrawVehicleRefitWindow(WP(w, refit_d).list, WP(w, refit_d).sel, w->vscroll.pos, w->vscroll.cap, w->resize.step_height);
00352
00353 if (WP(w, refit_d).cargo != NULL) {
00354 CommandCost cost;
00355
00356 cost = DoCommand(v->tile, v->index, WP(w, refit_d).cargo->cargo | WP(w, refit_d).cargo->subtype << 8,
00357 DC_QUERY_COST, GetCmdRefitVeh(GetVehicle(w->window_number)->type));
00358
00359 if (CmdSucceeded(cost)) {
00360 SetDParam(0, WP(w, refit_d).cargo->cargo);
00361 SetDParam(1, _returned_refit_capacity);
00362 SetDParam(2, cost.GetCost());
00363 DrawString(2, w->widget[5].top + 1, STR_9840_NEW_CAPACITY_COST_OF_REFIT, TC_FROMSTRING);
00364 }
00365 }
00366 } break;
00367
00368 case WE_CLICK:
00369 switch (e->we.click.widget) {
00370 case 3: {
00371 int y = e->we.click.pt.y - w->widget[3].top;
00372 if (y >= 0) {
00373 WP(w, refit_d).sel = (y / (int)w->resize.step_height) + w->vscroll.pos;
00374 SetWindowDirty(w);
00375 }
00376 } break;
00377 case 6:
00378 if (WP(w, refit_d).cargo != NULL) {
00379 const Vehicle *v = GetVehicle(w->window_number);
00380
00381 if (WP(w, refit_d).order == INVALID_VEH_ORDER_ID) {
00382 int command = 0;
00383
00384 switch (v->type) {
00385 default: NOT_REACHED();
00386 case VEH_TRAIN: command = CMD_REFIT_RAIL_VEHICLE | CMD_MSG(STR_RAIL_CAN_T_REFIT_VEHICLE); break;
00387 case VEH_ROAD: command = CMD_REFIT_ROAD_VEH | CMD_MSG(STR_REFIT_ROAD_VEHICLE_CAN_T); break;
00388 case VEH_SHIP: command = CMD_REFIT_SHIP | CMD_MSG(STR_9841_CAN_T_REFIT_SHIP); break;
00389 case VEH_AIRCRAFT: command = CMD_REFIT_AIRCRAFT | CMD_MSG(STR_A042_CAN_T_REFIT_AIRCRAFT); break;
00390 }
00391 if (DoCommandP(v->tile, v->index, WP(w, refit_d).cargo->cargo | WP(w, refit_d).cargo->subtype << 8, NULL, command)) DeleteWindow(w);
00392 } else {
00393 if (DoCommandP(v->tile, v->index, WP(w, refit_d).cargo->cargo | WP(w, refit_d).cargo->subtype << 8 | WP(w, refit_d).order << 16, NULL, CMD_ORDER_REFIT)) DeleteWindow(w);
00394 }
00395 }
00396 break;
00397 }
00398 break;
00399
00400 case WE_RESIZE:
00401 w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
00402 w->widget[3].data = (w->vscroll.cap << 8) + 1;
00403 break;
00404
00405 case WE_DESTROY:
00406 free(WP(w, refit_d).list->items);
00407 free(WP(w, refit_d).list);
00408 break;
00409 }
00410 }
00411
00412
00413 static const Widget _vehicle_refit_widgets[] = {
00414 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00415 { WWT_CAPTION, RESIZE_NONE, 14, 11, 239, 0, 13, STR_983B_REFIT, STR_018C_WINDOW_TITLE_DRAG_THIS},
00416 { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 239, 14, 27, STR_983F_SELECT_CARGO_TYPE_TO_CARRY, STR_983D_SELECT_TYPE_OF_CARGO_FOR},
00417 { WWT_MATRIX, RESIZE_BOTTOM, 14, 0, 227, 28, 139, 0x801, STR_EMPTY},
00418 { WWT_SCROLLBAR, RESIZE_BOTTOM, 14, 228, 239, 28, 139, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00419 { WWT_PANEL, RESIZE_TB, 14, 0, 239, 140, 161, 0x0, STR_NULL},
00420 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 227, 162, 173, 0x0, STR_NULL},
00421 { WWT_RESIZEBOX, RESIZE_TB, 14, 228, 239, 162, 173, 0x0, STR_RESIZE_BUTTON},
00422 { WIDGETS_END},
00423 };
00424
00425 static const WindowDesc _vehicle_refit_desc = {
00426 WDP_AUTO, WDP_AUTO, 240, 174, 240, 174,
00427 WC_VEHICLE_REFIT, WC_VEHICLE_VIEW,
00428 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
00429 _vehicle_refit_widgets,
00430 VehicleRefitWndProc,
00431 };
00432
00437 void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order)
00438 {
00439 Window *w;
00440
00441 DeleteWindowById(WC_VEHICLE_REFIT, v->index);
00442
00443 w = AllocateWindowDescFront(&_vehicle_refit_desc, v->index);
00444 WP(w, refit_d).order = order;
00445
00446 if (w != NULL) {
00447 w->caption_color = v->owner;
00448 w->vscroll.cap = 8;
00449 w->resize.step_height = 14;
00450 WP(w, refit_d).sel = -1;
00451 WP(w, refit_d).list = BuildRefitList(v);
00452 if (v->type == VEH_TRAIN) WP(w, refit_d).length = CountVehiclesInChain(v);
00453 SetVScrollCount(w, WP(w, refit_d).list->num_lines);
00454
00455 switch (v->type) {
00456 case VEH_TRAIN:
00457 w->widget[3].tooltips = STR_RAIL_SELECT_TYPE_OF_CARGO_FOR;
00458 w->widget[6].data = STR_RAIL_REFIT_VEHICLE;
00459 w->widget[6].tooltips = STR_RAIL_REFIT_TO_CARRY_HIGHLIGHTED;
00460 break;
00461 case VEH_ROAD:
00462 w->widget[3].tooltips = STR_ROAD_SELECT_TYPE_OF_CARGO_FOR;
00463 w->widget[6].data = STR_REFIT_ROAD_VEHICLE;
00464 w->widget[6].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED;
00465 break;
00466 case VEH_SHIP:
00467 w->widget[3].tooltips = STR_983D_SELECT_TYPE_OF_CARGO_FOR;
00468 w->widget[6].data = STR_983C_REFIT_SHIP;
00469 w->widget[6].tooltips = STR_983E_REFIT_SHIP_TO_CARRY_HIGHLIGHTED;
00470 break;
00471 case VEH_AIRCRAFT:
00472 w->widget[3].tooltips = STR_A03E_SELECT_TYPE_OF_CARGO_FOR;
00473 w->widget[6].data = STR_A03D_REFIT_AIRCRAFT;
00474 w->widget[6].tooltips = STR_A03F_REFIT_AIRCRAFT_TO_CARRY;
00475 break;
00476 default: NOT_REACHED();
00477 }
00478 }
00479 }
00480
00482 uint ShowAdditionalText(int x, int y, uint w, EngineID engine)
00483 {
00484 uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL);
00485 if (callback == CALLBACK_FAILED) return 0;
00486
00487
00488 SetDParam(0, GetGRFStringID(GetEngineGRFID(engine), 0xD000 + callback));
00489 PrepareTextRefStackUsage(0);
00490 uint result = DrawStringMultiLine(x, y, STR_02BD, w);
00491 StopTextRefStackUsage();
00492 return result;
00493 }
00494
00496 uint ShowRefitOptionsList(int x, int y, uint w, EngineID engine)
00497 {
00498
00499 uint32 cmask = EngInfo(engine)->refit_mask;
00500
00501 uint32 lmask = _cargo_mask;
00502 char *b = _userstring;
00503
00504
00505 if (CountBits(cmask) <= 1) return 0;
00506
00507 b = InlineString(b, STR_PURCHASE_INFO_REFITTABLE_TO);
00508
00509 if (cmask == lmask) {
00510
00511 b = InlineString(b, STR_PURCHASE_INFO_ALL_TYPES);
00512 } else {
00513
00514
00515 if (CountBits(cmask ^ lmask) < CountBits(cmask)) {
00516 cmask ^= lmask;
00517 b = InlineString(b, STR_PURCHASE_INFO_ALL_BUT);
00518 }
00519
00520 bool first = true;
00521
00522
00523 for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
00524 if (!HasBit(cmask, cid)) continue;
00525
00526 if (b >= lastof(_userstring) - (2 + 2 * 4)) break;
00527
00528 if (!first) b = strecpy(b, ", ", lastof(_userstring));
00529 first = false;
00530
00531 b = InlineString(b, GetCargo(cid)->name);
00532 }
00533 }
00534
00535
00536 *b = '\0';
00537
00538
00539 assert(b < endof(_userstring));
00540
00541 return DrawStringMultiLine(x, y, STR_SPEC_USERSTRING, w);
00542 }
00543
00544
00545
00546 #define VEHICLEUNITNUMBERSORTER(r, a, b) {if (r == 0) {r = a->unitnumber - b->unitnumber;}}
00547
00548 static int CDECL VehicleNumberSorter(const void *a, const void *b)
00549 {
00550 const Vehicle* va = *(const Vehicle**)a;
00551 const Vehicle* vb = *(const Vehicle**)b;
00552 int r = va->unitnumber - vb->unitnumber;
00553
00554 return (_internal_sort_order & 1) ? -r : r;
00555 }
00556
00557 static int CDECL VehicleNameSorter(const void *a, const void *b)
00558 {
00559 const Vehicle* va = *(const Vehicle**)a;
00560 const Vehicle* vb = *(const Vehicle**)b;
00561 int r;
00562
00563 if (va != _last_vehicle[0]) {
00564 _last_vehicle[0] = va;
00565 SetDParam(0, va->index);
00566 GetString(_last_name[0], STR_VEHICLE_NAME, lastof(_last_name[0]));
00567 }
00568
00569 if (vb != _last_vehicle[1]) {
00570 _last_vehicle[1] = vb;
00571 SetDParam(0, vb->index);
00572 GetString(_last_name[1], STR_VEHICLE_NAME, lastof(_last_name[1]));
00573 }
00574
00575 r = strcmp(_last_name[0], _last_name[1]);
00576
00577 VEHICLEUNITNUMBERSORTER(r, va, vb);
00578
00579 return (_internal_sort_order & 1) ? -r : r;
00580 }
00581
00582 static int CDECL VehicleAgeSorter(const void *a, const void *b)
00583 {
00584 const Vehicle* va = *(const Vehicle**)a;
00585 const Vehicle* vb = *(const Vehicle**)b;
00586 int r = va->age - vb->age;
00587
00588 VEHICLEUNITNUMBERSORTER(r, va, vb);
00589
00590 return (_internal_sort_order & 1) ? -r : r;
00591 }
00592
00593 static int CDECL VehicleProfitThisYearSorter(const void *a, const void *b)
00594 {
00595 const Vehicle* va = *(const Vehicle**)a;
00596 const Vehicle* vb = *(const Vehicle**)b;
00597 int r = ClampToI32(va->GetDisplayProfitThisYear() - vb->GetDisplayProfitThisYear());
00598
00599 VEHICLEUNITNUMBERSORTER(r, va, vb);
00600
00601 return (_internal_sort_order & 1) ? -r : r;
00602 }
00603
00604 static int CDECL VehicleProfitLastYearSorter(const void *a, const void *b)
00605 {
00606 const Vehicle* va = *(const Vehicle**)a;
00607 const Vehicle* vb = *(const Vehicle**)b;
00608 int r = ClampToI32(va->GetDisplayProfitLastYear() - vb->GetDisplayProfitLastYear());
00609
00610 VEHICLEUNITNUMBERSORTER(r, va, vb);
00611
00612 return (_internal_sort_order & 1) ? -r : r;
00613 }
00614
00615 static int CDECL VehicleCargoSorter(const void *a, const void *b)
00616 {
00617 const Vehicle* va = *(const Vehicle**)a;
00618 const Vehicle* vb = *(const Vehicle**)b;
00619 const Vehicle* v;
00620 AcceptedCargo cargoa;
00621 AcceptedCargo cargob;
00622 int r = 0;
00623
00624 memset(cargoa, 0, sizeof(cargoa));
00625 memset(cargob, 0, sizeof(cargob));
00626 for (v = va; v != NULL; v = v->Next()) cargoa[v->cargo_type] += v->cargo_cap;
00627 for (v = vb; v != NULL; v = v->Next()) cargob[v->cargo_type] += v->cargo_cap;
00628
00629 for (CargoID i = 0; i < NUM_CARGO; i++) {
00630 r = cargoa[i] - cargob[i];
00631 if (r != 0) break;
00632 }
00633
00634 VEHICLEUNITNUMBERSORTER(r, va, vb);
00635
00636 return (_internal_sort_order & 1) ? -r : r;
00637 }
00638
00639 static int CDECL VehicleReliabilitySorter(const void *a, const void *b)
00640 {
00641 const Vehicle* va = *(const Vehicle**)a;
00642 const Vehicle* vb = *(const Vehicle**)b;
00643 int r = va->reliability - vb->reliability;
00644
00645 VEHICLEUNITNUMBERSORTER(r, va, vb);
00646
00647 return (_internal_sort_order & 1) ? -r : r;
00648 }
00649
00650 static int CDECL VehicleMaxSpeedSorter(const void *a, const void *b)
00651 {
00652 const Vehicle* va = *(const Vehicle**)a;
00653 const Vehicle* vb = *(const Vehicle**)b;
00654 int r;
00655
00656 if (va->type == VEH_TRAIN && vb->type == VEH_TRAIN) {
00657 r = va->u.rail.cached_max_speed - vb->u.rail.cached_max_speed;
00658 } else {
00659 r = va->max_speed - vb->max_speed;
00660 }
00661
00662 VEHICLEUNITNUMBERSORTER(r, va, vb);
00663
00664 return (_internal_sort_order & 1) ? -r : r;
00665 }
00666
00667 static int CDECL VehicleModelSorter(const void *a, const void *b)
00668 {
00669 const Vehicle* va = *(const Vehicle**)a;
00670 const Vehicle* vb = *(const Vehicle**)b;
00671 int r = va->engine_type - vb->engine_type;
00672
00673 VEHICLEUNITNUMBERSORTER(r, va, vb);
00674
00675 return (_internal_sort_order & 1) ? -r : r;
00676 }
00677
00678 static int CDECL VehicleValueSorter(const void *a, const void *b)
00679 {
00680 const Vehicle* va = *(const Vehicle**)a;
00681 const Vehicle* vb = *(const Vehicle**)b;
00682 const Vehicle *u;
00683 Money valuea = 0, valueb = 0;
00684
00685 for (u = va; u != NULL; u = u->Next()) valuea += u->value;
00686 for (u = vb; u != NULL; u = u->Next()) valueb += u->value;
00687
00688 int r = ClampToI32(valuea - valueb);
00689
00690 VEHICLEUNITNUMBERSORTER(r, va, vb);
00691
00692 return (_internal_sort_order & 1) ? -r : r;
00693 }
00694
00695 void InitializeGUI()
00696 {
00697 memset(&_sorting, 0, sizeof(_sorting));
00698 }
00699
00706 void ChangeVehicleViewWindow(const Vehicle *from_v, const Vehicle *to_v)
00707 {
00708 Window *w;
00709
00710 w = FindWindowById(WC_VEHICLE_VIEW, from_v->index);
00711 if (w != NULL) {
00712 w->window_number = to_v->index;
00713 WP(w, vp_d).follow_vehicle = to_v->index;
00714 SetWindowDirty(w);
00715
00716 w = FindWindowById(WC_VEHICLE_ORDERS, from_v->index);
00717 if (w != NULL) {
00718 w->window_number = to_v->index;
00719 SetWindowDirty(w);
00720 }
00721
00722 w = FindWindowById(WC_VEHICLE_REFIT, from_v->index);
00723 if (w != NULL) {
00724 w->window_number = to_v->index;
00725 SetWindowDirty(w);
00726 }
00727
00728 w = FindWindowById(WC_VEHICLE_DETAILS, from_v->index);
00729 if (w != NULL) {
00730 w->window_number = to_v->index;
00731 SetWindowDirty(w);
00732 }
00733
00734 w = FindWindowById(WC_VEHICLE_TIMETABLE, from_v->index);
00735 if (w != NULL) {
00736 w->window_number = to_v->index;
00737 SetWindowDirty(w);
00738 }
00739 }
00740 }
00741
00742 enum VehicleListWindowWidgets {
00743 VLW_WIDGET_CLOSEBOX = 0,
00744 VLW_WIDGET_CAPTION,
00745 VLW_WIDGET_STICKY,
00746 VLW_WIDGET_SORT_ORDER,
00747 VLW_WIDGET_SORT_BY_PULLDOWN,
00748 VLW_WIDGET_EMPTY_TOP_RIGHT,
00749 VLW_WIDGET_LIST,
00750 VLW_WIDGET_SCROLLBAR,
00751 VLW_WIDGET_OTHER_PLAYER_FILLER,
00752 VLW_WIDGET_AVAILABLE_VEHICLES,
00753 VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
00754 VLW_WIDGET_STOP_ALL,
00755 VLW_WIDGET_START_ALL,
00756 VLW_WIDGET_EMPTY_BOTTOM_RIGHT,
00757 VLW_WIDGET_RESIZE,
00758 };
00759
00760 static const Widget _vehicle_list_widgets[] = {
00761 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00762 { WWT_CAPTION, RESIZE_RIGHT, 14, 11, 247, 0, 13, 0x0, STR_018C_WINDOW_TITLE_DRAG_THIS},
00763 { WWT_STICKYBOX, RESIZE_LR, 14, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON},
00764 { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP},
00765 { WWT_DROPDOWN, RESIZE_NONE, 14, 81, 247, 14, 25, 0x0, STR_SORT_CRITERIA_TIP},
00766 { WWT_PANEL, RESIZE_RIGHT, 14, 248, 259, 14, 25, 0x0, STR_NULL},
00767 { WWT_MATRIX, RESIZE_RB, 14, 0, 247, 26, 169, 0x0, STR_NULL},
00768 { WWT_SCROLLBAR, RESIZE_LRB, 14, 248, 259, 26, 169, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00769
00770 { WWT_PANEL, RESIZE_RTB, 14, 0, 247, 170, 181, 0x0, STR_NULL},
00771
00772 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 105, 170, 181, 0x0, STR_AVAILABLE_ENGINES_TIP},
00773 { WWT_DROPDOWN, RESIZE_TB, 14, 106, 223, 170, 181, STR_MANAGE_LIST, STR_MANAGE_LIST_TIP},
00774
00775 { WWT_PUSHIMGBTN, RESIZE_TB, 14, 224, 235, 170, 181, SPR_FLAG_VEH_STOPPED, STR_MASS_STOP_LIST_TIP},
00776 { WWT_PUSHIMGBTN, RESIZE_TB, 14, 236, 247, 170, 181, SPR_FLAG_VEH_RUNNING, STR_MASS_START_LIST_TIP},
00777 { WWT_PANEL, RESIZE_RTB, 14, 248, 247, 170, 181, 0x0, STR_NULL},
00778 { WWT_RESIZEBOX, RESIZE_LRTB, 14, 248, 259, 170, 181, 0x0, STR_RESIZE_BUTTON},
00779 { WIDGETS_END},
00780 };
00781
00782 static void CreateVehicleListWindow(Window *w)
00783 {
00784 vehiclelist_d *vl = &WP(w, vehiclelist_d);
00785 uint16 window_type = w->window_number & VLW_MASK;
00786 PlayerID player = (PlayerID)GB(w->window_number, 0, 8);
00787
00788 vl->vehicle_type = (VehicleType)GB(w->window_number, 11, 5);
00789 vl->length_of_sort_list = 0;
00790 vl->sort_list = NULL;
00791 w->caption_color = player;
00792
00793
00794
00795 if (player == _local_player) {
00796 w->HideWidget(VLW_WIDGET_OTHER_PLAYER_FILLER);
00797 w->SetWidgetDisabledState(VLW_WIDGET_AVAILABLE_VEHICLES, window_type != VLW_STANDARD);
00798 } else {
00799 w->SetWidgetsHiddenState(true,
00800 VLW_WIDGET_AVAILABLE_VEHICLES,
00801 VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
00802 VLW_WIDGET_STOP_ALL,
00803 VLW_WIDGET_START_ALL,
00804 VLW_WIDGET_EMPTY_BOTTOM_RIGHT,
00805 WIDGET_LIST_END);
00806 }
00807
00808
00809 switch (vl->vehicle_type) {
00810 case VEH_TRAIN:
00811 w->widget[VLW_WIDGET_LIST].tooltips = STR_883D_TRAINS_CLICK_ON_TRAIN_FOR;
00812 w->widget[VLW_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_TRAINS;
00813 break;
00814
00815 case VEH_ROAD:
00816 w->widget[VLW_WIDGET_LIST].tooltips = STR_901A_ROAD_VEHICLES_CLICK_ON;
00817 w->widget[VLW_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_ROAD_VEHICLES;
00818 break;
00819
00820 case VEH_SHIP:
00821 w->widget[VLW_WIDGET_LIST].tooltips = STR_9823_SHIPS_CLICK_ON_SHIP_FOR;
00822 w->widget[VLW_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_SHIPS;
00823 break;
00824
00825 case VEH_AIRCRAFT:
00826 w->widget[VLW_WIDGET_LIST].tooltips = STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT;
00827 w->widget[VLW_WIDGET_AVAILABLE_VEHICLES].data = STR_AVAILABLE_AIRCRAFT;
00828 break;
00829
00830 default: NOT_REACHED();
00831 }
00832
00833 switch (window_type) {
00834 case VLW_SHARED_ORDERS:
00835 w->widget[VLW_WIDGET_CAPTION].data = STR_VEH_WITH_SHARED_ORDERS_LIST;
00836 break;
00837 case VLW_STANDARD:
00838 switch (vl->vehicle_type) {
00839 case VEH_TRAIN: w->widget[VLW_WIDGET_CAPTION].data = STR_881B_TRAINS; break;
00840 case VEH_ROAD: w->widget[VLW_WIDGET_CAPTION].data = STR_9001_ROAD_VEHICLES; break;
00841 case VEH_SHIP: w->widget[VLW_WIDGET_CAPTION].data = STR_9805_SHIPS; break;
00842 case VEH_AIRCRAFT: w->widget[VLW_WIDGET_CAPTION].data = STR_A009_AIRCRAFT; break;
00843 default: NOT_REACHED(); break;
00844 }
00845 break;
00846 case VLW_STATION_LIST:
00847 switch (vl->vehicle_type) {
00848 case VEH_TRAIN: w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_TRAINS; break;
00849 case VEH_ROAD: w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_ROAD_VEHICLES; break;
00850 case VEH_SHIP: w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_SHIPS; break;
00851 case VEH_AIRCRAFT: w->widget[VLW_WIDGET_CAPTION].data = STR_SCHEDULED_AIRCRAFT; break;
00852 default: NOT_REACHED(); break;
00853 }
00854 break;
00855
00856 case VLW_DEPOT_LIST:
00857 switch (vl->vehicle_type) {
00858 case VEH_TRAIN: w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_TRAIN_DEPOT; break;
00859 case VEH_ROAD: w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_ROADVEH_DEPOT; break;
00860 case VEH_SHIP: w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_SHIP_DEPOT; break;
00861 case VEH_AIRCRAFT: w->widget[VLW_WIDGET_CAPTION].data = STR_VEHICLE_LIST_AIRCRAFT_DEPOT; break;
00862 default: NOT_REACHED(); break;
00863 }
00864 break;
00865 default: NOT_REACHED(); break;
00866 }
00867
00868 switch (vl->vehicle_type) {
00869 case VEH_TRAIN:
00870 w->resize.step_width = 1;
00871
00872 case VEH_ROAD:
00873 w->vscroll.cap = 7;
00874 w->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_SMALL;
00875 w->resize.height = 220 - (PLY_WND_PRC__SIZE_OF_ROW_SMALL * 3);
00876 break;
00877 case VEH_SHIP:
00878 case VEH_AIRCRAFT:
00879 w->vscroll.cap = 4;
00880 w->resize.step_height = PLY_WND_PRC__SIZE_OF_ROW_BIG;
00881 break;
00882 default: NOT_REACHED();
00883 }
00884
00885 w->widget[VLW_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
00886
00887
00888
00889
00890 switch (vl->vehicle_type) {
00891 case VEH_TRAIN: vl->_sorting = &_sorting.train; break;
00892 case VEH_ROAD: vl->_sorting = &_sorting.roadveh; break;
00893 case VEH_SHIP: vl->_sorting = &_sorting.ship; break;
00894 case VEH_AIRCRAFT: vl->_sorting = &_sorting.aircraft; break;
00895 default: NOT_REACHED(); break;
00896 }
00897
00898 vl->l.flags = VL_REBUILD | (vl->_sorting->order ? VL_DESC : VL_NONE);
00899 vl->l.sort_type = vl->_sorting->criteria;
00900 vl->sort_list = NULL;
00901 vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
00902 }
00903
00904 void DrawSmallOrderList(const Vehicle *v, int x, int y)
00905 {
00906 const Order *order;
00907 int sel, i = 0;
00908
00909 sel = v->cur_order_index;
00910
00911 FOR_VEHICLE_ORDERS(v, order) {
00912 if (sel == 0) DrawString(x - 6, y, STR_SMALL_RIGHT_ARROW, TC_BLACK);
00913 sel--;
00914
00915 if (order->type == OT_GOTO_STATION) {
00916 if (v->type == VEH_SHIP && GetStation(order->dest)->IsBuoy()) continue;
00917
00918 SetDParam(0, order->dest);
00919 DrawString(x, y, STR_A036, TC_FROMSTRING);
00920
00921 y += 6;
00922 if (++i == 4) break;
00923 }
00924 }
00925 }
00926
00927 static void DrawVehicleListWindow(Window *w)
00928 {
00929 vehiclelist_d *vl = &WP(w, vehiclelist_d);
00930 int x = 2;
00931 int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;
00932 int max;
00933 int i;
00934 const PlayerID owner = (PlayerID)w->caption_color;
00935 const uint16 window_type = w->window_number & VLW_MASK;
00936 const uint16 index = GB(w->window_number, 16, 16);
00937
00938 BuildVehicleList(vl, owner, index, window_type);
00939 SortVehicleList(vl);
00940 SetVScrollCount(w, vl->l.list_length);
00941
00942 if (vl->l.list_length == 0) HideDropDownMenu(w);
00943
00944
00945 switch (window_type) {
00946 case VLW_SHARED_ORDERS:
00947 if (vl->l.list_length == 0) {
00948
00949
00950 NOT_REACHED();
00951 }
00952 SetDParam(0, w->vscroll.count);
00953 break;
00954
00955 case VLW_STANDARD:
00956 SetDParam(0, owner);
00957 SetDParam(1, w->vscroll.count);
00958 break;
00959
00960 case VLW_STATION_LIST:
00961 SetDParam(0, index);
00962 SetDParam(1, w->vscroll.count);
00963 break;
00964
00965 case VLW_DEPOT_LIST:
00966 switch (vl->vehicle_type) {
00967 case VEH_TRAIN: SetDParam(0, STR_8800_TRAIN_DEPOT); break;
00968 case VEH_ROAD: SetDParam(0, STR_9003_ROAD_VEHICLE_DEPOT); break;
00969 case VEH_SHIP: SetDParam(0, STR_9803_SHIP_DEPOT); break;
00970 case VEH_AIRCRAFT: SetDParam(0, STR_A002_AIRCRAFT_HANGAR); break;
00971 default: NOT_REACHED(); break;
00972 }
00973 if (vl->vehicle_type == VEH_AIRCRAFT) {
00974 SetDParam(1, index);
00975 } else {
00976 SetDParam(1, GetDepot(index)->town_index);
00977 }
00978 SetDParam(2, w->vscroll.count);
00979 break;
00980 default: NOT_REACHED(); break;
00981 }
00982
00983 w->SetWidgetsDisabledState(vl->l.list_length == 0,
00984 VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
00985 VLW_WIDGET_STOP_ALL,
00986 VLW_WIDGET_START_ALL,
00987 WIDGET_LIST_END);
00988
00989 DrawWindowWidgets(w);
00990
00991
00992 DrawString(85, 15, _vehicle_sort_listing[vl->l.sort_type], TC_BLACK);
00993
00994 DrawSortButtonState(w, VLW_WIDGET_SORT_ORDER, vl->l.flags & VL_DESC ? SBS_DOWN : SBS_UP);
00995
00996 max = min(w->vscroll.pos + w->vscroll.cap, vl->l.list_length);
00997 for (i = w->vscroll.pos; i < max; ++i) {
00998 const Vehicle *v = vl->sort_list[i];
00999 StringID str;
01000
01001 SetDParam(0, v->GetDisplayProfitThisYear());
01002 SetDParam(1, v->GetDisplayProfitLastYear());
01003
01004 DrawVehicleImage(v, x + 19, y + 6, INVALID_VEHICLE, w->widget[VLW_WIDGET_LIST].right - w->widget[VLW_WIDGET_LIST].left - 20, 0);
01005 DrawString(x + 19, y + w->resize.step_height - 8, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, TC_FROMSTRING);
01006
01007 if (v->name != NULL) {
01008
01009 SetDParam(0, v->index);
01010 DrawString(x + 19, y, STR_01AB, TC_FROMSTRING);
01011 }
01012
01013 if (w->resize.step_height == PLY_WND_PRC__SIZE_OF_ROW_BIG) DrawSmallOrderList(v, x + 138, y);
01014
01015 if (v->IsInDepot()) {
01016 str = STR_021F;
01017 } else {
01018 str = (v->age > v->max_age - 366) ? STR_00E3 : STR_00E2;
01019 }
01020
01021 SetDParam(0, v->unitnumber);
01022 DrawString(x, y + 2, str, TC_FROMSTRING);
01023
01024 DrawVehicleProfitButton(v, x, y + 13);
01025
01026 y += w->resize.step_height;
01027 }
01028 }
01029
01030
01031
01032
01033
01034
01035
01036
01037 void PlayerVehWndProc(Window *w, WindowEvent *e)
01038 {
01039 vehiclelist_d *vl = &WP(w, vehiclelist_d);
01040
01041 switch (e->event) {
01042 case WE_CREATE:
01043 CreateVehicleListWindow(w);
01044 break;
01045
01046 case WE_PAINT:
01047 DrawVehicleListWindow(w);
01048 break;
01049
01050 case WE_CLICK: {
01051 switch (e->we.click.widget) {
01052 case VLW_WIDGET_SORT_ORDER:
01053 vl->l.flags ^= VL_DESC;
01054 vl->l.flags |= VL_RESORT;
01055
01056 vl->_sorting->order = !!(vl->l.flags & VL_DESC);
01057 SetWindowDirty(w);
01058 break;
01059 case VLW_WIDGET_SORT_BY_PULLDOWN:
01060 ShowDropDownMenu(w, _vehicle_sort_listing, vl->l.sort_type, VLW_WIDGET_SORT_BY_PULLDOWN, 0, 0);
01061 return;
01062 case VLW_WIDGET_LIST: {
01063 uint32 id_v = (e->we.click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / w->resize.step_height;
01064 const Vehicle *v;
01065
01066 if (id_v >= w->vscroll.cap) return;
01067
01068 id_v += w->vscroll.pos;
01069
01070 if (id_v >= vl->l.list_length) return;
01071
01072 v = vl->sort_list[id_v];
01073
01074 ShowVehicleViewWindow(v);
01075 } break;
01076
01077 case VLW_WIDGET_AVAILABLE_VEHICLES:
01078 ShowBuildVehicleWindow(0, vl->vehicle_type);
01079 break;
01080
01081 case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN: {
01082 static StringID action_str[] = {
01083 STR_REPLACE_VEHICLES,
01084 STR_SEND_FOR_SERVICING,
01085 STR_NULL,
01086 INVALID_STRING_ID
01087 };
01088
01089 static const StringID depot_name[] = {
01090 STR_SEND_TRAIN_TO_DEPOT,
01091 STR_SEND_ROAD_VEHICLE_TO_DEPOT,
01092 STR_SEND_SHIP_TO_DEPOT,
01093 STR_SEND_AIRCRAFT_TO_HANGAR
01094 };
01095
01096
01097 action_str[2] = depot_name[vl->vehicle_type];
01098 ShowDropDownMenu(w, action_str, 0, VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN, 0, (w->window_number & VLW_MASK) == VLW_STANDARD ? 0 : 1);
01099 break;
01100 }
01101
01102 case VLW_WIDGET_STOP_ALL:
01103 case VLW_WIDGET_START_ALL:
01104 DoCommandP(0, GB(w->window_number, 16, 16), (w->window_number & VLW_MASK) | (1 << 6) | (e->we.click.widget == VLW_WIDGET_START_ALL ? (1 << 5) : 0) | vl->vehicle_type, NULL, CMD_MASS_START_STOP);
01105 break;
01106 }
01107 } break;
01108
01109 case WE_DROPDOWN_SELECT:
01110 switch (e->we.dropdown.button) {
01111 case VLW_WIDGET_SORT_BY_PULLDOWN:
01112 if (vl->l.sort_type != e->we.dropdown.index) {
01113
01114 vl->l.flags |= VL_RESORT;
01115 vl->l.sort_type = e->we.dropdown.index;
01116 vl->_sorting->criteria = vl->l.sort_type;
01117 }
01118 break;
01119 case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN:
01120 assert(vl->l.list_length != 0);
01121
01122 switch (e->we.dropdown.index) {
01123 case 0:
01124 ShowReplaceGroupVehicleWindow(DEFAULT_GROUP, vl->vehicle_type);
01125 break;
01126 case 1:
01127 DoCommandP(0, GB(w->window_number, 16, 16) ,
01128 (w->window_number & VLW_MASK) | DEPOT_MASS_SEND | DEPOT_SERVICE,
01129 NULL,
01130 GetCmdSendToDepot(vl->vehicle_type));
01131 break;
01132 case 2:
01133 DoCommandP(0, GB(w->window_number, 16, 16) ,
01134 (w->window_number & VLW_MASK) | DEPOT_MASS_SEND,
01135 NULL,
01136 GetCmdSendToDepot(vl->vehicle_type));
01137 break;
01138
01139 default: NOT_REACHED();
01140 }
01141 break;
01142 default: NOT_REACHED();
01143 }
01144 SetWindowDirty(w);
01145 break;
01146
01147 case WE_DESTROY:
01148 free((void*)vl->sort_list);
01149 break;
01150
01151 case WE_TICK:
01152 if (_pause_game != 0) break;
01153 if (--vl->l.resort_timer == 0) {
01154 StationID station = ((w->window_number & VLW_MASK) == VLW_STATION_LIST) ? GB(w->window_number, 16, 16) : INVALID_STATION;
01155 PlayerID owner = (PlayerID)w->caption_color;
01156
01157 DEBUG(misc, 3, "Periodic resort %d list player %d at station %d", vl->vehicle_type, owner, station);
01158 vl->l.resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
01159 vl->l.flags |= VL_RESORT;
01160 SetWindowDirty(w);
01161 }
01162 break;
01163
01164 case WE_RESIZE:
01165 w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
01166 w->widget[VLW_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
01167 break;
01168 }
01169 }
01170
01171 static const WindowDesc _player_vehicle_list_train_desc = {
01172 WDP_AUTO, WDP_AUTO, 260, 182, 260, 182,
01173 WC_TRAINS_LIST, WC_NONE,
01174 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
01175 _vehicle_list_widgets,
01176 PlayerVehWndProc
01177 };
01178
01179 static const WindowDesc _player_vehicle_list_road_veh_desc = {
01180 WDP_AUTO, WDP_AUTO, 260, 182, 260, 182,
01181 WC_ROADVEH_LIST, WC_NONE,
01182 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
01183 _vehicle_list_widgets,
01184 PlayerVehWndProc
01185 };
01186
01187 static const WindowDesc _player_vehicle_list_ship_desc = {
01188 WDP_AUTO, WDP_AUTO, 260, 182, 260, 182,
01189 WC_SHIPS_LIST, WC_NONE,
01190 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
01191 _vehicle_list_widgets,
01192 PlayerVehWndProc
01193 };
01194
01195 static const WindowDesc _player_vehicle_list_aircraft_desc = {
01196 WDP_AUTO, WDP_AUTO, 260, 182, 260, 182,
01197 WC_AIRCRAFT_LIST, WC_NONE,
01198 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
01199 _vehicle_list_widgets,
01200 PlayerVehWndProc
01201 };
01202
01203 static void ShowVehicleListWindowLocal(PlayerID player, uint16 VLW_flag, VehicleType vehicle_type, uint16 unique_number)
01204 {
01205 Window *w;
01206 WindowNumber num;
01207
01208 if (!IsValidPlayer(player)) return;
01209
01210 num = (unique_number << 16) | (vehicle_type << 11) | VLW_flag | player;
01211
01212
01213
01214
01215 switch (vehicle_type) {
01216 default: NOT_REACHED();
01217 case VEH_TRAIN:
01218 w = AllocateWindowDescFront(&_player_vehicle_list_train_desc, num);
01219 if (w != NULL) ResizeWindow(w, 65, 38);
01220 break;
01221 case VEH_ROAD:
01222 w = AllocateWindowDescFront(&_player_vehicle_list_road_veh_desc, num);
01223 if (w != NULL) ResizeWindow(w, 0, 38);
01224 break;
01225 case VEH_SHIP:
01226 w = AllocateWindowDescFront(&_player_vehicle_list_ship_desc, num);
01227 break;
01228 case VEH_AIRCRAFT:
01229 w = AllocateWindowDescFront(&_player_vehicle_list_aircraft_desc, num);
01230 break;
01231 }
01232
01233 if (w != NULL) {
01234
01235 w->resize.width = w->width;
01236 w->resize.height = w->height;
01237 }
01238 }
01239
01240 void ShowVehicleListWindow(PlayerID player, VehicleType vehicle_type)
01241 {
01242
01243
01244
01245
01246
01247 if ((_patches.advanced_vehicle_list > (uint)(player != _local_player)) != _ctrl_pressed) {
01248 ShowPlayerGroup(player, vehicle_type);
01249 } else {
01250 ShowVehicleListWindowLocal(player, VLW_STANDARD, vehicle_type, 0);
01251 }
01252 }
01253
01254 void ShowVehicleListWindow(const Vehicle *v)
01255 {
01256 if (v->orders == NULL) return;
01257 ShowVehicleListWindowLocal(v->owner, VLW_SHARED_ORDERS, v->type, v->orders->index);
01258 }
01259
01260 void ShowVehicleListWindow(PlayerID player, VehicleType vehicle_type, StationID station)
01261 {
01262 ShowVehicleListWindowLocal(player, VLW_STATION_LIST, vehicle_type, station);
01263 }
01264
01265 void ShowVehicleListWindow(PlayerID player, VehicleType vehicle_type, TileIndex depot_tile)
01266 {
01267 uint16 depot_airport_index;
01268
01269 if (vehicle_type == VEH_AIRCRAFT) {
01270 depot_airport_index = GetStationIndex(depot_tile);
01271 } else {
01272 Depot *depot = GetDepotByTile(depot_tile);
01273 if (depot == NULL) return;
01274 depot_airport_index = depot->index;
01275 }
01276 ShowVehicleListWindowLocal(player, VLW_DEPOT_LIST, vehicle_type, depot_airport_index);
01277 }
01278
01279
01280
01281
01283 enum VehicleDetailsWindowWidgets {
01284 VLD_WIDGET_CLOSEBOX = 0,
01285 VLD_WIDGET_CAPTION,
01286 VLD_WIDGET_RENAME_VEHICLE,
01287 VLD_WIDGET_TOP_DETAILS,
01288 VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
01289 VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
01290 VLD_WIDGET_BOTTOM_RIGHT,
01291 VLD_WIDGET_MIDDLE_DETAILS,
01292 VLD_WIDGET_SCROLLBAR,
01293 VLD_WIDGET_DETAILS_CARGO_CARRIED,
01294 VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
01295 VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
01296 VLD_WIDGET_DETAILS_TOTAL_CARGO,
01297 VLD_WIDGET_RESIZE,
01298 };
01299
01301 static const Widget _vehicle_details_widgets[] = {
01302 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01303 { WWT_CAPTION, RESIZE_RIGHT, 14, 11, 364, 0, 13, 0x0, STR_018C_WINDOW_TITLE_DRAG_THIS},
01304 { WWT_PUSHTXTBTN, RESIZE_LR, 14, 365, 404, 0, 13, STR_01AA_NAME, STR_NULL },
01305 { WWT_PANEL, RESIZE_RIGHT, 14, 0, 404, 14, 55, 0x0, STR_NULL},
01306 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 10, 101, 106, STR_0188, STR_884D_INCREASE_SERVICING_INTERVAL},
01307 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 10, 107, 112, STR_0189, STR_884E_DECREASE_SERVICING_INTERVAL},
01308 { WWT_PANEL, RESIZE_RTB, 14, 11, 404, 101, 112, 0x0, STR_NULL},
01309 { WWT_MATRIX, RESIZE_RB, 14, 0, 392, 56, 100, 0x701, STR_NULL},
01310 { WWT_SCROLLBAR, RESIZE_LRB, 14, 393, 404, 56, 100, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
01311 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 95, 113, 124, STR_013C_CARGO, STR_884F_SHOW_DETAILS_OF_CARGO_CARRIED},
01312 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 96, 194, 113, 124, STR_013D_INFORMATION, STR_8850_SHOW_DETAILS_OF_TRAIN_VEHICLES},
01313 { WWT_PUSHTXTBTN, RESIZE_TB, 14, 195, 293, 113, 124, STR_013E_CAPACITIES, STR_8851_SHOW_CAPACITIES_OF_EACH},
01314 { WWT_PUSHTXTBTN, RESIZE_RTB, 14, 294, 392, 113, 124, STR_TOTAL_CARGO, STR_SHOW_TOTAL_CARGO},
01315 { WWT_RESIZEBOX, RESIZE_LRTB, 14, 393, 404, 113, 124, 0x0, STR_RESIZE_BUTTON},
01316 { WIDGETS_END},
01317 };
01318
01319
01321 enum VehicleStringTranslation {
01322 VST_VEHICLE_AGE_RUNNING_COST_YR,
01323 VST_VEHICLE_MAX_SPEED,
01324 VST_VEHICLE_PROFIT_THIS_YEAR_LAST_YEAR,
01325 VST_VEHICLE_RELIABILITY_BREAKDOWNS,
01326 };
01327
01329 static const StringID _vehicle_translation_table[][4] = {
01330 {
01331 STR_885D_AGE_RUNNING_COST_YR,
01332 STR_900D_AGE_RUNNING_COST_YR,
01333 STR_9812_AGE_RUNNING_COST_YR,
01334 STR_A00D_AGE_RUNNING_COST_YR,
01335 },
01336 {
01337 STR_NULL,
01338 STR_900E_MAX_SPEED,
01339 STR_9813_MAX_SPEED,
01340 STR_A00E_MAX_SPEED,
01341 },
01342 {
01343 STR_885F_PROFIT_THIS_YEAR_LAST_YEAR,
01344 STR_900F_PROFIT_THIS_YEAR_LAST_YEAR,
01345 STR_9814_PROFIT_THIS_YEAR_LAST_YEAR,
01346 STR_A00F_PROFIT_THIS_YEAR_LAST_YEAR,
01347 },
01348 {
01349 STR_8860_RELIABILITY_BREAKDOWNS,
01350 STR_9010_RELIABILITY_BREAKDOWNS,
01351 STR_9815_RELIABILITY_BREAKDOWNS,
01352 STR_A010_RELIABILITY_BREAKDOWNS,
01353 },
01354 };
01355
01357 void CreateVehicleDetailsWindow(Window *w)
01358 {
01359 const Vehicle *v = GetVehicle(w->window_number);
01360
01361 switch (v->type) {
01362 case VEH_TRAIN:
01363 ResizeWindow(w, 0, 39);
01364
01365 w->vscroll.cap = 6;
01366 w->height += 12;
01367 w->resize.step_height = 14;
01368 w->resize.height = w->height - 14 * 2;
01369
01370 w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_8867_NAME_TRAIN;
01371 w->widget[VLD_WIDGET_CAPTION].data = STR_8802_DETAILS;
01372 break;
01373
01374 case VEH_ROAD: {
01375 w->widget[VLD_WIDGET_CAPTION].data = STR_900C_DETAILS;
01376 w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_902E_NAME_ROAD_VEHICLE;
01377
01378 if (!RoadVehHasArticPart(v)) break;
01379
01380
01381
01382 uint height_extension = 15 - 11;
01383
01384
01385 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
01386 if (u->cargo_cap != 0) height_extension += 11;
01387 }
01388
01389 ResizeWindow(w, 0, height_extension);
01390 } break;
01391
01392 case VEH_SHIP:
01393 w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_982F_NAME_SHIP;
01394 w->widget[VLD_WIDGET_CAPTION].data = STR_9811_DETAILS;
01395 break;
01396
01397 case VEH_AIRCRAFT:
01398 ResizeWindow(w, 0, 11);
01399 w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_A032_NAME_AIRCRAFT;
01400 w->widget[VLD_WIDGET_CAPTION].data = STR_A00C_DETAILS;
01401 break;
01402 default: NOT_REACHED();
01403 }
01404
01405 if (v->type != VEH_TRAIN) {
01406 w->vscroll.cap = 1;
01407 w->widget[VLD_WIDGET_MIDDLE_DETAILS].right += 12;
01408 }
01409
01410 w->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (w->vscroll.cap << 8) + 1;
01411 w->caption_color = v->owner;
01412
01413 WP(w, vehicledetails_d).tab = 0;
01414 }
01415
01417 static inline bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type)
01418 {
01419 switch (vehicle_type) {
01420 default: NOT_REACHED();
01421 case VEH_TRAIN: return _patches.servint_trains != 0; break;
01422 case VEH_ROAD: return _patches.servint_roadveh != 0; break;
01423 case VEH_SHIP: return _patches.servint_ships != 0; break;
01424 case VEH_AIRCRAFT: return _patches.servint_aircraft != 0; break;
01425 }
01426 return false;
01427 }
01428
01429 extern int GetTrainDetailsWndVScroll(VehicleID veh_id, byte det_tab);
01430 extern void DrawTrainDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint16 vscroll_cap, byte det_tab);
01431 extern void DrawRoadVehDetails(const Vehicle *v, int x, int y);
01432 extern void DrawShipDetails(const Vehicle *v, int x, int y);
01433 extern void DrawAircraftDetails(const Vehicle *v, int x, int y);
01434
01445 static inline void DrawVehicleDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint vscroll_cap, byte det_tab)
01446 {
01447 switch (v->type) {
01448 case VEH_TRAIN: DrawTrainDetails(v, x, y, vscroll_pos, vscroll_cap, det_tab); break;
01449 case VEH_ROAD: DrawRoadVehDetails(v, x, y); break;
01450 case VEH_SHIP: DrawShipDetails(v, x, y); break;
01451 case VEH_AIRCRAFT: DrawAircraftDetails(v, x, y); break;
01452 default: NOT_REACHED();
01453 }
01454 }
01455
01457 static void DrawVehicleDetailsWindow(Window *w)
01458 {
01459 const Vehicle *v = GetVehicle(w->window_number);
01460 byte det_tab = WP(w, vehicledetails_d).tab;
01461
01462 w->SetWidgetDisabledState(VLD_WIDGET_RENAME_VEHICLE, v->owner != _local_player);
01463
01464 if (v->type == VEH_TRAIN) {
01465 w->DisableWidget(det_tab + VLD_WIDGET_DETAILS_CARGO_CARRIED);
01466 SetVScrollCount(w, GetTrainDetailsWndVScroll(v->index, det_tab));
01467 }
01468
01469 w->SetWidgetsHiddenState(v->type != VEH_TRAIN,
01470 VLD_WIDGET_SCROLLBAR,
01471 VLD_WIDGET_DETAILS_CARGO_CARRIED,
01472 VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
01473 VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
01474 VLD_WIDGET_DETAILS_TOTAL_CARGO,
01475 VLD_WIDGET_RESIZE,
01476 WIDGET_LIST_END);
01477
01478
01479 w->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type),
01480 VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
01481 VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
01482 WIDGET_LIST_END);
01483
01484
01485 SetDParam(0, v->index);
01486 DrawWindowWidgets(w);
01487
01488
01489 SetDParam(1, v->age / 366);
01490 SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
01491 SetDParam(2, v->max_age / 366);
01492 SetDParam(3, v->GetDisplayRunningCost());
01493 DrawString(2, 15, _vehicle_translation_table[VST_VEHICLE_AGE_RUNNING_COST_YR][v->type], TC_FROMSTRING);
01494
01495
01496 switch (v->type) {
01497 case VEH_TRAIN:
01498 SetDParam(2, v->GetDisplayMaxSpeed());
01499 SetDParam(1, v->u.rail.cached_power);
01500 SetDParam(0, v->u.rail.cached_weight);
01501 SetDParam(3, v->u.rail.cached_max_te / 1000);
01502 DrawString(2, 25, (_patches.realistic_acceleration && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
01503 STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
01504 STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, TC_FROMSTRING);
01505 break;
01506
01507 case VEH_ROAD:
01508 case VEH_SHIP:
01509 case VEH_AIRCRAFT:
01510 SetDParam(0, v->GetDisplayMaxSpeed());
01511 DrawString(2, 25, _vehicle_translation_table[VST_VEHICLE_MAX_SPEED][v->type], TC_FROMSTRING);
01512 break;
01513
01514 default: NOT_REACHED();
01515 }
01516
01517
01518 SetDParam(0, v->GetDisplayProfitThisYear());
01519 SetDParam(1, v->GetDisplayProfitLastYear());
01520 DrawString(2, 35, _vehicle_translation_table[VST_VEHICLE_PROFIT_THIS_YEAR_LAST_YEAR][v->type], TC_FROMSTRING);
01521
01522
01523 SetDParam(0, v->reliability * 100 >> 16);
01524 SetDParam(1, v->breakdowns_since_last_service);
01525 DrawString(2, 45, _vehicle_translation_table[VST_VEHICLE_RELIABILITY_BREAKDOWNS][v->type], TC_FROMSTRING);
01526
01527
01528 SetDParam(0, v->service_interval);
01529 SetDParam(1, v->date_of_last_service);
01530 DrawString(13, w->height - (v->type != VEH_TRAIN ? 11 : 23), _patches.servint_ispercent ? STR_SERVICING_INTERVAL_PERCENT : STR_883C_SERVICING_INTERVAL_DAYS, TC_FROMSTRING);
01531
01532 switch (v->type) {
01533 case VEH_TRAIN:
01534 DrawVehicleDetails(v, 2, 57, w->vscroll.pos, w->vscroll.cap, det_tab);
01535 break;
01536
01537 case VEH_ROAD:
01538 case VEH_SHIP:
01539 case VEH_AIRCRAFT:
01540 DrawVehicleImage(v, 3, 57, INVALID_VEHICLE, 0, 0);
01541 DrawVehicleDetails(v, 75, 57, w->vscroll.pos, w->vscroll.cap, det_tab);
01542 break;
01543
01544 default: NOT_REACHED();
01545 }
01546 }
01547
01549 static const StringID _name_vehicle_title[] = {
01550 STR_8865_NAME_TRAIN,
01551 STR_902C_NAME_ROAD_VEHICLE,
01552 STR_9831_NAME_SHIP,
01553 STR_A030_NAME_AIRCRAFT
01554 };
01555
01557 static const StringID _name_vehicle_error[] = {
01558 STR_8866_CAN_T_NAME_TRAIN,
01559 STR_902D_CAN_T_NAME_ROAD_VEHICLE,
01560 STR_9832_CAN_T_NAME_SHIP,
01561 STR_A031_CAN_T_NAME_AIRCRAFT
01562 };
01563
01565 static void VehicleDetailsWndProc(Window *w, WindowEvent *e)
01566 {
01567 switch (e->event) {
01568 case WE_CREATE:
01569 CreateVehicleDetailsWindow(w);
01570 break;
01571
01572 case WE_PAINT:
01573 DrawVehicleDetailsWindow(w);
01574 break;
01575
01576 case WE_CLICK: {
01577 switch (e->we.click.widget) {
01578 case VLD_WIDGET_RENAME_VEHICLE: {
01579 const Vehicle *v = GetVehicle(w->window_number);
01580 SetDParam(0, v->index);
01581 ShowQueryString(STR_VEHICLE_NAME, _name_vehicle_title[v->type], 31, 150, w, CS_ALPHANUMERAL);
01582 } break;
01583
01584 case VLD_WIDGET_INCREASE_SERVICING_INTERVAL:
01585 case VLD_WIDGET_DECREASE_SERVICING_INTERVAL: {
01586 int mod = _ctrl_pressed ? 5 : 10;
01587 const Vehicle *v = GetVehicle(w->window_number);
01588
01589 mod = (e->we.click.widget == VLD_WIDGET_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
01590 mod = GetServiceIntervalClamped(mod + v->service_interval);
01591 if (mod == v->service_interval) return;
01592
01593 DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
01594 } break;
01595
01596 case VLD_WIDGET_DETAILS_CARGO_CARRIED:
01597 case VLD_WIDGET_DETAILS_TRAIN_VEHICLES:
01598 case VLD_WIDGET_DETAILS_CAPACITY_OF_EACH:
01599 case VLD_WIDGET_DETAILS_TOTAL_CARGO:
01600 w->SetWidgetsDisabledState(false,
01601 VLD_WIDGET_DETAILS_CARGO_CARRIED,
01602 VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
01603 VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
01604 VLD_WIDGET_DETAILS_TOTAL_CARGO,
01605 e->we.click.widget,
01606 WIDGET_LIST_END);
01607
01608 WP(w, vehicledetails_d).tab = e->we.click.widget - VLD_WIDGET_DETAILS_CARGO_CARRIED;
01609 SetWindowDirty(w);
01610 break;
01611 }
01612 } break;
01613
01614 case WE_ON_EDIT_TEXT:
01615 if (!StrEmpty(e->we.edittext.str)) {
01616 _cmd_text = e->we.edittext.str;
01617 DoCommandP(0, w->window_number, 0, NULL, CMD_NAME_VEHICLE | CMD_MSG(_name_vehicle_error[GetVehicle(w->window_number)->type]));
01618 }
01619 break;
01620
01621 case WE_RESIZE:
01622 if (e->we.sizing.diff.x != 0) ResizeButtons(w, VLD_WIDGET_DETAILS_CARGO_CARRIED, VLD_WIDGET_DETAILS_TOTAL_CARGO);
01623 if (e->we.sizing.diff.y == 0) break;
01624
01625 w->vscroll.cap += e->we.sizing.diff.y / 14;
01626 w->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (w->vscroll.cap << 8) + 1;
01627 break;
01628 }
01629 }
01630
01632 static const WindowDesc _vehicle_details_desc = {
01633 WDP_AUTO, WDP_AUTO, 405, 113, 405, 113,
01634 WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
01635 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
01636 _vehicle_details_widgets,
01637 VehicleDetailsWndProc
01638 };
01639
01641 static void ShowVehicleDetailsWindow(const Vehicle *v)
01642 {
01643 DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
01644 DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
01645 AllocateWindowDescFront(&_vehicle_details_desc, v->index);
01646 }
01647
01648
01649
01650
01652 static const Widget _vehicle_view_widgets[] = {
01653 { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
01654 { WWT_CAPTION, RESIZE_RIGHT, 14, 11, 237, 0, 13, 0x0 , STR_018C_WINDOW_TITLE_DRAG_THIS },
01655 { WWT_STICKYBOX, RESIZE_LR, 14, 238, 249, 0, 13, 0x0, STR_STICKY_BUTTON },
01656 { WWT_PANEL, RESIZE_RB, 14, 0, 231, 14, 103, 0x0, STR_NULL },
01657 { WWT_INSET, RESIZE_RB, 14, 2, 229, 16, 101, 0x0, STR_NULL },
01658 { WWT_PUSHBTN, RESIZE_RTB, 14, 0, 237, 104, 115, 0x0, 0x0 },
01659 { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 14, 31, SPR_CENTRE_VIEW_VEHICLE, 0x0 },
01660 { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, 0x0 , 0x0 },
01661 { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 50, 67, SPR_REFIT_VEHICLE, 0x0 },
01662 { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 68, 85, SPR_SHOW_ORDERS, 0x0 },
01663 { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 86, 103, SPR_SHOW_VEHICLE_DETAILS, 0x0 },
01664 { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, 0x0 , 0x0 },
01665 { WWT_PANEL, RESIZE_LRB, 14, 232, 249, 104, 103, 0x0, STR_NULL },
01666 { WWT_RESIZEBOX, RESIZE_LRTB, 14, 238, 249, 104, 115, 0x0, STR_NULL },
01667 { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 50, 67, SPR_FORCE_VEHICLE_TURN, STR_9020_FORCE_VEHICLE_TO_TURN_AROUND },
01668 { WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 50, 67, SPR_IGNORE_SIGNALS, STR_884A_FORCE_TRAIN_TO_PROCEED },
01669 { WIDGETS_END},
01670 };
01671
01672
01673 static void VehicleViewWndProc(Window *w, WindowEvent *e);
01674
01676 static const WindowDesc _vehicle_view_desc = {
01677 WDP_AUTO, WDP_AUTO, 250, 116, 250, 116,
01678 WC_VEHICLE_VIEW, WC_NONE,
01679 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
01680 _vehicle_view_widgets,
01681 VehicleViewWndProc
01682 };
01683
01687 static const WindowDesc _train_view_desc = {
01688 WDP_AUTO, WDP_AUTO, 250, 134, 250, 134,
01689 WC_VEHICLE_VIEW, WC_NONE,
01690 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
01691 _vehicle_view_widgets,
01692 VehicleViewWndProc
01693 };
01694
01695
01696
01697
01698 assert_compile(VEH_TRAIN == 0);
01699 assert_compile(VEH_ROAD == 1);
01700 assert_compile(VEH_SHIP == 2);
01701 assert_compile(VEH_AIRCRAFT == 3);
01702
01704 static const ZoomLevel _vehicle_view_zoom_levels[] = {
01705 ZOOM_LVL_TRAIN,
01706 ZOOM_LVL_ROADVEH,
01707 ZOOM_LVL_SHIP,
01708 ZOOM_LVL_AIRCRAFT,
01709 };
01710
01711
01712 static const int VV_VIEWPORT_X = 3;
01713 static const int VV_VIEWPORT_Y = 17;
01714 static const int VV_INITIAL_VIEWPORT_WIDTH = 226;
01715 static const int VV_INITIAL_VIEWPORT_HEIGHT = 84;
01716 static const int VV_INITIAL_VIEWPORT_HEIGHT_TRAIN = 102;
01717
01719 void ShowVehicleViewWindow(const Vehicle *v)
01720 {
01721 Window *w = AllocateWindowDescFront((v->type == VEH_TRAIN) ? &_train_view_desc : &_vehicle_view_desc, v->index);
01722
01723 if (w != NULL) {
01724 w->caption_color = v->owner;
01725 AssignWindowViewport(w, VV_VIEWPORT_X, VV_VIEWPORT_Y, VV_INITIAL_VIEWPORT_WIDTH,
01726 (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT,
01727 w->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]);
01728 }
01729 }
01730
01732 static void CreateVehicleViewWindow(Window *w)
01733 {
01734 const Vehicle *v = GetVehicle(w->window_number);
01735
01736
01737
01738
01739
01740 switch (v->type) {
01741 case VEH_TRAIN:
01742 w->widget[VVW_WIDGET_CAPTION].data = STR_882E;
01743
01744 w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_8846_CURRENT_TRAIN_ACTION_CLICK;
01745
01746 w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_8848_CENTER_MAIN_VIEW_ON_TRAIN;
01747
01748 w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_TRAIN_TODEPOT;
01749 w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_8849_SEND_TRAIN_TO_DEPOT;
01750
01751 w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_RAIL_REFIT_VEHICLE_TO_CARRY;
01752
01753 w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_8847_SHOW_TRAIN_S_ORDERS;
01754
01755 w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_884C_SHOW_TRAIN_DETAILS;
01756
01757 w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_TRAIN;
01758 w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_TRAIN_INFO;
01759
01760 w->widget[VVW_WIDGET_TURN_AROUND].tooltips = STR_884B_REVERSE_DIRECTION_OF_TRAIN;
01761
01762
01763
01764 w->widget[VVW_WIDGET_PANEL].bottom = 121;
01765 w->widget[VVW_WIDGET_VIEWPORT].bottom = 119;
01766
01767 w->widget[VVW_WIDGET_START_STOP_VEH].top = 122;
01768 w->widget[VVW_WIDGET_START_STOP_VEH].bottom = 133;
01769
01770 w->widget[VVW_WIDGET_REFIT_VEH].top = 68;
01771 w->widget[VVW_WIDGET_REFIT_VEH].bottom = 85;
01772
01773 w->widget[VVW_WIDGET_SHOW_ORDERS].top = 86;
01774 w->widget[VVW_WIDGET_SHOW_ORDERS].bottom = 103;
01775
01776 w->widget[VVW_WIDGET_SHOW_DETAILS].top = 104;
01777 w->widget[VVW_WIDGET_SHOW_DETAILS].bottom = 121;
01778
01779 w->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].top = 122;
01780 w->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].bottom = 121;
01781
01782 w->widget[VVW_WIDGET_RESIZE].top = 122;
01783 w->widget[VVW_WIDGET_RESIZE].bottom = 133;
01784
01785 w->widget[VVW_WIDGET_TURN_AROUND].top = 68;
01786 w->widget[VVW_WIDGET_TURN_AROUND].bottom = 85;
01787 break;
01788
01789 case VEH_ROAD:
01790 w->widget[VVW_WIDGET_CAPTION].data = STR_9002;
01791
01792 w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_901C_CURRENT_VEHICLE_ACTION;
01793
01794 w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_901E_CENTER_MAIN_VIEW_ON_VEHICLE;
01795
01796 w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_ROADVEH_TODEPOT;
01797 w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_901F_SEND_VEHICLE_TO_DEPOT;
01798
01799 w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY;
01800
01801 w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_901D_SHOW_VEHICLE_S_ORDERS;
01802
01803 w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_9021_SHOW_ROAD_VEHICLE_DETAILS;
01804
01805 w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_ROADVEH;
01806 w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_ROAD_VEHICLE_INFO;
01807
01808 w->SetWidgetHiddenState(VVW_WIDGET_FORCE_PROCEED, true);
01809 break;
01810
01811 case VEH_SHIP:
01812 w->widget[VVW_WIDGET_CAPTION].data = STR_980F;
01813
01814 w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_9827_CURRENT_SHIP_ACTION_CLICK;
01815
01816 w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_9829_CENTER_MAIN_VIEW_ON_SHIP;
01817
01818 w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_SHIP_TODEPOT;
01819 w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_982A_SEND_SHIP_TO_DEPOT;
01820
01821 w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_983A_REFIT_CARGO_SHIP_TO_CARRY;
01822
01823 w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_9828_SHOW_SHIP_S_ORDERS;
01824
01825 w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_982B_SHOW_SHIP_DETAILS;
01826
01827 w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_SHIP;
01828 w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_SHIP_INFO;
01829
01830 w->SetWidgetsHiddenState(true,
01831 VVW_WIDGET_TURN_AROUND,
01832 VVW_WIDGET_FORCE_PROCEED,
01833 WIDGET_LIST_END);
01834 break;
01835
01836 case VEH_AIRCRAFT:
01837 w->widget[VVW_WIDGET_CAPTION].data = STR_A00A;
01838
01839 w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_A027_CURRENT_AIRCRAFT_ACTION;
01840
01841 w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT;
01842
01843 w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_AIRCRAFT_TODEPOT;
01844 w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_A02A_SEND_AIRCRAFT_TO_HANGAR;
01845
01846 w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_A03B_REFIT_AIRCRAFT_TO_CARRY;
01847
01848 w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_A028_SHOW_AIRCRAFT_S_ORDERS;
01849
01850 w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_A02B_SHOW_AIRCRAFT_DETAILS;
01851
01852 w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_AIRCRAFT;
01853 w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_AIRCRAFT_INFO;
01854
01855 w->SetWidgetsHiddenState(true,
01856 VVW_WIDGET_TURN_AROUND,
01857 VVW_WIDGET_FORCE_PROCEED,
01858 WIDGET_LIST_END);
01859 break;
01860
01861 default: NOT_REACHED();
01862 }
01863 }
01864
01866 static bool IsVehicleRefitable(const Vehicle *v)
01867 {
01868
01869
01870
01871 switch (v->type) {
01872 case VEH_TRAIN: return false;
01873 case VEH_ROAD: return EngInfo(v->engine_type)->refit_mask != 0 && v->IsStoppedInDepot();
01874 case VEH_SHIP: return ShipVehInfo(v->engine_type)->refittable && v->IsStoppedInDepot();
01875 case VEH_AIRCRAFT: return v->IsStoppedInDepot();
01876 default: NOT_REACHED();
01877 }
01878 }
01879
01881 static const StringID _heading_for_depot_strings[] = {
01882 STR_HEADING_FOR_TRAIN_DEPOT,
01883 STR_HEADING_FOR_ROAD_DEPOT,
01884 STR_HEADING_FOR_SHIP_DEPOT,
01885 STR_HEADING_FOR_HANGAR,
01886 };
01887
01889 static const StringID _heading_for_depot_service_strings[] = {
01890 STR_HEADING_FOR_TRAIN_DEPOT_SERVICE,
01891 STR_HEADING_FOR_ROAD_DEPOT_SERVICE,
01892 STR_HEADING_FOR_SHIP_DEPOT_SERVICE,
01893 STR_HEADING_FOR_HANGAR_SERVICE,
01894 };
01895
01897 static void DrawVehicleViewWindow(Window *w)
01898 {
01899 const Vehicle *v = GetVehicle(w->window_number);
01900 StringID str;
01901 bool is_localplayer = v->owner == _local_player;
01902 bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
01903
01904 w->SetWidgetDisabledState(VVW_WIDGET_GOTO_DEPOT, !is_localplayer);
01905 w->SetWidgetDisabledState(VVW_WIDGET_REFIT_VEH,
01906 !refitable_and_stopped_in_depot || !is_localplayer);
01907 w->SetWidgetDisabledState(VVW_WIDGET_CLONE_VEH, !is_localplayer);
01908
01909 if (v->type == VEH_TRAIN) {
01910 w->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !is_localplayer);
01911 w->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !is_localplayer);
01912
01913
01914
01915 if (is_localplayer) {
01916
01917 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
01918 if (EngInfo(u->engine_type)->refit_mask != 0 ||
01919 (RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON && v->cargo_cap != 0)) {
01920 w->EnableWidget(VVW_WIDGET_REFIT_VEH);
01921
01922 break;
01923 }
01924 }
01925 }
01926 }
01927
01928
01929 SetDParam(0, v->index);
01930 DrawWindowWidgets(w);
01931
01932 if (v->vehstatus & VS_CRASHED) {
01933 str = STR_8863_CRASHED;
01934 } else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) {
01935 str = STR_885C_BROKEN_DOWN;
01936 } else if (v->vehstatus & VS_STOPPED) {
01937 if (v->type == VEH_TRAIN) {
01938 if (v->cur_speed == 0) {
01939 if (v->u.rail.cached_power == 0) {
01940 str = STR_TRAIN_NO_POWER;
01941 } else {
01942 str = STR_8861_STOPPED;
01943 }
01944 } else {
01945 SetDParam(0, v->GetDisplaySpeed());
01946 str = STR_TRAIN_STOPPING + _patches.vehicle_speed;
01947 }
01948 } else {
01949 str = STR_8861_STOPPED;
01950 }
01951 } else {
01952 switch (v->current_order.type) {
01953 case OT_GOTO_STATION: {
01954 SetDParam(0, v->current_order.dest);
01955 SetDParam(1, v->GetDisplaySpeed());
01956 str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
01957 } break;
01958
01959 case OT_GOTO_DEPOT: {
01960 if (v->type == VEH_AIRCRAFT) {
01961
01962 SetDParam(0, v->current_order.dest);
01963 SetDParam(1, v->GetDisplaySpeed());
01964 } else {
01965 Depot *depot = GetDepot(v->current_order.dest);
01966 SetDParam(0, depot->town_index);
01967 SetDParam(1, v->GetDisplaySpeed());
01968 }
01969 if (HasBit(v->current_order.flags, OF_HALT_IN_DEPOT) && !HasBit(v->current_order.flags, OF_PART_OF_ORDERS)) {
01970 str = _heading_for_depot_strings[v->type] + _patches.vehicle_speed;
01971 } else {
01972 str = _heading_for_depot_service_strings[v->type] + _patches.vehicle_speed;
01973 }
01974 } break;
01975
01976 case OT_LOADING:
01977 str = STR_882F_LOADING_UNLOADING;
01978 break;
01979
01980 case OT_GOTO_WAYPOINT: {
01981 assert(v->type == VEH_TRAIN);
01982 SetDParam(0, v->current_order.dest);
01983 str = STR_HEADING_FOR_WAYPOINT + _patches.vehicle_speed;
01984 SetDParam(1, v->GetDisplaySpeed());
01985 break;
01986 }
01987
01988 case OT_LEAVESTATION:
01989 if (v->type != VEH_AIRCRAFT) {
01990 str = STR_882F_LOADING_UNLOADING;
01991 break;
01992 }
01993
01994
01995 default:
01996 if (v->num_orders == 0) {
01997 str = STR_NO_ORDERS + _patches.vehicle_speed;
01998 SetDParam(0, v->GetDisplaySpeed());
01999 } else {
02000 str = STR_EMPTY;
02001 }
02002 break;
02003 }
02004 }
02005
02006
02007 DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, 2, w->widget[VVW_WIDGET_START_STOP_VEH].top + 1);
02008 DrawStringCenteredTruncated(w->widget[VVW_WIDGET_START_STOP_VEH].left + 8, w->widget[VVW_WIDGET_START_STOP_VEH].right, w->widget[VVW_WIDGET_START_STOP_VEH].top + 1, str, TC_FROMSTRING);
02009 DrawWindowViewport(w);
02010 }
02011
02013 enum VehicleCommandTranslation {
02014 VCT_CMD_START_STOP = 0,
02015 VCT_CMD_GOTO_DEPOT,
02016 VCT_CMD_CLONE_VEH,
02017 VCT_CMD_TURN_AROUND,
02018 };
02019
02021 static const uint32 _vehicle_command_translation_table[][4] = {
02022 {
02023 CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN),
02024 CMD_START_STOP_ROADVEH | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE),
02025 CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP),
02026 CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT)
02027 },
02028 {
02029
02030 CMD_SEND_TRAIN_TO_DEPOT | CMD_NO_TEST_IF_IN_NETWORK | CMD_MSG(STR_8830_CAN_T_SEND_TRAIN_TO_DEPOT),
02031 CMD_SEND_ROADVEH_TO_DEPOT | CMD_MSG(STR_9018_CAN_T_SEND_VEHICLE_TO_DEPOT),
02032 CMD_SEND_SHIP_TO_DEPOT | CMD_MSG(STR_9819_CAN_T_SEND_SHIP_TO_DEPOT),
02033 CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_MSG(STR_A012_CAN_T_SEND_AIRCRAFT_TO)
02034 },
02035 {
02036 CMD_CLONE_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE),
02037 CMD_CLONE_VEHICLE | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE),
02038 CMD_CLONE_VEHICLE | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP),
02039 CMD_CLONE_VEHICLE | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT)
02040 },
02041 {
02042 CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_8869_CAN_T_REVERSE_DIRECTION),
02043 CMD_TURN_ROADVEH | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN),
02044 0xffffffff,
02045 0xffffffff
02046 },
02047 };
02048
02050 static void VehicleViewWndProc(Window *w, WindowEvent *e)
02051 {
02052 switch (e->event) {
02053 case WE_CREATE:
02054 CreateVehicleViewWindow(w);
02055 break;
02056
02057 case WE_PAINT:
02058 DrawVehicleViewWindow(w);
02059 break;
02060
02061 case WE_CLICK: {
02062 const Vehicle *v = GetVehicle(w->window_number);
02063
02064 switch (e->we.click.widget) {
02065 case VVW_WIDGET_START_STOP_VEH:
02066 DoCommandP(v->tile, v->index, 0, NULL,
02067 _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type]);
02068 break;
02069 case VVW_WIDGET_CENTER_MAIN_VIEH: {
02070 const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
02071
02072 if (_ctrl_pressed && mainwindow->viewport->zoom == ZOOM_LVL_NORMAL) {
02073 WP(mainwindow, vp_d).follow_vehicle = v->index;
02074 } else {
02075 ScrollMainWindowTo(v->x_pos, v->y_pos);
02076 }
02077 } break;
02078
02079 case VVW_WIDGET_GOTO_DEPOT:
02080 DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL,
02081 _vehicle_command_translation_table[VCT_CMD_GOTO_DEPOT][v->type]);
02082 break;
02083 case VVW_WIDGET_REFIT_VEH:
02084 ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
02085 break;
02086 case VVW_WIDGET_SHOW_ORDERS:
02087 ShowOrdersWindow(v);
02088 break;
02089 case VVW_WIDGET_SHOW_DETAILS:
02090 ShowVehicleDetailsWindow(v);
02091 break;
02092 case VVW_WIDGET_CLONE_VEH:
02093 DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle,
02094 _vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type]);
02095 break;
02096 case VVW_WIDGET_TURN_AROUND:
02097 assert(v->type == VEH_TRAIN || v->type == VEH_ROAD);
02098 DoCommandP(v->tile, v->index, 0, NULL,
02099 _vehicle_command_translation_table[VCT_CMD_TURN_AROUND][v->type]);
02100 break;
02101 case VVW_WIDGET_FORCE_PROCEED:
02102 assert(v->type == VEH_TRAIN);
02103 DoCommandP(v->tile, v->index, 0, NULL, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL));
02104 break;
02105 }
02106 } break;
02107
02108 case WE_RESIZE:
02109 w->viewport->width += e->we.sizing.diff.x;
02110 w->viewport->height += e->we.sizing.diff.y;
02111 w->viewport->virtual_width += e->we.sizing.diff.x;
02112 w->viewport->virtual_height += e->we.sizing.diff.y;
02113 break;
02114
02115 case WE_DESTROY:
02116 DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
02117 DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
02118 DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
02119 DeleteWindowById(WC_VEHICLE_TIMETABLE, w->window_number);
02120 break;
02121
02122 case WE_MOUSELOOP: {
02123 const Vehicle *v = GetVehicle(w->window_number);
02124 bool veh_stopped = v->IsStoppedInDepot();
02125
02126
02127
02128
02129
02130
02131
02132 if (veh_stopped != w->IsWidgetHidden(VVW_WIDGET_GOTO_DEPOT) || veh_stopped == w->IsWidgetHidden(VVW_WIDGET_CLONE_VEH)) {
02133 w->SetWidgetHiddenState( VVW_WIDGET_GOTO_DEPOT, veh_stopped);
02134 w->SetWidgetHiddenState(VVW_WIDGET_CLONE_VEH, !veh_stopped);
02135 if (v->type == VEH_ROAD || v->type == VEH_TRAIN) {
02136 w->SetWidgetHiddenState( VVW_WIDGET_REFIT_VEH, !veh_stopped);
02137 w->SetWidgetHiddenState(VVW_WIDGET_TURN_AROUND, veh_stopped);
02138 }
02139 SetWindowDirty(w);
02140 }
02141 } break;
02142 }
02143 }
02144
02145 void DrawVehicleImage(const Vehicle *v, int x, int y, VehicleID selection, int count, int skip)
02146 {
02147 switch (v->type) {
02148 case VEH_TRAIN: DrawTrainImage(v, x, y, selection, count, skip); break;
02149 case VEH_ROAD: DrawRoadVehImage(v, x, y, selection, count); break;
02150 case VEH_SHIP: DrawShipImage(v, x, y, selection); break;
02151 case VEH_AIRCRAFT: DrawAircraftImage(v, x, y, selection); break;
02152 default: NOT_REACHED();
02153 }
02154 }