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