00001
00002
00005 #include "train.h"
00006 #include "ship.h"
00007 #include "aircraft.h"
00008 #include "gui.h"
00009 #include "textbuf_gui.h"
00010 #include "viewport_func.h"
00011 #include "gfx_func.h"
00012 #include "command_func.h"
00013 #include "depot_base.h"
00014 #include "vehicle_gui.h"
00015 #include "newgrf_engine.h"
00016 #include "spritecache.h"
00017 #include "strings_func.h"
00018 #include "window_func.h"
00019 #include "vehicle_func.h"
00020 #include "company_func.h"
00021 #include "tilehighlight_func.h"
00022 #include "window_gui.h"
00023 #include "vehiclelist.h"
00024
00025 #include "table/strings.h"
00026 #include "table/sprites.h"
00027
00028
00029
00030
00031
00032
00033
00034
00035 enum DepotWindowWidgets {
00036 DEPOT_WIDGET_CLOSEBOX = 0,
00037 DEPOT_WIDGET_CAPTION,
00038 DEPOT_WIDGET_STICKY,
00039 DEPOT_WIDGET_SELL,
00040 DEPOT_WIDGET_SELL_CHAIN,
00041 DEPOT_WIDGET_SELL_ALL,
00042 DEPOT_WIDGET_AUTOREPLACE,
00043 DEPOT_WIDGET_MATRIX,
00044 DEPOT_WIDGET_V_SCROLL,
00045 DEPOT_WIDGET_H_SCROLL,
00046 DEPOT_WIDGET_BUILD,
00047 DEPOT_WIDGET_CLONE,
00048 DEPOT_WIDGET_LOCATION,
00049 DEPOT_WIDGET_VEHICLE_LIST,
00050 DEPOT_WIDGET_STOP_ALL,
00051 DEPOT_WIDGET_START_ALL,
00052 DEPOT_WIDGET_RESIZE,
00053 };
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 static const Widget _depot_widgets[] = {
00072 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00073 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_GREY, 11, 23, 0, 13, 0x0, STR_018C_WINDOW_TITLE_DRAG_THIS},
00074 { WWT_STICKYBOX, RESIZE_LR, COLOUR_GREY, 24, 35, 0, 13, 0x0, STR_STICKY_BUTTON},
00075
00076
00077 { WWT_IMGBTN, RESIZE_LRB, COLOUR_GREY, 1, 23, 14, -32, 0x0, STR_NULL},
00078 { WWT_IMGBTN, RESIZE_LRTB, COLOUR_GREY, 1, 23, -55, -32, SPR_SELL_CHAIN_TRAIN,STR_DRAG_WHOLE_TRAIN_TO_SELL_TIP},
00079 { WWT_PUSHIMGBTN, RESIZE_LRTB, COLOUR_GREY, 1, 23, -31, -9, 0x0, STR_NULL},
00080 { WWT_PUSHIMGBTN, RESIZE_LRTB, COLOUR_GREY, 1, 23, -8, 14, 0x0, STR_NULL},
00081
00082 { WWT_MATRIX, RESIZE_RB, COLOUR_GREY, 0, 0, 14, 14, 0x0, STR_NULL},
00083 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_GREY, 24, 35, 14, 14, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00084
00085 { WWT_HSCROLLBAR, RESIZE_RTB, COLOUR_GREY, 0, 0, 3, 14, 0x0, STR_HSCROLL_BAR_SCROLLS_LIST},
00086
00087
00088
00089 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_GREY, 0, 0, 15, 26, 0x0, STR_NULL},
00090 { WWT_TEXTBTN, RESIZE_TB, COLOUR_GREY, 0, 0, 15, 26, 0x0, STR_NULL},
00091 { WWT_PUSHTXTBTN, RESIZE_RTB, COLOUR_GREY, 0, -12, 15, 26, STR_00E4_LOCATION, STR_NULL},
00092 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_GREY, -11, 0, 15, 26, 0x0, STR_NULL},
00093 { WWT_PUSHIMGBTN, RESIZE_LRTB, COLOUR_GREY, 1, 11, 15, 26, SPR_FLAG_VEH_STOPPED,STR_NULL},
00094 { WWT_PUSHIMGBTN, RESIZE_LRTB, COLOUR_GREY, 12, 23, 15, 26, SPR_FLAG_VEH_RUNNING,STR_NULL},
00095 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_GREY, 24, 35, 15, 26, 0x0, STR_RESIZE_BUTTON},
00096 { WIDGETS_END},
00097 };
00098
00099
00100 static const WindowDesc _train_depot_desc(
00101 WDP_AUTO, WDP_AUTO, 36, 27, 362, 123,
00102 WC_VEHICLE_DEPOT, WC_NONE,
00103 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00104 _depot_widgets
00105 );
00106
00107 static const WindowDesc _road_depot_desc(
00108 WDP_AUTO, WDP_AUTO, 36, 27, 316, 97,
00109 WC_VEHICLE_DEPOT, WC_NONE,
00110 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00111 _depot_widgets
00112 );
00113
00114 static const WindowDesc _ship_depot_desc(
00115 WDP_AUTO, WDP_AUTO, 36, 27, 306, 99,
00116 WC_VEHICLE_DEPOT, WC_NONE,
00117 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00118 _depot_widgets
00119 );
00120
00121 static const WindowDesc _aircraft_depot_desc(
00122 WDP_AUTO, WDP_AUTO, 36, 27, 332, 99,
00123 WC_VEHICLE_DEPOT, WC_NONE,
00124 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00125 _depot_widgets
00126 );
00127
00128 extern int WagonLengthToPixels(int len);
00129 extern void DepotSortList(VehicleList *list);
00130
00138 void CcCloneVehicle(bool success, TileIndex tile, uint32 p1, uint32 p2)
00139 {
00140 if (!success) return;
00141
00142 const Vehicle *v = GetVehicle(_new_vehicle_id);
00143
00144 ShowVehicleViewWindow(v);
00145 }
00146
00147 static void TrainDepotMoveVehicle(const Vehicle *wagon, VehicleID sel, const Vehicle *head)
00148 {
00149 const Vehicle *v = GetVehicle(sel);
00150
00151 if (v == wagon) return;
00152
00153 if (wagon == NULL) {
00154 if (head != NULL) wagon = GetLastVehicleInChain(head);
00155 } else {
00156 wagon = wagon->Previous();
00157 if (wagon == NULL) return;
00158 }
00159
00160 if (wagon == v) return;
00161
00162 DoCommandP(v->tile, v->index + ((wagon == NULL ? INVALID_VEHICLE : wagon->index) << 16), _ctrl_pressed ? 1 : 0, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_8837_CAN_T_MOVE_VEHICLE));
00163 }
00164
00165
00166
00167 uint _block_sizes[4][2];
00168
00169
00170
00171 const uint _resize_cap[][2] = {
00172 {6, 10 * 29},
00173 {5, 5},
00174 {3, 3},
00175 {3, 4},
00176 };
00177
00178 static void ResizeDefaultWindowSizeForTrains()
00179 {
00180 _block_sizes[VEH_TRAIN][0] = 1;
00181 _block_sizes[VEH_TRAIN][1] = GetVehicleListHeight(VEH_TRAIN);
00182 }
00183
00184 static void ResizeDefaultWindowSizeForRoadVehicles()
00185 {
00186 _block_sizes[VEH_ROAD][0] = 56;
00187 _block_sizes[VEH_ROAD][1] = GetVehicleListHeight(VEH_ROAD);
00188 }
00189
00190 static void ResizeDefaultWindowSize(VehicleType type)
00191 {
00192 uint max_width = 0;
00193 uint max_height = 0;
00194
00195 const Engine *e;
00196 FOR_ALL_ENGINES_OF_TYPE(e, type) {
00197 EngineID eid = e->index;
00198 uint x, y;
00199
00200 switch (type) {
00201 default: NOT_REACHED();
00202 case VEH_SHIP: GetShipSpriteSize( eid, x, y); break;
00203 case VEH_AIRCRAFT: GetAircraftSpriteSize(eid, x, y); break;
00204 }
00205 if (x > max_width) max_width = x;
00206 if (y > max_height) max_height = y;
00207 }
00208
00209 switch (type) {
00210 default: NOT_REACHED();
00211 case VEH_SHIP:
00212 _block_sizes[VEH_SHIP][0] = max(90U, max_width + 20);
00213 break;
00214 case VEH_AIRCRAFT:
00215 _block_sizes[VEH_AIRCRAFT][0] = max(74U, max_width);
00216 break;
00217 }
00218 _block_sizes[type][1] = max(GetVehicleListHeight(type), max_height);
00219 }
00220
00221
00222
00223 void InitDepotWindowBlockSizes()
00224 {
00225 ResizeDefaultWindowSizeForTrains();
00226 ResizeDefaultWindowSizeForRoadVehicles();
00227 ResizeDefaultWindowSize(VEH_SHIP);
00228 ResizeDefaultWindowSize(VEH_AIRCRAFT);
00229 }
00230
00231 static void DepotSellAllConfirmationCallback(Window *w, bool confirmed);
00232 const Sprite *GetAircraftSprite(EngineID engine);
00233
00234 struct DepotWindow : Window {
00235 VehicleID sel;
00236 VehicleType type;
00237 bool generate_list;
00238 VehicleList vehicle_list;
00239 VehicleList wagon_list;
00240
00241 DepotWindow(const WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc, tile)
00242 {
00243 this->sel = INVALID_VEHICLE;
00244 this->generate_list = true;
00245
00246 this->owner = GetTileOwner(tile);
00247 this->CreateDepotListWindow(type);
00248
00249 this->FindWindowPlacementAndResize(desc);
00250 }
00251
00252 ~DepotWindow()
00253 {
00254 DeleteWindowById(WC_BUILD_VEHICLE, this->window_number);
00255 }
00256
00263 void DrawVehicleInDepot(Window *w, const Vehicle *v, int x, int y)
00264 {
00265 byte diff_x = 0, diff_y = 0;
00266
00267 int sprite_y = y + this->resize.step_height - GetVehicleListHeight(v->type);
00268
00269 switch (v->type) {
00270 case VEH_TRAIN:
00271 DrawTrainImage(v, x + 21, sprite_y, this->sel, this->hscroll.cap + 4, this->hscroll.pos);
00272
00273
00274 SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
00275 DrawStringRightAligned(this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING);
00276 break;
00277
00278 case VEH_ROAD: DrawRoadVehImage( v, x + 24, sprite_y, this->sel, 1); break;
00279 case VEH_SHIP: DrawShipImage( v, x + 19, sprite_y - 1, this->sel); break;
00280 case VEH_AIRCRAFT: {
00281 const Sprite *spr = GetSprite(v->GetImage(DIR_W), ST_NORMAL);
00282 DrawAircraftImage(v, x + 12,
00283 y + max(spr->height + spr->y_offs - 14, 0),
00284 this->sel);
00285 } break;
00286 default: NOT_REACHED();
00287 }
00288
00289 if (this->resize.step_height == 14) {
00290
00291 diff_x = 15;
00292 } else {
00293
00294 diff_y = 12;
00295 }
00296
00297 DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, x + diff_x, y + diff_y);
00298
00299 SetDParam(0, v->unitnumber);
00300 DrawString(x, y + 2, (uint16)(v->max_age - DAYS_IN_LEAP_YEAR) >= v->age ? STR_00E2 : STR_00E3, TC_FROMSTRING);
00301 }
00302
00303 void DrawDepotWindow(Window *w)
00304 {
00305 TileIndex tile = this->window_number;
00306 int x, y, i, maxval;
00307 uint16 hnum;
00308
00309
00310 uint16 rows_in_display = this->widget[DEPOT_WIDGET_MATRIX].data >> 8;
00311 uint16 boxes_in_each_row = this->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
00312
00313
00314 this->SetWidgetsDisabledState(!IsTileOwner(tile, _local_company),
00315 DEPOT_WIDGET_STOP_ALL,
00316 DEPOT_WIDGET_START_ALL,
00317 DEPOT_WIDGET_SELL,
00318 DEPOT_WIDGET_SELL_CHAIN,
00319 DEPOT_WIDGET_SELL_ALL,
00320 DEPOT_WIDGET_BUILD,
00321 DEPOT_WIDGET_CLONE,
00322 DEPOT_WIDGET_AUTOREPLACE,
00323 WIDGET_LIST_END);
00324
00325
00326 if (this->type == VEH_TRAIN) {
00327 hnum = 8;
00328 for (uint num = 0; num < this->vehicle_list.Length(); num++) {
00329 const Vehicle *v = this->vehicle_list[num];
00330 hnum = max(hnum, v->u.rail.cached_total_length);
00331 }
00332
00333 SetVScrollCount(w, this->vehicle_list.Length() + this->wagon_list.Length() + 1);
00334 SetHScrollCount(w, WagonLengthToPixels(hnum));
00335 } else {
00336 SetVScrollCount(w, (this->vehicle_list.Length() + this->hscroll.cap - 1) / this->hscroll.cap);
00337 }
00338
00339
00340 if (this->type == VEH_AIRCRAFT) {
00341 SetDParam(0, GetStationIndex(tile));
00342 } else {
00343 Depot *depot = GetDepotByTile(tile);
00344 assert(depot != NULL);
00345
00346 SetDParam(0, depot->town_index);
00347 }
00348
00349 w->DrawWidgets();
00350
00351 uint16 num = this->vscroll.pos * boxes_in_each_row;
00352 maxval = min(this->vehicle_list.Length(), num + (rows_in_display * boxes_in_each_row));
00353
00354 for (x = 2, y = 15; num < maxval; y += this->resize.step_height, x = 2) {
00355 byte i;
00356
00357 for (i = 0; i < boxes_in_each_row && num < maxval; i++, num++, x += this->resize.step_width) {
00358
00359 const Vehicle *v = this->vehicle_list[num];
00360 DrawVehicleInDepot(w, v, x, y);
00361 }
00362 }
00363
00364 maxval = min(this->vehicle_list.Length() + this->wagon_list.Length(), (this->vscroll.pos * boxes_in_each_row) + (rows_in_display * boxes_in_each_row));
00365
00366
00367 for (; num < maxval; num++, y += 14) {
00368 const Vehicle *v = this->wagon_list[num - this->vehicle_list.Length()];
00369 const Vehicle *u;
00370
00371 DrawTrainImage(v, x + 50, y, this->sel, this->hscroll.cap - 29, 0);
00372 DrawString(x, y + 2, STR_8816, TC_FROMSTRING);
00373
00374
00375 i = 0;
00376 u = v;
00377 do i++; while ((u = u->Next()) != NULL);
00378 SetDParam(0, i);
00379 DrawStringRightAligned(this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING);
00380 }
00381 }
00382
00383 struct GetDepotVehiclePtData {
00384 const Vehicle *head;
00385 const Vehicle *wagon;
00386 };
00387
00388 enum DepotGUIAction {
00389 MODE_ERROR,
00390 MODE_DRAG_VEHICLE,
00391 MODE_SHOW_VEHICLE,
00392 MODE_START_STOP,
00393 };
00394
00395 DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, const Vehicle **veh, GetDepotVehiclePtData *d) const
00396 {
00397 uint xt, row, xm = 0, ym = 0;
00398 int pos, skip = 0;
00399 uint16 boxes_in_each_row = this->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
00400
00401 if (this->type == VEH_TRAIN) {
00402 xt = 0;
00403 x -= 23;
00404 } else {
00405 xt = x / this->resize.step_width;
00406 xm = x % this->resize.step_width;
00407 if (xt >= this->hscroll.cap) return MODE_ERROR;
00408
00409 ym = (y - 14) % this->resize.step_height;
00410 }
00411
00412 row = (y - 14) / this->resize.step_height;
00413 if (row >= this->vscroll.cap) return MODE_ERROR;
00414
00415 pos = ((row + this->vscroll.pos) * boxes_in_each_row) + xt;
00416
00417 if ((int)(this->vehicle_list.Length() + this->wagon_list.Length()) <= pos) {
00418 if (this->type == VEH_TRAIN) {
00419 d->head = NULL;
00420 d->wagon = NULL;
00421 return MODE_DRAG_VEHICLE;
00422 } else {
00423 return MODE_ERROR;
00424 }
00425 }
00426
00427 if ((int)this->vehicle_list.Length() > pos) {
00428 *veh = this->vehicle_list[pos];
00429 skip = this->hscroll.pos;
00430 } else {
00431 pos -= this->vehicle_list.Length();
00432 *veh = this->wagon_list[pos];
00433
00434 x -= _traininfo_vehicle_width;
00435 }
00436
00437 switch (this->type) {
00438 case VEH_TRAIN: {
00439 const Vehicle *v = *veh;
00440 d->head = d->wagon = v;
00441
00442
00443 if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
00444
00445 skip = (skip * 8) / _traininfo_vehicle_width;
00446 x = (x * 8) / _traininfo_vehicle_width;
00447
00448
00449 x += skip;
00450
00451
00452 while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->Next();
00453
00454
00455 while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
00456
00457 d->wagon = v;
00458
00459 return MODE_DRAG_VEHICLE;
00460 }
00461 break;
00462
00463 case VEH_ROAD:
00464 if (xm >= 24) return MODE_DRAG_VEHICLE;
00465 if (xm <= 16) return MODE_SHOW_VEHICLE;
00466 break;
00467
00468 case VEH_SHIP:
00469 if (xm >= 19) return MODE_DRAG_VEHICLE;
00470 if (ym <= 10) return MODE_SHOW_VEHICLE;
00471 break;
00472
00473 case VEH_AIRCRAFT:
00474 if (xm >= 12) return MODE_DRAG_VEHICLE;
00475 if (ym <= 12) return MODE_SHOW_VEHICLE;
00476 break;
00477
00478 default: NOT_REACHED();
00479 }
00480 return MODE_START_STOP;
00481 }
00482
00483 void DepotClick(int x, int y)
00484 {
00485 GetDepotVehiclePtData gdvp = { NULL, NULL };
00486 const Vehicle *v = NULL;
00487 DepotGUIAction mode = this->GetVehicleFromDepotWndPt(x, y, &v, &gdvp);
00488
00489
00490 if (_thd.place_mode != VHM_NONE && mode != MODE_ERROR) {
00491 _place_clicked_vehicle = (this->type == VEH_TRAIN ? gdvp.head : v);
00492 return;
00493 }
00494
00495 if (this->type == VEH_TRAIN) v = gdvp.wagon;
00496
00497 switch (mode) {
00498 case MODE_ERROR:
00499 return;
00500
00501 case MODE_DRAG_VEHICLE: {
00502 VehicleID sel = this->sel;
00503
00504 if (this->type == VEH_TRAIN && sel != INVALID_VEHICLE) {
00505 this->sel = INVALID_VEHICLE;
00506 TrainDepotMoveVehicle(v, sel, gdvp.head);
00507 } else if (v != NULL) {
00508 int image = v->GetImage(DIR_W);
00509
00510 this->sel = v->index;
00511 this->SetDirty();
00512 SetObjectToPlaceWnd(image, GetVehiclePalette(v), VHM_DRAG, this);
00513
00514 switch (v->type) {
00515 case VEH_TRAIN:
00516 _cursor.short_vehicle_offset = 16 - v->u.rail.cached_veh_length * 2;
00517 break;
00518
00519 case VEH_ROAD:
00520 _cursor.short_vehicle_offset = 16 - v->u.road.cached_veh_length * 2;
00521 break;
00522
00523 default:
00524 _cursor.short_vehicle_offset = 0;
00525 break;
00526 }
00527 _cursor.vehchain = _ctrl_pressed;
00528 }
00529 } break;
00530
00531 case MODE_SHOW_VEHICLE:
00532 ShowVehicleViewWindow(v);
00533 break;
00534
00535 case MODE_START_STOP: {
00536 uint command;
00537
00538 switch (this->type) {
00539 case VEH_TRAIN: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN); break;
00540 case VEH_ROAD: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE); break;
00541 case VEH_SHIP: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP); break;
00542 case VEH_AIRCRAFT: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT); break;
00543 default: NOT_REACHED(); command = 0;
00544 }
00545 DoCommandP(v->tile, v->index, 0, command);
00546 } break;
00547
00548 default: NOT_REACHED();
00549 }
00550 }
00551
00557 void HandleCloneVehClick(const Vehicle *v, const Window *w)
00558 {
00559 uint error_str;
00560
00561 if (v == NULL) return;
00562
00563 if (!v->IsPrimaryVehicle()) {
00564 v = v->First();
00565
00566 if (v->type == VEH_TRAIN && !IsFrontEngine(v)) return;
00567 }
00568
00569 switch (v->type) {
00570 case VEH_TRAIN: error_str = CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE); break;
00571 case VEH_ROAD: error_str = CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE); break;
00572 case VEH_SHIP: error_str = CMD_MSG(STR_980D_CAN_T_BUILD_SHIP); break;
00573 case VEH_AIRCRAFT: error_str = CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT); break;
00574 default: return;
00575 }
00576
00577 DoCommandP(this->window_number, v->index, _ctrl_pressed ? 1 : 0, CMD_CLONE_VEHICLE | error_str, CcCloneVehicle);
00578
00579 ResetObjectToPlace();
00580 }
00581
00582 void ResizeDepotButtons(Window *w)
00583 {
00584 ResizeButtons(w, DEPOT_WIDGET_BUILD, DEPOT_WIDGET_LOCATION);
00585
00586 if (this->type == VEH_TRAIN) {
00587
00588
00589 this->widget[DEPOT_WIDGET_SELL_CHAIN].top = ((this->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - this->widget[DEPOT_WIDGET_SELL].top) / 2) + this->widget[DEPOT_WIDGET_SELL].top;
00590 this->widget[DEPOT_WIDGET_SELL].bottom = this->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1;
00591 }
00592 }
00593
00594
00595
00596
00597
00598 void SetupStringsForDepotWindow(VehicleType type)
00599 {
00600 switch (type) {
00601 default: NOT_REACHED();
00602
00603 case VEH_TRAIN:
00604 this->widget[DEPOT_WIDGET_CAPTION].data = STR_8800_TRAIN_DEPOT;
00605 this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_TRAIN_TIP;
00606 this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_TRAIN_TIP;
00607 this->widget[DEPOT_WIDGET_SELL].tooltips = STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE;
00608 this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP;
00609
00610 this->widget[DEPOT_WIDGET_BUILD].data = STR_8815_NEW_VEHICLES;
00611 this->widget[DEPOT_WIDGET_BUILD].tooltips = STR_8840_BUILD_NEW_TRAIN_VEHICLE;
00612 this->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_TRAIN;
00613 this->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_TRAIN_DEPOT_INFO;
00614
00615 this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_8842_CENTER_MAIN_VIEW_ON_TRAIN;
00616 this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_TRAIN;
00617 this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TIP;
00618 this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_TRAIN_TIP;
00619
00620
00621 this->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_TRAIN;
00622 this->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_TRAIN;
00623 this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_TRAIN;
00624 break;
00625
00626 case VEH_ROAD:
00627 this->widget[DEPOT_WIDGET_CAPTION].data = STR_9003_ROAD_VEHICLE_DEPOT;
00628 this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_ROADVEH_TIP;
00629 this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_ROADVEH_TIP;
00630 this->widget[DEPOT_WIDGET_SELL].tooltips = STR_9024_DRAG_ROAD_VEHICLE_TO_HERE;
00631 this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP;
00632
00633 this->widget[DEPOT_WIDGET_BUILD].data = STR_9004_NEW_VEHICLES;
00634 this->widget[DEPOT_WIDGET_BUILD].tooltips = STR_9023_BUILD_NEW_ROAD_VEHICLE;
00635 this->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_ROAD_VEHICLE;
00636 this->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_ROAD_VEHICLE_DEPOT_INFO;
00637
00638 this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9025_CENTER_MAIN_VIEW_ON_ROAD;
00639 this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_LORRY;
00640 this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_ROADVEH_TIP;
00641 this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_ROADVEH_TIP;
00642
00643
00644 this->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_ROADVEH;
00645 this->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_ROADVEH;
00646 this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_ROADVEH;
00647 break;
00648
00649 case VEH_SHIP:
00650 this->widget[DEPOT_WIDGET_CAPTION].data = STR_9803_SHIP_DEPOT;
00651 this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_SHIP_TIP;
00652 this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_SHIP_TIP;
00653 this->widget[DEPOT_WIDGET_SELL].tooltips = STR_9821_DRAG_SHIP_TO_HERE_TO_SELL;
00654 this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP;
00655
00656 this->widget[DEPOT_WIDGET_BUILD].data = STR_9804_NEW_SHIPS;
00657 this->widget[DEPOT_WIDGET_BUILD].tooltips = STR_9820_BUILD_NEW_SHIP;
00658 this->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_SHIP;
00659 this->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_SHIP_DEPOT_INFO;
00660
00661 this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9822_CENTER_MAIN_VIEW_ON_SHIP;
00662 this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_SHIP;
00663 this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TIP;
00664 this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_SHIP_TIP;
00665
00666
00667 this->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_SHIP;
00668 this->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_SHIP;
00669 this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_SHIP;
00670 break;
00671
00672 case VEH_AIRCRAFT:
00673 this->widget[DEPOT_WIDGET_CAPTION].data = STR_A002_AIRCRAFT_HANGAR;
00674 this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_HANGAR_TIP;
00675 this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_HANGAR_TIP;
00676 this->widget[DEPOT_WIDGET_SELL].tooltips = STR_A023_DRAG_AIRCRAFT_TO_HERE_TO;
00677 this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TIP;
00678
00679 this->widget[DEPOT_WIDGET_BUILD].data = STR_A003_NEW_AIRCRAFT;
00680 this->widget[DEPOT_WIDGET_BUILD].tooltips = STR_A022_BUILD_NEW_AIRCRAFT;
00681 this->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_AIRCRAFT;
00682 this->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW;
00683
00684 this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_A024_CENTER_MAIN_VIEW_ON_HANGAR;
00685 this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_PLANE;
00686 this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TIP;
00687 this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP;
00688
00689
00690 this->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_AIRCRAFT;
00691 this->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_AIRCRAFT;
00692 this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_AIRCRAFT;
00693 break;
00694 }
00695 }
00696
00697 void CreateDepotListWindow(VehicleType type)
00698 {
00699 this->type = type;
00700 _backup_orders_tile = 0;
00701
00702 assert(IsCompanyBuildableVehicleType(type));
00703
00704
00705
00706
00707 this->vscroll.cap = _resize_cap[type][0];
00708 this->hscroll.cap = _resize_cap[type][1];
00709
00710
00711 this->resize.step_width = _block_sizes[type][0];
00712 this->resize.step_height = _block_sizes[type][1];
00713
00714
00715 ResizeWindow(this,
00716 _block_sizes[type][0] * this->hscroll.cap,
00717 _block_sizes[type][1] * this->vscroll.cap);
00718
00719 if (type == VEH_TRAIN) {
00720
00721
00722 ResizeWindow(this, 36, 12);
00723
00724 this->widget[DEPOT_WIDGET_MATRIX].bottom -= 12;
00725 }
00726
00727
00728 this->resize.width = this->width;
00729 this->resize.height = this->height;
00730
00731 this->SetupStringsForDepotWindow(type);
00732
00733 this->widget[DEPOT_WIDGET_MATRIX].data =
00734 (this->vscroll.cap * 0x100)
00735 + (type == VEH_TRAIN ? 1 : this->hscroll.cap);
00736
00737
00738 this->SetWidgetsHiddenState(type != VEH_TRAIN,
00739 DEPOT_WIDGET_H_SCROLL,
00740 DEPOT_WIDGET_SELL_CHAIN,
00741 WIDGET_LIST_END);
00742
00743 ResizeDepotButtons(this);
00744 }
00745
00746 virtual void OnInvalidateData(int data)
00747 {
00748 this->generate_list = true;
00749 }
00750
00751 virtual void OnPaint()
00752 {
00753 if (this->generate_list) {
00754
00755
00756 BuildDepotVehicleList(this->type, this->window_number, &this->vehicle_list, &this->wagon_list);
00757 this->generate_list = false;
00758 DepotSortList(&this->vehicle_list);
00759 }
00760 DrawDepotWindow(this);
00761 }
00762
00763 virtual void OnClick(Point pt, int widget)
00764 {
00765 switch (widget) {
00766 case DEPOT_WIDGET_MATRIX:
00767 this->DepotClick(pt.x, pt.y);
00768 break;
00769
00770 case DEPOT_WIDGET_BUILD:
00771 ResetObjectToPlace();
00772 ShowBuildVehicleWindow(this->window_number, this->type);
00773 break;
00774
00775 case DEPOT_WIDGET_CLONE:
00776 this->InvalidateWidget(DEPOT_WIDGET_CLONE);
00777 this->ToggleWidgetLoweredState(DEPOT_WIDGET_CLONE);
00778
00779 if (this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
00780 static const CursorID clone_icons[] = {
00781 SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH,
00782 SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE
00783 };
00784
00785 _place_clicked_vehicle = NULL;
00786 SetObjectToPlaceWnd(clone_icons[this->type], PAL_NONE, VHM_RECT, this);
00787 } else {
00788 ResetObjectToPlace();
00789 }
00790 break;
00791
00792 case DEPOT_WIDGET_LOCATION:
00793 if (_ctrl_pressed) {
00794 ShowExtraViewPortWindow(this->window_number);
00795 } else {
00796 ScrollMainWindowToTile(this->window_number);
00797 }
00798 break;
00799
00800 case DEPOT_WIDGET_STOP_ALL:
00801 case DEPOT_WIDGET_START_ALL:
00802 DoCommandP(this->window_number, 0, this->type | (widget == DEPOT_WIDGET_START_ALL ? (1 << 5) : 0), CMD_MASS_START_STOP);
00803 break;
00804
00805 case DEPOT_WIDGET_SELL_ALL:
00806
00807 if (this->vehicle_list.Length() != 0 || this->wagon_list.Length() != 0) {
00808 static const StringID confirm_captions[] = {
00809 STR_8800_TRAIN_DEPOT,
00810 STR_9003_ROAD_VEHICLE_DEPOT,
00811 STR_9803_SHIP_DEPOT,
00812 STR_A002_AIRCRAFT_HANGAR
00813 };
00814 TileIndex tile = this->window_number;
00815 byte vehtype = this->type;
00816
00817 SetDParam(0, (vehtype == VEH_AIRCRAFT) ? GetStationIndex(tile) : GetDepotByTile(tile)->town_index);
00818 ShowQuery(
00819 confirm_captions[vehtype],
00820 STR_DEPOT_SELL_CONFIRMATION_TEXT,
00821 this,
00822 DepotSellAllConfirmationCallback
00823 );
00824 }
00825 break;
00826
00827 case DEPOT_WIDGET_VEHICLE_LIST:
00828 ShowVehicleListWindow(GetTileOwner(this->window_number), this->type, (TileIndex)this->window_number);
00829 break;
00830
00831 case DEPOT_WIDGET_AUTOREPLACE:
00832 DoCommandP(this->window_number, this->type, 0, CMD_DEPOT_MASS_AUTOREPLACE);
00833 break;
00834
00835 }
00836 }
00837
00838 virtual void OnRightClick(Point pt, int widget)
00839 {
00840 if (widget != DEPOT_WIDGET_MATRIX) return;
00841
00842 GetDepotVehiclePtData gdvp = { NULL, NULL };
00843 const Vehicle *v = NULL;
00844 DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp);
00845
00846 if (this->type == VEH_TRAIN) v = gdvp.wagon;
00847
00848 if (v != NULL && mode == MODE_DRAG_VEHICLE) {
00849 AcceptedCargo capacity, loaded;
00850 memset(capacity, 0, sizeof(capacity));
00851 memset(loaded, 0, sizeof(loaded));
00852
00853
00854 bool whole_chain = (this->type == VEH_TRAIN && _ctrl_pressed);
00855
00856
00857 uint num = 0;
00858 for (const Vehicle *w = v; w != NULL; w = w->Next()) {
00859 if (w->cargo_cap > 0 && w->cargo_type < NUM_CARGO) {
00860 capacity[w->cargo_type] += w->cargo_cap;
00861 loaded [w->cargo_type] += w->cargo.Count();
00862 }
00863
00864 if (w->type == VEH_TRAIN && !EngineHasArticPart(w)) {
00865 num++;
00866 if (!whole_chain) break;
00867 }
00868 }
00869
00870
00871 static char details[1024];
00872 details[0] = '\0';
00873 char *pos = details;
00874
00875 for (CargoID cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
00876 if (capacity[cargo_type] == 0) continue;
00877
00878 SetDParam(0, cargo_type);
00879 SetDParam(1, loaded[cargo_type]);
00880 SetDParam(2, cargo_type);
00881 SetDParam(3, capacity[cargo_type]);
00882 pos = GetString(pos, STR_DEPOT_VEHICLE_TOOLTIP_CARGO, lastof(details));
00883 }
00884
00885
00886 uint64 args[2];
00887 args[0] = (whole_chain ? num : v->engine_type);
00888 args[1] = (uint64)(size_t)details;
00889 GuiShowTooltips(whole_chain ? STR_DEPOT_VEHICLE_TOOLTIP_CHAIN : STR_DEPOT_VEHICLE_TOOLTIP, 2, args);
00890 } else {
00891
00892 StringID tooltip = INVALID_STRING_ID;
00893 switch (this->type) {
00894 case VEH_TRAIN: tooltip = STR_883F_TRAINS_CLICK_ON_TRAIN_FOR; break;
00895 case VEH_ROAD: tooltip = STR_9022_VEHICLES_CLICK_ON_VEHICLE; break;
00896 case VEH_SHIP: tooltip = STR_981F_SHIPS_CLICK_ON_SHIP_FOR; break;
00897 case VEH_AIRCRAFT: tooltip = STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT;break;
00898 default: NOT_REACHED();
00899 }
00900 GuiShowTooltips(tooltip);
00901 }
00902 }
00903
00904
00905 virtual void OnPlaceObject(Point pt, TileIndex tile)
00906 {
00907 const Vehicle *v = CheckMouseOverVehicle();
00908
00909 if (v != NULL) HandleCloneVehClick(v, this);
00910 }
00911
00912 virtual void OnPlaceObjectAbort()
00913 {
00914
00915 this->RaiseWidget(DEPOT_WIDGET_CLONE);
00916 this->InvalidateWidget(DEPOT_WIDGET_CLONE);
00917
00918
00919 this->sel = INVALID_VEHICLE;
00920 this->InvalidateWidget(DEPOT_WIDGET_MATRIX);
00921 };
00922
00923
00924 virtual void OnMouseLoop()
00925 {
00926 const Vehicle *v = _place_clicked_vehicle;
00927
00928
00929 if (v != NULL && this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
00930 _place_clicked_vehicle = NULL;
00931 HandleCloneVehClick(v, this);
00932 }
00933 }
00934
00935 virtual void OnDragDrop(Point pt, int widget)
00936 {
00937 switch (widget) {
00938 case DEPOT_WIDGET_MATRIX: {
00939 const Vehicle *v = NULL;
00940 VehicleID sel = this->sel;
00941
00942 this->sel = INVALID_VEHICLE;
00943 this->SetDirty();
00944
00945 if (this->type == VEH_TRAIN) {
00946 GetDepotVehiclePtData gdvp = { NULL, NULL };
00947
00948 if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE &&
00949 sel != INVALID_VEHICLE) {
00950 if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
00951 DoCommandP(GetVehicle(sel)->tile, GetVehicle(sel)->index, true, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
00952 } else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
00953 TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
00954 } else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
00955 ShowVehicleViewWindow(gdvp.head);
00956 }
00957 }
00958 } else if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, NULL) == MODE_DRAG_VEHICLE &&
00959 v != NULL &&
00960 sel == v->index) {
00961 ShowVehicleViewWindow(v);
00962 }
00963 } break;
00964
00965 case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN:
00966 if (!this->IsWidgetDisabled(DEPOT_WIDGET_SELL) &&
00967 this->sel != INVALID_VEHICLE) {
00968 uint command;
00969
00970 if (this->IsWidgetDisabled(widget)) return;
00971 if (this->sel == INVALID_VEHICLE) return;
00972
00973 this->HandleButtonClick(widget);
00974
00975 const Vehicle *v = GetVehicle(this->sel);
00976 this->sel = INVALID_VEHICLE;
00977 this->SetDirty();
00978
00979 int sell_cmd = (v->type == VEH_TRAIN && (widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
00980
00981 bool is_engine = (!(v->type == VEH_TRAIN && !IsFrontEngine(v)));
00982
00983 if (is_engine) {
00984 _backup_orders_tile = v->tile;
00985 BackupVehicleOrders(v);
00986 }
00987
00988 switch (v->type) {
00989 case VEH_TRAIN: command = CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE); break;
00990 case VEH_ROAD: command = CMD_SELL_ROAD_VEH | CMD_MSG(STR_9014_CAN_T_SELL_ROAD_VEHICLE); break;
00991 case VEH_SHIP: command = CMD_SELL_SHIP | CMD_MSG(STR_980C_CAN_T_SELL_SHIP); break;
00992 case VEH_AIRCRAFT: command = CMD_SELL_AIRCRAFT | CMD_MSG(STR_A01C_CAN_T_SELL_AIRCRAFT); break;
00993 default: NOT_REACHED(); command = 0;
00994 }
00995
00996 if (!DoCommandP(v->tile, v->index, sell_cmd, command) && is_engine) _backup_orders_tile = 0;
00997 }
00998 break;
00999 default:
01000 this->sel = INVALID_VEHICLE;
01001 this->SetDirty();
01002 }
01003 _cursor.vehchain = false;
01004 }
01005
01006 virtual void OnResize(Point new_size, Point delta)
01007 {
01008 this->vscroll.cap += delta.y / (int)this->resize.step_height;
01009 this->hscroll.cap += delta.x / (int)this->resize.step_width;
01010 this->widget[DEPOT_WIDGET_MATRIX].data = (this->vscroll.cap << 8) + (this->type == VEH_TRAIN ? 1 : this->hscroll.cap);
01011 ResizeDepotButtons(this);
01012 }
01013
01014 virtual EventState OnCTRLStateChange()
01015 {
01016 if (this->sel != INVALID_VEHICLE) {
01017 _cursor.vehchain = _ctrl_pressed;
01018 this->InvalidateWidget(DEPOT_WIDGET_MATRIX);
01019 return ES_HANDLED;
01020 }
01021
01022 return ES_NOT_HANDLED;
01023 }
01024 };
01025
01026 static void DepotSellAllConfirmationCallback(Window *win, bool confirmed)
01027 {
01028 if (confirmed) {
01029 DepotWindow *w = (DepotWindow*)win;
01030 TileIndex tile = w->window_number;
01031 byte vehtype = w->type;
01032 DoCommandP(tile, vehtype, 0, CMD_DEPOT_SELL_ALL_VEHICLES);
01033 }
01034 }
01035
01040 void ShowDepotWindow(TileIndex tile, VehicleType type)
01041 {
01042 if (BringWindowToFrontById(WC_VEHICLE_DEPOT, tile) != NULL) return;
01043
01044 const WindowDesc *desc;
01045 switch (type) {
01046 default: NOT_REACHED();
01047 case VEH_TRAIN: desc = &_train_depot_desc; break;
01048 case VEH_ROAD: desc = &_road_depot_desc; break;
01049 case VEH_SHIP: desc = &_ship_depot_desc; break;
01050 case VEH_AIRCRAFT: desc = &_aircraft_depot_desc; break;
01051 }
01052
01053 new DepotWindow(desc, tile, type);
01054 }
01055
01059 void DeleteDepotHighlightOfVehicle(const Vehicle *v)
01060 {
01061 DepotWindow *w;
01062
01063
01064
01065
01066 if (_special_mouse_mode != WSM_DRAGDROP) return;
01067
01068 w = dynamic_cast<DepotWindow*>(FindWindowById(WC_VEHICLE_DEPOT, v->tile));
01069 if (w != NULL) {
01070 if (w->sel == v->index) ResetObjectToPlace();
01071 }
01072 }