00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "debug.h"
00008 #include "gui.h"
00009 #include "window_gui.h"
00010 #include "textbuf_gui.h"
00011 #include "company_func.h"
00012 #include "command_func.h"
00013 #include "vehicle_gui.h"
00014 #include "cargotype.h"
00015 #include "station_gui.h"
00016 #include "strings_func.h"
00017 #include "window_func.h"
00018 #include "viewport_func.h"
00019 #include "gfx_func.h"
00020 #include "widgets/dropdown_func.h"
00021 #include "newgrf_cargo.h"
00022 #include "station_map.h"
00023 #include "tilehighlight_func.h"
00024 #include "core/smallmap_type.hpp"
00025 #include "company_base.h"
00026 #include "sortlist_type.h"
00027 #include "settings_type.h"
00028
00029 #include "table/strings.h"
00030 #include "table/sprites.h"
00031
00046 static void StationsWndShowStationRating(int x, int y, CargoID type, uint amount, byte rating)
00047 {
00048 static const uint units_full = 576;
00049 static const uint rating_full = 224;
00050
00051 const CargoSpec *cs = GetCargo(type);
00052 if (!cs->IsValid()) return;
00053
00054 int colour = cs->rating_colour;
00055 uint w = (minu(amount, units_full) + 5) / 36;
00056
00057
00058 if (w != 0) GfxFillRect(x, y, x + w - 1, y + 6, colour);
00059
00060
00061
00062 if (w == 0) {
00063 uint rest = amount / 5;
00064 if (rest != 0) {
00065 w += x;
00066 GfxFillRect(w, y + 6 - rest, w, y + 6, colour);
00067 }
00068 }
00069
00070 DrawString(x + 1, y, cs->abbrev, TC_BLACK);
00071
00072
00073 y += 8;
00074 GfxFillRect(x + 1, y, x + 14, y, 0xB8);
00075 rating = minu(rating, rating_full) / 16;
00076 if (rating != 0) GfxFillRect(x + 1, y, x + rating, y, 0xD0);
00077 }
00078
00079 typedef GUIList<const Station*> GUIStationList;
00080
00084 class CompanyStationsWindow : public Window
00085 {
00087 enum StationListWidgets {
00088 SLW_CLOSEBOX = 0,
00089 SLW_CAPTION,
00090 SLW_STICKY,
00091 SLW_LIST,
00092 SLW_SCROLLBAR,
00093 SLW_RESIZE,
00094
00095 SLW_TRAIN,
00096 SLW_TRUCK,
00097 SLW_BUS,
00098 SLW_AIRPLANE,
00099 SLW_SHIP,
00100 SLW_FACILALL,
00101
00102 SLW_PAN_BETWEEN,
00103 SLW_NOCARGOWAITING,
00104 SLW_CARGOALL,
00105 SLW_PAN_RIGHT,
00106
00107 SLW_SORTBY,
00108 SLW_SORTDROPBTN,
00109 SLW_PAN_SORT_RIGHT,
00110
00111 SLW_CARGOSTART,
00112 };
00113
00114 protected:
00115
00116 static Listing last_sorting;
00117 static byte facilities;
00118 static bool include_empty;
00119 static const uint32 cargo_filter_max;
00120 static uint32 cargo_filter;
00121 static const Station *last_station;
00122
00123
00124 static const StringID sorter_names[];
00125 static GUIStationList::SortFunction * const sorter_funcs[];
00126
00127 GUIStationList stations;
00128
00129
00135 void BuildStationsList(const Owner owner)
00136 {
00137 if (!this->stations.NeedRebuild()) return;
00138
00139 DEBUG(misc, 3, "Building station list for company %d", owner);
00140
00141 this->stations.Clear();
00142
00143 const Station *st;
00144 FOR_ALL_STATIONS(st) {
00145 if (st->owner == owner || (st->owner == OWNER_NONE && !st->IsBuoy() && HasStationInUse(st->index, owner))) {
00146 if (this->facilities & st->facilities) {
00147 int num_waiting_cargo = 0;
00148 for (CargoID j = 0; j < NUM_CARGO; j++) {
00149 if (!st->goods[j].cargo.Empty()) {
00150 num_waiting_cargo++;
00151 if (HasBit(this->cargo_filter, j)) {
00152 *this->stations.Append() = st;
00153 break;
00154 }
00155 }
00156 }
00157
00158 if (num_waiting_cargo == 0 && this->include_empty) {
00159 *this->stations.Append() = st;
00160 }
00161 }
00162 }
00163 }
00164
00165 this->stations.Compact();
00166 this->stations.RebuildDone();
00167 }
00168
00170 static int CDECL StationNameSorter(const Station * const *a, const Station * const *b)
00171 {
00172 static char buf_cache[64];
00173 char buf[64];
00174
00175 SetDParam(0, (*a)->index);
00176 GetString(buf, STR_STATION, lastof(buf));
00177
00178 if (*b != last_station) {
00179 last_station = *b;
00180 SetDParam(0, (*b)->index);
00181 GetString(buf_cache, STR_STATION, lastof(buf_cache));
00182 }
00183
00184 return strcmp(buf, buf_cache);
00185 }
00186
00188 static int CDECL StationTypeSorter(const Station * const *a, const Station * const *b)
00189 {
00190 return (*a)->facilities - (*b)->facilities;
00191 }
00192
00194 static int CDECL StationWaitingSorter(const Station * const *a, const Station * const *b)
00195 {
00196 Money diff = 0;
00197
00198 for (CargoID j = 0; j < NUM_CARGO; j++) {
00199 if (!HasBit(cargo_filter, j)) continue;
00200 if (!(*a)->goods[j].cargo.Empty()) diff += GetTransportedGoodsIncome((*a)->goods[j].cargo.Count(), 20, 50, j);
00201 if (!(*b)->goods[j].cargo.Empty()) diff -= GetTransportedGoodsIncome((*b)->goods[j].cargo.Count(), 20, 50, j);
00202 }
00203
00204 return ClampToI32(diff);
00205 }
00206
00208 static int CDECL StationRatingMaxSorter(const Station * const *a, const Station * const *b)
00209 {
00210 byte maxr1 = 0;
00211 byte maxr2 = 0;
00212
00213 for (CargoID j = 0; j < NUM_CARGO; j++) {
00214 if (HasBit((*a)->goods[j].acceptance_pickup, GoodsEntry::PICKUP)) maxr1 = max(maxr1, (*a)->goods[j].rating);
00215 if (HasBit((*b)->goods[j].acceptance_pickup, GoodsEntry::PICKUP)) maxr2 = max(maxr2, (*b)->goods[j].rating);
00216 }
00217
00218 return maxr1 - maxr2;
00219 }
00220
00222 void SortStationsList()
00223 {
00224 if (!this->stations.Sort()) return;
00225
00226
00227 this->last_station = NULL;
00228
00229
00230 this->InvalidateWidget(SLW_LIST);
00231 }
00232
00233 public:
00234 CompanyStationsWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
00235 {
00236 this->owner = (Owner)this->window_number;
00237 this->vscroll.cap = 12;
00238 this->resize.step_height = 10;
00239 this->resize.height = this->height - 10 * 7;
00240
00241
00242 uint num_active = 0;
00243 for (CargoID c = 0; c < NUM_CARGO; c++) {
00244 if (GetCargo(c)->IsValid()) num_active++;
00245 }
00246
00247 this->widget_count += num_active;
00248 this->widget = ReallocT(this->widget, this->widget_count + 1);
00249 this->widget[this->widget_count].type = WWT_LAST;
00250
00251 uint i = 0;
00252 for (CargoID c = 0; c < NUM_CARGO; c++) {
00253 if (!GetCargo(c)->IsValid()) continue;
00254
00255 Widget *wi = &this->widget[SLW_CARGOSTART + i];
00256 wi->type = WWT_PANEL;
00257 wi->display_flags = RESIZE_NONE;
00258 wi->colour = COLOUR_GREY;
00259 wi->left = 89 + i * 14;
00260 wi->right = wi->left + 13;
00261 wi->top = 14;
00262 wi->bottom = 24;
00263 wi->data = 0;
00264 wi->tooltips = STR_USE_CTRL_TO_SELECT_MORE;
00265
00266 if (HasBit(this->cargo_filter, c)) this->LowerWidget(SLW_CARGOSTART + i);
00267 i++;
00268 }
00269
00270 this->widget[SLW_NOCARGOWAITING].left += num_active * 14;
00271 this->widget[SLW_NOCARGOWAITING].right += num_active * 14;
00272 this->widget[SLW_CARGOALL].left += num_active * 14;
00273 this->widget[SLW_CARGOALL].right += num_active * 14;
00274 this->widget[SLW_PAN_RIGHT].left += num_active * 14;
00275
00276 if (num_active > 15) {
00277
00278 ResizeWindow(this, (num_active - 15) * 14, 0);
00279 this->resize.width = this->width;
00280 }
00281
00282 if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = _cargo_mask;
00283
00284 for (uint i = 0; i < 5; i++) {
00285 if (HasBit(this->facilities, i)) this->LowerWidget(i + SLW_TRAIN);
00286 }
00287 this->SetWidgetLoweredState(SLW_FACILALL, this->facilities == (FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK));
00288 this->SetWidgetLoweredState(SLW_CARGOALL, this->cargo_filter == _cargo_mask && this->include_empty);
00289 this->SetWidgetLoweredState(SLW_NOCARGOWAITING, this->include_empty);
00290
00291 this->stations.SetListing(this->last_sorting);
00292 this->stations.SetSortFuncs(this->sorter_funcs);
00293 this->stations.ForceRebuild();
00294 this->stations.NeedResort();
00295 this->SortStationsList();
00296
00297 this->widget[SLW_SORTDROPBTN].data = this->sorter_names[this->stations.SortType()];
00298
00299 this->FindWindowPlacementAndResize(desc);
00300 }
00301
00302 ~CompanyStationsWindow()
00303 {
00304 this->last_sorting = this->stations.GetListing();
00305 }
00306
00307 virtual void OnPaint()
00308 {
00309 const Owner owner = (Owner)this->window_number;
00310
00311 this->BuildStationsList(owner);
00312 this->SortStationsList();
00313
00314 SetVScrollCount(this, this->stations.Length());
00315
00316
00317 SetDParam(0, owner);
00318 SetDParam(1, this->vscroll.count);
00319
00320 this->DrawWidgets();
00321
00322
00323 this->DrawSortButtonState(SLW_SORTBY, this->stations.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00324
00325 int cg_ofst;
00326 int x = 89;
00327 int y = 14;
00328 int xb = 2;
00329
00330 uint i = 0;
00331 for (CargoID c = 0; c < NUM_CARGO; c++) {
00332 const CargoSpec *cs = GetCargo(c);
00333 if (!cs->IsValid()) continue;
00334
00335 cg_ofst = HasBit(this->cargo_filter, c) ? 2 : 1;
00336 GfxFillRect(x + cg_ofst, y + cg_ofst, x + cg_ofst + 10 , y + cg_ofst + 7, cs->rating_colour);
00337 DrawStringCentered(x + 6 + cg_ofst, y + cg_ofst, cs->abbrev, TC_BLACK);
00338 x += 14;
00339 i++;
00340 }
00341
00342 x += 6;
00343 cg_ofst = this->IsWidgetLowered(SLW_NOCARGOWAITING) ? 2 : 1;
00344 DrawStringCentered(x + cg_ofst, y + cg_ofst, STR_ABBREV_NONE, TC_BLACK);
00345 x += 14;
00346 cg_ofst = this->IsWidgetLowered(SLW_CARGOALL) ? 2 : 1;
00347 DrawStringCentered(x + cg_ofst, y + cg_ofst, STR_ABBREV_ALL, TC_BLACK);
00348
00349 cg_ofst = this->IsWidgetLowered(SLW_FACILALL) ? 2 : 1;
00350 DrawString(71 + cg_ofst, y + cg_ofst, STR_ABBREV_ALL, TC_BLACK);
00351
00352 if (this->vscroll.count == 0) {
00353 DrawString(xb, 40, STR_304A_NONE, TC_FROMSTRING);
00354 return;
00355 }
00356
00357 int max = min(this->vscroll.pos + this->vscroll.cap, this->stations.Length());
00358 y = 40;
00359
00360 for (int i = this->vscroll.pos; i < max; ++i) {
00361 const Station *st = this->stations[i];
00362 int x;
00363
00364 assert(st->xy != INVALID_TILE);
00365
00366
00367
00368 assert(st->owner == owner || (st->owner == OWNER_NONE && !st->IsBuoy()));
00369
00370 SetDParam(0, st->index);
00371 SetDParam(1, st->facilities);
00372 x = DrawString(xb, y, STR_3049_0, TC_FROMSTRING) + 5;
00373
00374
00375 for (CargoID j = 0; j < NUM_CARGO; j++) {
00376 if (!st->goods[j].cargo.Empty()) {
00377 StationsWndShowStationRating(x, y, j, st->goods[j].cargo.Count(), st->goods[j].rating);
00378 x += 20;
00379 }
00380 }
00381 y += 10;
00382 }
00383 }
00384
00385 virtual void OnClick(Point pt, int widget)
00386 {
00387 switch (widget) {
00388 case SLW_LIST: {
00389 uint32 id_v = (pt.y - 41) / 10;
00390
00391 if (id_v >= this->vscroll.cap) return;
00392
00393 id_v += this->vscroll.pos;
00394
00395 if (id_v >= this->stations.Length()) return;
00396
00397 const Station *st = this->stations[id_v];
00398
00399 assert(st->owner == (Owner)this->window_number || (st->owner == OWNER_NONE && !st->IsBuoy()));
00400
00401 if (_ctrl_pressed) {
00402 ShowExtraViewPortWindow(st->xy);
00403 } else {
00404 ScrollMainWindowToTile(st->xy);
00405 }
00406 break;
00407 }
00408
00409 case SLW_TRAIN:
00410 case SLW_TRUCK:
00411 case SLW_BUS:
00412 case SLW_AIRPLANE:
00413 case SLW_SHIP:
00414 if (_ctrl_pressed) {
00415 ToggleBit(this->facilities, widget - SLW_TRAIN);
00416 this->ToggleWidgetLoweredState(widget);
00417 } else {
00418 uint i;
00419 FOR_EACH_SET_BIT(i, this->facilities) {
00420 this->RaiseWidget(i + SLW_TRAIN);
00421 }
00422 SetBit(this->facilities, widget - SLW_TRAIN);
00423 this->LowerWidget(widget);
00424 }
00425 this->SetWidgetLoweredState(SLW_FACILALL, this->facilities == (FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK));
00426 this->stations.ForceRebuild();
00427 this->SetDirty();
00428 break;
00429
00430 case SLW_FACILALL:
00431 for (uint i = 0; i < 5; i++) {
00432 this->LowerWidget(i + SLW_TRAIN);
00433 }
00434 this->LowerWidget(SLW_FACILALL);
00435
00436 this->facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
00437 this->stations.ForceRebuild();
00438 this->SetDirty();
00439 break;
00440
00441 case SLW_CARGOALL: {
00442 uint i = 0;
00443 for (CargoID c = 0; c < NUM_CARGO; c++) {
00444 if (!GetCargo(c)->IsValid()) continue;
00445 this->LowerWidget(i + SLW_CARGOSTART);
00446 i++;
00447 }
00448 this->LowerWidget(SLW_NOCARGOWAITING);
00449 this->LowerWidget(SLW_CARGOALL);
00450
00451 this->cargo_filter = _cargo_mask;
00452 this->include_empty = true;
00453 this->stations.ForceRebuild();
00454 this->SetDirty();
00455 break;
00456 }
00457
00458 case SLW_SORTBY:
00459 this->stations.ToggleSortOrder();
00460 this->flags4 |= WF_TIMEOUT_BEGIN;
00461 this->LowerWidget(SLW_SORTBY);
00462 this->SetDirty();
00463 break;
00464
00465 case SLW_SORTDROPBTN:
00466 ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), SLW_SORTDROPBTN, 0, 0);
00467 break;
00468
00469 case SLW_NOCARGOWAITING:
00470 if (_ctrl_pressed) {
00471 this->include_empty = !this->include_empty;
00472 this->ToggleWidgetLoweredState(SLW_NOCARGOWAITING);
00473 } else {
00474 for (uint i = SLW_CARGOSTART; i < this->widget_count; i++) {
00475 this->RaiseWidget(i);
00476 }
00477
00478 this->cargo_filter = 0;
00479 this->include_empty = true;
00480
00481 this->LowerWidget(SLW_NOCARGOWAITING);
00482 }
00483 this->SetWidgetLoweredState(SLW_CARGOALL, this->cargo_filter == _cargo_mask && this->include_empty);
00484 this->stations.ForceRebuild();
00485 this->SetDirty();
00486 break;
00487
00488 default:
00489 if (widget >= SLW_CARGOSTART) {
00490
00491 CargoID c;
00492 int i = 0;
00493 for (c = 0; c < NUM_CARGO; c++) {
00494 if (!GetCargo(c)->IsValid()) continue;
00495 if (widget - SLW_CARGOSTART == i) break;
00496 i++;
00497 }
00498
00499 if (_ctrl_pressed) {
00500 ToggleBit(this->cargo_filter, c);
00501 this->ToggleWidgetLoweredState(widget);
00502 } else {
00503 for (uint i = SLW_CARGOSTART; i < this->widget_count; i++) {
00504 this->RaiseWidget(i);
00505 }
00506 this->RaiseWidget(SLW_NOCARGOWAITING);
00507
00508 this->cargo_filter = 0;
00509 this->include_empty = false;
00510
00511 SetBit(this->cargo_filter, c);
00512 this->LowerWidget(widget);
00513 }
00514 this->SetWidgetLoweredState(SLW_CARGOALL, this->cargo_filter == _cargo_mask && this->include_empty);
00515 this->stations.ForceRebuild();
00516 this->SetDirty();
00517 }
00518 break;
00519 }
00520 }
00521
00522 virtual void OnDropdownSelect(int widget, int index)
00523 {
00524 if (this->stations.SortType() != index) {
00525 this->stations.SetSortType(index);
00526
00527
00528 this->widget[SLW_SORTDROPBTN].data = this->sorter_names[this->stations.SortType()];
00529
00530 this->SetDirty();
00531 }
00532 }
00533
00534 virtual void OnTick()
00535 {
00536 if (_pause_game != 0) return;
00537 if (this->stations.NeedResort()) {
00538 DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number);
00539 this->SetDirty();
00540 }
00541 }
00542
00543 virtual void OnTimeout()
00544 {
00545 this->RaiseWidget(SLW_SORTBY);
00546 this->SetDirty();
00547 }
00548
00549 virtual void OnResize(Point new_size, Point delta)
00550 {
00551 this->vscroll.cap += delta.y / 10;
00552 }
00553
00554 virtual void OnInvalidateData(int data)
00555 {
00556 if (data == 0) {
00557 this->stations.ForceRebuild();
00558 } else {
00559 this->stations.ForceResort();
00560 }
00561 }
00562 };
00563
00564 Listing CompanyStationsWindow::last_sorting = {false, 0};
00565 byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
00566 bool CompanyStationsWindow::include_empty = true;
00567 const uint32 CompanyStationsWindow::cargo_filter_max = UINT32_MAX;
00568 uint32 CompanyStationsWindow::cargo_filter = UINT32_MAX;
00569 const Station *CompanyStationsWindow::last_station = NULL;
00570
00571
00572 GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = {
00573 &StationNameSorter,
00574 &StationTypeSorter,
00575 &StationWaitingSorter,
00576 &StationRatingMaxSorter
00577 };
00578
00579
00580 const StringID CompanyStationsWindow::sorter_names[] = {
00581 STR_SORT_BY_DROPDOWN_NAME,
00582 STR_SORT_BY_FACILITY,
00583 STR_SORT_BY_WAITING,
00584 STR_SORT_BY_RATING_MAX,
00585 INVALID_STRING_ID
00586 };
00587
00588
00589 static const Widget _company_stations_widgets[] = {
00590 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00591 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_GREY, 11, 345, 0, 13, STR_3048_STATIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
00592 { WWT_STICKYBOX, RESIZE_LR, COLOUR_GREY, 346, 357, 0, 13, 0x0, STR_STICKY_BUTTON},
00593 { WWT_PANEL, RESIZE_RB, COLOUR_GREY, 0, 345, 37, 161, 0x0, STR_3057_STATION_NAMES_CLICK_ON},
00594 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_GREY, 346, 357, 37, 149, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00595 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_GREY, 346, 357, 150, 161, 0x0, STR_RESIZE_BUTTON},
00596
00597 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 0, 13, 14, 24, STR_TRAIN, STR_USE_CTRL_TO_SELECT_MORE},
00598 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 14, 27, 14, 24, STR_LORRY, STR_USE_CTRL_TO_SELECT_MORE},
00599 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 28, 41, 14, 24, STR_BUS, STR_USE_CTRL_TO_SELECT_MORE},
00600 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 42, 55, 14, 24, STR_PLANE, STR_USE_CTRL_TO_SELECT_MORE},
00601 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 56, 69, 14, 24, STR_SHIP, STR_USE_CTRL_TO_SELECT_MORE},
00602 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 70, 83, 14, 24, 0x0, STR_SELECT_ALL_FACILITIES},
00603
00604 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 83, 88, 14, 24, 0x0, STR_NULL},
00605 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 89, 102, 14, 24, 0x0, STR_NO_WAITING_CARGO},
00606 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 103, 116, 14, 24, 0x0, STR_SELECT_ALL_TYPES},
00607 { WWT_PANEL, RESIZE_RIGHT, COLOUR_GREY, 117, 357, 14, 24, 0x0, STR_NULL},
00608
00609 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 0, 80, 25, 36, STR_SORT_BY, STR_SORT_ORDER_TIP},
00610 { WWT_DROPDOWN, RESIZE_NONE, COLOUR_GREY, 81, 243, 25, 36, 0x0, STR_SORT_CRITERIA_TIP},
00611 { WWT_PANEL, RESIZE_RIGHT, COLOUR_GREY, 244, 357, 25, 36, 0x0, STR_NULL},
00612 { WIDGETS_END},
00613 };
00614
00615 static const WindowDesc _company_stations_desc(
00616 WDP_AUTO, WDP_AUTO, 358, 162, 358, 162,
00617 WC_STATION_LIST, WC_NONE,
00618 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00619 _company_stations_widgets
00620 );
00621
00627 void ShowCompanyStations(CompanyID company)
00628 {
00629 if (!IsValidCompanyID(company)) return;
00630
00631 AllocateWindowDescFront<CompanyStationsWindow>(&_company_stations_desc, company);
00632 }
00633
00634 static const Widget _station_view_widgets[] = {
00635 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00636 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_GREY, 11, 236, 0, 13, STR_300A_0, STR_018C_WINDOW_TITLE_DRAG_THIS},
00637 { WWT_STICKYBOX, RESIZE_LR, COLOUR_GREY, 237, 248, 0, 13, 0x0, STR_STICKY_BUTTON},
00638 { WWT_PANEL, RESIZE_RB, COLOUR_GREY, 0, 236, 14, 65, 0x0, STR_NULL},
00639 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_GREY, 237, 248, 14, 65, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00640 { WWT_PANEL, RESIZE_RTB, COLOUR_GREY, 0, 248, 66, 97, 0x0, STR_NULL},
00641 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_GREY, 0, 59, 98, 109, STR_00E4_LOCATION, STR_3053_CENTER_MAIN_VIEW_ON_STATION},
00642 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_GREY, 60, 120, 98, 109, STR_3032_RATINGS, STR_3054_SHOW_STATION_RATINGS},
00643 { WWT_PUSHTXTBTN, RESIZE_RTB, COLOUR_GREY, 121, 180, 98, 109, STR_0130_RENAME, STR_3055_CHANGE_NAME_OF_STATION},
00644 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_GREY, 181, 194, 98, 109, STR_TRAIN, STR_SCHEDULED_TRAINS_TIP },
00645 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_GREY, 195, 208, 98, 109, STR_LORRY, STR_SCHEDULED_ROAD_VEHICLES_TIP },
00646 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_GREY, 209, 222, 98, 109, STR_PLANE, STR_SCHEDULED_AIRCRAFT_TIP },
00647 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_GREY, 223, 236, 98, 109, STR_SHIP, STR_SCHEDULED_SHIPS_TIP },
00648 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_GREY, 237, 248, 98, 109, 0x0, STR_RESIZE_BUTTON},
00649 { WIDGETS_END},
00650 };
00651
00652 SpriteID GetCargoSprite(CargoID i)
00653 {
00654 const CargoSpec *cs = GetCargo(i);
00655 SpriteID sprite;
00656
00657 if (cs->sprite == 0xFFFF) {
00658
00659 sprite = GetCustomCargoSprite(cs);
00660 } else {
00661 sprite = cs->sprite;
00662 }
00663
00664 if (sprite == 0) sprite = SPR_CARGO_GOODS;
00665
00666 return sprite;
00667 }
00668
00677 static void DrawCargoIcons(CargoID i, uint waiting, int x, int y, uint width)
00678 {
00679 uint num = min((waiting + 5) / 10, width / 10);
00680 if (num == 0) return;
00681
00682 SpriteID sprite = GetCargoSprite(i);
00683
00684 do {
00685 DrawSprite(sprite, PAL_NONE, x, y);
00686 x += 10;
00687 } while (--num);
00688 }
00689
00690 struct CargoData {
00691 CargoID cargo;
00692 StationID source;
00693 uint count;
00694
00695 CargoData(CargoID cargo, StationID source, uint count) :
00696 cargo(cargo),
00697 source(source),
00698 count(count)
00699 { }
00700 };
00701
00702 typedef std::list<CargoData> CargoDataList;
00703
00707 struct StationViewWindow : public Window {
00708 uint32 cargo;
00709 uint16 cargo_rows[NUM_CARGO];
00710
00711 StationViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
00712 {
00713 Owner owner = GetStation(window_number)->owner;
00714 if (owner != OWNER_NONE) this->owner = owner;
00715 this->vscroll.cap = 5;
00716 this->resize.step_height = 10;
00717
00718 this->FindWindowPlacementAndResize(desc);
00719 }
00720
00721 ~StationViewWindow()
00722 {
00723 WindowNumber wno =
00724 (this->window_number << 16) | VLW_STATION_LIST | GetStation(this->window_number)->owner;
00725
00726 DeleteWindowById(WC_TRAINS_LIST, wno | (VEH_TRAIN << 11), false);
00727 DeleteWindowById(WC_ROADVEH_LIST, wno | (VEH_ROAD << 11), false);
00728 DeleteWindowById(WC_SHIPS_LIST, wno | (VEH_SHIP << 11), false);
00729 DeleteWindowById(WC_AIRCRAFT_LIST, wno | (VEH_AIRCRAFT << 11), false);
00730 }
00731
00732 virtual void OnPaint()
00733 {
00734 StationID station_id = this->window_number;
00735 const Station *st = GetStation(station_id);
00736 CargoDataList cargolist;
00737 uint32 transfers = 0;
00738
00739
00740 for (CargoID i = 0; i < NUM_CARGO; i++) {
00741 if (st->goods[i].cargo.Empty()) {
00742 this->cargo_rows[i] = 0;
00743 } else {
00744
00745 cargolist.push_back(CargoData(i, INVALID_STATION, st->goods[i].cargo.Count()));
00746
00747
00748 this->cargo_rows[i] = (uint16)cargolist.size();
00749
00750
00751 const CargoList::List *packets = st->goods[i].cargo.Packets();
00752 for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
00753 const CargoPacket *cp = *it;
00754 if (cp->source != station_id) {
00755 bool added = false;
00756
00757
00758 SetBit(transfers, i);
00759
00760
00761 if (!HasBit(this->cargo, i)) break;
00762
00763
00764 for (CargoDataList::iterator jt = cargolist.begin(); jt != cargolist.end(); jt++) {
00765 CargoData *cd = &(*jt);
00766 if (cd->cargo == i && cd->source == cp->source) {
00767 cd->count += cp->count;
00768 added = true;
00769 break;
00770 }
00771 }
00772
00773 if (!added) cargolist.push_back(CargoData(i, cp->source, cp->count));
00774 }
00775 }
00776 }
00777 }
00778 SetVScrollCount(this, (int)cargolist.size() + 1);
00779
00780
00781 this->SetWidgetDisabledState(SVW_RENAME, st->owner != _local_company);
00782 this->SetWidgetDisabledState(SVW_TRAINS, !(st->facilities & FACIL_TRAIN));
00783 this->SetWidgetDisabledState(SVW_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP));
00784 this->SetWidgetDisabledState(SVW_PLANES, !(st->facilities & FACIL_AIRPORT));
00785 this->SetWidgetDisabledState(SVW_SHIPS, !(st->facilities & FACIL_DOCK));
00786
00787 SetDParam(0, st->index);
00788 SetDParam(1, st->facilities);
00789 this->DrawWidgets();
00790
00791 int x = 2;
00792 int y = 15;
00793 int pos = this->vscroll.pos;
00794
00795 uint width = this->widget[SVW_WAITING].right - this->widget[SVW_WAITING].left - 4;
00796 int maxrows = this->vscroll.cap;
00797
00798 StringID str;
00799
00800 if (--pos < 0) {
00801 str = STR_00D0_NOTHING;
00802 for (CargoID i = 0; i < NUM_CARGO; i++) {
00803 if (!st->goods[i].cargo.Empty()) str = STR_EMPTY;
00804 }
00805 SetDParam(0, str);
00806 DrawString(x, y, STR_0008_WAITING, TC_FROMSTRING);
00807 y += 10;
00808 }
00809
00810 for (CargoDataList::const_iterator it = cargolist.begin(); it != cargolist.end() && pos > -maxrows; ++it) {
00811 if (--pos < 0) {
00812 const CargoData *cd = &(*it);
00813 if (cd->source == INVALID_STATION) {
00814
00815 DrawCargoIcons(cd->cargo, cd->count, x, y, width);
00816 SetDParam(0, cd->cargo);
00817 SetDParam(1, cd->count);
00818 if (HasBit(transfers, cd->cargo)) {
00819
00820 const char *sym = HasBit(this->cargo, cd->cargo) ? "-" : "+";
00821 DrawStringRightAligned(x + width - 8, y, STR_0009, TC_FROMSTRING);
00822 DoDrawString(sym, x + width - 6, y, TC_YELLOW);
00823 } else {
00824 DrawStringRightAligned(x + width, y, STR_0009, TC_FROMSTRING);
00825 }
00826 } else {
00827 SetDParam(0, cd->cargo);
00828 SetDParam(1, cd->count);
00829 SetDParam(2, cd->source);
00830 DrawStringRightAlignedTruncated(x + width, y, STR_EN_ROUTE_FROM, TC_FROMSTRING, width);
00831 }
00832
00833 y += 10;
00834 }
00835 }
00836
00837 if (this->widget[SVW_ACCEPTS].data == STR_3032_RATINGS) {
00838 char string[512];
00839 char *b = string;
00840 bool first = true;
00841
00842 b = InlineString(b, STR_000C_ACCEPTS);
00843
00844 for (CargoID i = 0; i < NUM_CARGO; i++) {
00845 if (b >= lastof(string) - (1 + 2 * 4)) break;
00846 if (HasBit(st->goods[i].acceptance_pickup, GoodsEntry::ACCEPTANCE)) {
00847 if (first) {
00848 first = false;
00849 } else {
00850
00851 *b++ = ',';
00852 *b++ = ' ';
00853 }
00854 b = InlineString(b, GetCargo(i)->name);
00855 }
00856 }
00857
00858
00859 if (first) b = InlineString(b, STR_00D0_NOTHING);
00860
00861 *b = '\0';
00862
00863
00864 assert(b < endof(string));
00865
00866 SetDParamStr(0, string);
00867 DrawStringMultiLine(2, this->widget[SVW_ACCEPTLIST].top + 1, STR_JUST_RAW_STRING, this->widget[SVW_ACCEPTLIST].right - this->widget[SVW_ACCEPTLIST].left);
00868 } else {
00869 y = this->widget[SVW_RATINGLIST].top + 1;
00870
00871 DrawString(2, y, STR_3034_LOCAL_RATING_OF_TRANSPORT, TC_FROMSTRING);
00872 y += 10;
00873
00874 for (CargoID i = 0; i < NUM_CARGO; i++) {
00875 const CargoSpec *cs = GetCargo(i);
00876 if (!cs->IsValid()) continue;
00877
00878 const GoodsEntry *ge = &st->goods[i];
00879 if (!HasBit(ge->acceptance_pickup, GoodsEntry::PICKUP)) continue;
00880
00881 SetDParam(0, cs->name);
00882 SetDParam(2, ge->rating * 101 >> 8);
00883 SetDParam(1, STR_3035_APPALLING + (ge->rating >> 5));
00884 DrawString(8, y, STR_303D, TC_FROMSTRING);
00885 y += 10;
00886 }
00887 }
00888 }
00889
00890 void HandleCargoWaitingClick(int row)
00891 {
00892 if (row == 0) return;
00893
00894 for (CargoID c = 0; c < NUM_CARGO; c++) {
00895 if (this->cargo_rows[c] == row) {
00896 ToggleBit(this->cargo, c);
00897 this->InvalidateWidget(SVW_WAITING);
00898 break;
00899 }
00900 }
00901 }
00902
00903 virtual void OnClick(Point pt, int widget)
00904 {
00905 switch (widget) {
00906 case SVW_WAITING:
00907 this->HandleCargoWaitingClick((pt.y - this->widget[SVW_WAITING].top) / 10 + this->vscroll.pos);
00908 break;
00909
00910 case SVW_LOCATION:
00911 if (_ctrl_pressed) {
00912 ShowExtraViewPortWindow(GetStation(this->window_number)->xy);
00913 } else {
00914 ScrollMainWindowToTile(GetStation(this->window_number)->xy);
00915 }
00916 break;
00917
00918 case SVW_RATINGS:
00919 this->SetDirty();
00920
00921 if (this->widget[SVW_RATINGS].data == STR_3032_RATINGS) {
00922
00923 this->widget[SVW_RATINGS].data = STR_3033_ACCEPTS;
00924 this->widget[SVW_RATINGS].tooltips = STR_3056_SHOW_LIST_OF_ACCEPTED_CARGO;
00925 ResizeWindowForWidget(this, SVW_ACCEPTLIST, 0, 100);
00926 } else {
00927
00928 this->widget[SVW_RATINGS].data = STR_3032_RATINGS;
00929 this->widget[SVW_RATINGS].tooltips = STR_3054_SHOW_STATION_RATINGS;
00930 ResizeWindowForWidget(this, SVW_ACCEPTLIST, 0, -100);
00931 }
00932
00933 this->SetDirty();
00934 break;
00935
00936 case SVW_RENAME:
00937 SetDParam(0, this->window_number);
00938 ShowQueryString(STR_STATION, STR_3030_RENAME_STATION_LOADING, MAX_LENGTH_STATION_NAME_BYTES, MAX_LENGTH_STATION_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
00939 break;
00940
00941 case SVW_TRAINS: {
00942 const Station *st = GetStation(this->window_number);
00943 ShowVehicleListWindow(st->owner, VEH_TRAIN, (StationID)this->window_number);
00944 break;
00945 }
00946
00947 case SVW_ROADVEHS: {
00948 const Station *st = GetStation(this->window_number);
00949 ShowVehicleListWindow(st->owner, VEH_ROAD, (StationID)this->window_number);
00950 break;
00951 }
00952
00953 case SVW_PLANES: {
00954 const Station *st = GetStation(this->window_number);
00955
00956 Owner owner = (st->owner == OWNER_NONE) ? _local_company : st->owner;
00957 ShowVehicleListWindow(owner, VEH_AIRCRAFT, (StationID)this->window_number);
00958 break;
00959 }
00960
00961 case SVW_SHIPS: {
00962 const Station *st = GetStation(this->window_number);
00963
00964 Owner owner = (st->owner == OWNER_NONE) ? _local_company : st->owner;
00965 ShowVehicleListWindow(owner, VEH_SHIP, (StationID)this->window_number);
00966 break;
00967 }
00968 }
00969 }
00970
00971 virtual void OnQueryTextFinished(char *str)
00972 {
00973 if (str == NULL) return;
00974
00975 DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_3031_CAN_T_RENAME_STATION), NULL, str);
00976 }
00977
00978 virtual void OnResize(Point new_size, Point delta)
00979 {
00980 if (delta.x != 0) ResizeButtons(this, SVW_LOCATION, SVW_RENAME);
00981 this->vscroll.cap += delta.y / (int)this->resize.step_height;
00982 }
00983 };
00984
00985
00986 static const WindowDesc _station_view_desc(
00987 WDP_AUTO, WDP_AUTO, 249, 110, 249, 110,
00988 WC_STATION_VIEW, WC_NONE,
00989 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00990 _station_view_widgets
00991 );
00992
00998 void ShowStationViewWindow(StationID station)
00999 {
01000 AllocateWindowDescFront<StationViewWindow>(&_station_view_desc, station);
01001 }
01002
01004 struct TileAndStation {
01005 TileIndex tile;
01006 StationID station;
01007 };
01008
01009 static SmallVector<TileAndStation, 8> _deleted_stations_nearby;
01010 static SmallVector<StationID, 8> _stations_nearby_list;
01011
01013 struct FindNearbyStationContext {
01014 TileIndex tile;
01015 uint w;
01016 uint h;
01017 };
01018
01025 static bool AddNearbyStation(TileIndex tile, void *user_data)
01026 {
01027 FindNearbyStationContext *ctx = (FindNearbyStationContext *)user_data;
01028
01029
01030 for (uint i = 0; i < _deleted_stations_nearby.Length(); i++) {
01031 TileAndStation *ts = _deleted_stations_nearby.Get(i);
01032 if (ts->tile == tile) {
01033 *_stations_nearby_list.Append() = _deleted_stations_nearby[i].station;
01034 _deleted_stations_nearby.Erase(ts);
01035 i--;
01036 }
01037 }
01038
01039
01040 if (!IsTileType(tile, MP_STATION)) return false;
01041
01042 StationID sid = GetStationIndex(tile);
01043 Station *st = GetStation(sid);
01044 if (st->owner != _local_company || _stations_nearby_list.Contains(sid)) return false;
01045
01046 if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST)) {
01047 *_stations_nearby_list.Append() = sid;
01048 }
01049
01050 return false;
01051 }
01052
01063 static const Station *FindStationsNearby(TileIndex tile, int w, int h, bool distant_join)
01064 {
01065 FindNearbyStationContext ctx;
01066 ctx.tile = tile;
01067 ctx.w = w;
01068 ctx.h = h;
01069
01070 _stations_nearby_list.Clear();
01071 _deleted_stations_nearby.Clear();
01072
01073
01074 BEGIN_TILE_LOOP(t, w, h, tile)
01075 if (t < MapSize() && IsTileType(t, MP_STATION)) return GetStationByTile(t);
01076 END_TILE_LOOP(t, w, h, tile)
01077
01078
01079 const Station *st;
01080 FOR_ALL_STATIONS(st) {
01081 if (st->facilities == 0 && st->owner == _local_company) {
01082
01083 if (max(DistanceMax(tile, st->xy), DistanceMax(TILE_ADDXY(tile, w - 1, h - 1), st->xy)) < _settings_game.station.station_spread) {
01084 TileAndStation *ts = _deleted_stations_nearby.Append();
01085 ts->tile = st->xy;
01086 ts->station = st->index;
01087
01088
01089 if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
01090 IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
01091 AddNearbyStation(st->xy, &ctx);
01092 }
01093 }
01094 }
01095 }
01096
01097
01098
01099
01100 if (distant_join && min(w, h) >= _settings_game.station.station_spread) return NULL;
01101 uint max_dist = distant_join ? _settings_game.station.station_spread - min(w, h) : 1;
01102
01103 tile = TILE_ADD(ctx.tile, TileOffsByDir(DIR_N));
01104 CircularTileSearch(&tile, max_dist, w, h, AddNearbyStation, &ctx);
01105
01106 return NULL;
01107 }
01108
01109 enum JoinStationWidgets {
01110 JSW_WIDGET_CLOSEBOX = 0,
01111 JSW_WIDGET_CAPTION,
01112 JSW_PANEL,
01113 JSW_SCROLLBAR,
01114 JSW_EMPTY,
01115 JSW_RESIZEBOX,
01116 };
01117
01118 static const Widget _select_station_widgets[] = {
01119 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01120 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_DARK_GREEN, 11, 199, 0, 13, STR_SELECT_STATION_TO_JOIN, STR_018C_WINDOW_TITLE_DRAG_THIS},
01121 { WWT_PANEL, RESIZE_RB, COLOUR_DARK_GREEN, 0, 187, 14, 79, 0x0, STR_NULL},
01122 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_DARK_GREEN, 188, 199, 14, 79, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
01123 { WWT_PANEL, RESIZE_RTB, COLOUR_DARK_GREEN, 0, 187, 80, 91, 0x0, STR_NULL},
01124 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_DARK_GREEN, 188, 199, 80, 91, 0x0, STR_RESIZE_BUTTON},
01125 { WIDGETS_END},
01126 };
01127
01128 struct SelectStationWindow : Window {
01129 CommandContainer select_station_cmd;
01130 TileIndex tile;
01131 int size_x;
01132 int size_y;
01133
01134 SelectStationWindow(const WindowDesc *desc, CommandContainer cmd, int w, int h) :
01135 Window(desc, 0),
01136 select_station_cmd(cmd),
01137 tile(cmd.tile),
01138 size_x(w),
01139 size_y(h)
01140 {
01141 this->vscroll.cap = 6;
01142 this->resize.step_height = 10;
01143
01144 FindStationsNearby(this->tile, this->size_x, this->size_y, true);
01145
01146 this->FindWindowPlacementAndResize(desc);
01147 }
01148
01149 virtual void OnPaint()
01150 {
01151 SetVScrollCount(this, _stations_nearby_list.Length() + 1);
01152
01153 this->DrawWidgets();
01154
01155 uint y = 17;
01156 if (this->vscroll.pos == 0) {
01157 DrawStringTruncated(3, y, STR_CREATE_SPLITTED_STATION, TC_FROMSTRING, this->widget[JSW_PANEL].right - 5);
01158 y += 10;
01159 }
01160
01161 for (uint i = max<uint>(1, this->vscroll.pos); i <= _stations_nearby_list.Length(); ++i, y += 10) {
01162
01163 if (i - this->vscroll.pos >= this->vscroll.cap) break;
01164
01165 const Station *st = GetStation(_stations_nearby_list[i - 1]);
01166 SetDParam(0, st->index);
01167 SetDParam(1, st->facilities);
01168 DrawStringTruncated(3, y, STR_3049_0, TC_FROMSTRING, this->widget[JSW_PANEL].right - 5);
01169 }
01170 }
01171
01172 virtual void OnClick(Point pt, int widget)
01173 {
01174 if (widget != JSW_PANEL) return;
01175
01176 uint32 st_index = (pt.y - 16) / 10 + this->vscroll.pos;
01177 bool distant_join = (st_index > 0);
01178 if (distant_join) st_index--;
01179
01180 if (distant_join && st_index >= _stations_nearby_list.Length()) return;
01181
01182
01183 SB(this->select_station_cmd.p2, 16, 16,
01184 (distant_join ? _stations_nearby_list[st_index] : NEW_STATION));
01185
01186
01187 DoCommandP(&this->select_station_cmd);
01188
01189
01190 DeleteWindowById(WC_SELECT_STATION, 0);
01191 }
01192
01193 virtual void OnTick()
01194 {
01195 if (_thd.dirty & 2) {
01196 _thd.dirty &= ~2;
01197 this->SetDirty();
01198 }
01199 }
01200
01201 virtual void OnResize(Point new_size, Point delta)
01202 {
01203 this->vscroll.cap = (this->widget[JSW_PANEL].bottom - this->widget[JSW_PANEL].top) / 10;
01204 }
01205
01206 virtual void OnInvalidateData(int data)
01207 {
01208 FindStationsNearby(this->tile, this->size_x, this->size_y, true);
01209 this->SetDirty();
01210 }
01211 };
01212
01213 static const WindowDesc _select_station_desc(
01214 WDP_AUTO, WDP_AUTO, 200, 92, 200, 182,
01215 WC_SELECT_STATION, WC_NONE,
01216 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE | WDF_CONSTRUCTION,
01217 _select_station_widgets
01218 );
01219
01220
01228 static bool StationJoinerNeeded(CommandContainer cmd, int w, int h)
01229 {
01230
01231 if (!_settings_game.station.distant_join_stations) return false;
01232
01233
01234
01235 Window *selection_window = FindWindowById(WC_SELECT_STATION, 0);
01236 if (selection_window != NULL) {
01237 if (!_ctrl_pressed) return true;
01238
01239
01240 delete selection_window;
01241 UpdateTileSelection();
01242 }
01243
01244
01245 if (!_ctrl_pressed) return false;
01246
01247
01248 if (CmdFailed(DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))))) return false;
01249
01250
01251
01252
01253 const Station *st = FindStationsNearby(cmd.tile, w, h, false);
01254 return st == NULL && (_settings_game.station.adjacent_stations || _stations_nearby_list.Length() == 0);
01255 }
01256
01263 void ShowSelectStationIfNeeded(CommandContainer cmd, int w, int h)
01264 {
01265 if (StationJoinerNeeded(cmd, w, h)) {
01266 if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
01267 if (BringWindowToFrontById(WC_SELECT_STATION, 0)) return;
01268 new SelectStationWindow(&_select_station_desc, cmd, w, h);
01269 } else {
01270 DoCommandP(&cmd);
01271 }
01272 }