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
01003 static SmallVector<StationID, 8> _stations_nearby_list;
01004 static SmallMap<TileIndex, StationID, 8> _deleted_stations_nearby;
01005
01007 struct FindNearbyStationContext {
01008 TileIndex tile;
01009 uint w;
01010 uint h;
01011 };
01012
01019 static bool AddNearbyStation(TileIndex tile, void *user_data)
01020 {
01021 FindNearbyStationContext *ctx = (FindNearbyStationContext *)user_data;
01022
01023
01024 SmallPair<TileIndex, StationID> *dst = _deleted_stations_nearby.Find(tile);
01025 if (dst != _deleted_stations_nearby.End()) {
01026 _stations_nearby_list.Include(dst->second);
01027 return false;
01028 }
01029
01030
01031 if (!IsTileType(tile, MP_STATION)) return false;
01032
01033 StationID sid = GetStationIndex(tile);
01034 Station *st = GetStation(sid);
01035 if (st->owner != _local_company || _stations_nearby_list.Contains(sid)) return false;
01036
01037 if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST)) {
01038 *_stations_nearby_list.Append() = sid;
01039 }
01040
01041 return false;
01042 }
01043
01054 static const Station *FindStationsNearby(TileIndex tile, int w, int h, bool distant_join)
01055 {
01056 FindNearbyStationContext ctx;
01057 ctx.tile = tile;
01058 ctx.w = w;
01059 ctx.h = h;
01060
01061 _stations_nearby_list.Clear();
01062 _deleted_stations_nearby.Clear();
01063
01064
01065 BEGIN_TILE_LOOP(t, w, h, tile)
01066 if (t < MapSize() && IsTileType(t, MP_STATION)) return GetStationByTile(t);
01067 END_TILE_LOOP(t, w, h, tile)
01068
01069
01070 const Station *st;
01071 FOR_ALL_STATIONS(st) {
01072 if (st->facilities == 0 && st->owner == _local_company) {
01073
01074 if (max(DistanceMax(tile, st->xy), DistanceMax(TILE_ADDXY(tile, w - 1, h - 1), st->xy)) < _settings_game.station.station_spread) {
01075 _deleted_stations_nearby.Insert(st->xy, st->index);
01076
01077
01078 if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) &&
01079 IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) {
01080 AddNearbyStation(st->xy, &ctx);
01081 }
01082 }
01083 }
01084 }
01085
01086
01087
01088
01089 if (distant_join && min(w, h) >= _settings_game.station.station_spread) return NULL;
01090 uint max_dist = distant_join ? _settings_game.station.station_spread - min(w, h) : 1;
01091
01092 tile = TILE_ADD(ctx.tile, TileOffsByDir(DIR_N));
01093 CircularTileSearch(&tile, max_dist, w, h, AddNearbyStation, &ctx);
01094
01095 return NULL;
01096 }
01097
01098 enum JoinStationWidgets {
01099 JSW_WIDGET_CLOSEBOX = 0,
01100 JSW_WIDGET_CAPTION,
01101 JSW_PANEL,
01102 JSW_SCROLLBAR,
01103 JSW_EMPTY,
01104 JSW_RESIZEBOX,
01105 };
01106
01107 static const Widget _select_station_widgets[] = {
01108 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
01109 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_DARK_GREEN, 11, 199, 0, 13, STR_SELECT_STATION_TO_JOIN, STR_018C_WINDOW_TITLE_DRAG_THIS},
01110 { WWT_PANEL, RESIZE_RB, COLOUR_DARK_GREEN, 0, 187, 14, 79, 0x0, STR_NULL},
01111 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_DARK_GREEN, 188, 199, 14, 79, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
01112 { WWT_PANEL, RESIZE_RTB, COLOUR_DARK_GREEN, 0, 187, 80, 91, 0x0, STR_NULL},
01113 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_DARK_GREEN, 188, 199, 80, 91, 0x0, STR_RESIZE_BUTTON},
01114 { WIDGETS_END},
01115 };
01116
01117 struct SelectStationWindow : Window {
01118 CommandContainer select_station_cmd;
01119 TileIndex tile;
01120 int size_x;
01121 int size_y;
01122
01123 SelectStationWindow(const WindowDesc *desc, CommandContainer cmd, int w, int h) :
01124 Window(desc, 0),
01125 select_station_cmd(cmd),
01126 tile(cmd.tile),
01127 size_x(w),
01128 size_y(h)
01129 {
01130 this->vscroll.cap = 6;
01131 this->resize.step_height = 10;
01132
01133 FindStationsNearby(this->tile, this->size_x, this->size_y, true);
01134
01135 this->FindWindowPlacementAndResize(desc);
01136 }
01137
01138 virtual void OnPaint()
01139 {
01140 SetVScrollCount(this, _stations_nearby_list.Length() + 1);
01141
01142 this->DrawWidgets();
01143
01144 uint y = 17;
01145 if (this->vscroll.pos == 0) {
01146 DrawStringTruncated(3, y, STR_CREATE_SPLITTED_STATION, TC_FROMSTRING, this->widget[JSW_PANEL].right - 5);
01147 y += 10;
01148 }
01149
01150 for (uint i = max<uint>(1, this->vscroll.pos); i <= _stations_nearby_list.Length(); ++i, y += 10) {
01151
01152 if (i - this->vscroll.pos >= this->vscroll.cap) break;
01153
01154 const Station *st = GetStation(_stations_nearby_list[i - 1]);
01155 SetDParam(0, st->index);
01156 SetDParam(1, st->facilities);
01157 DrawStringTruncated(3, y, STR_3049_0, TC_FROMSTRING, this->widget[JSW_PANEL].right - 5);
01158 }
01159 }
01160
01161 virtual void OnClick(Point pt, int widget)
01162 {
01163 if (widget != JSW_PANEL) return;
01164
01165 uint32 st_index = (pt.y - 16) / 10 + this->vscroll.pos;
01166 bool distant_join = (st_index > 0);
01167 if (distant_join) st_index--;
01168
01169 if (distant_join && st_index >= _stations_nearby_list.Length()) return;
01170
01171
01172 SB(this->select_station_cmd.p2, 16, 16,
01173 (distant_join ? _stations_nearby_list[st_index] : INVALID_STATION));
01174
01175
01176 DoCommandP(&this->select_station_cmd);
01177
01178
01179 DeleteWindowById(WC_SELECT_STATION, 0);
01180 }
01181
01182 virtual void OnTick()
01183 {
01184 if (_thd.dirty & 2) {
01185 _thd.dirty &= ~2;
01186 this->SetDirty();
01187 }
01188 }
01189
01190 virtual void OnResize(Point new_size, Point delta)
01191 {
01192 this->vscroll.cap = (this->widget[JSW_PANEL].bottom - this->widget[JSW_PANEL].top) / 10;
01193 }
01194
01195 virtual void OnInvalidateData(int data)
01196 {
01197 FindStationsNearby(this->tile, this->size_x, this->size_y, true);
01198 this->SetDirty();
01199 }
01200 };
01201
01202 static const WindowDesc _select_station_desc = {
01203 WDP_AUTO, WDP_AUTO, 200, 92, 200, 182,
01204 WC_SELECT_STATION, WC_NONE,
01205 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE | WDF_CONSTRUCTION,
01206 _select_station_widgets,
01207 };
01208
01209
01217 static bool StationJoinerNeeded(CommandContainer cmd, int w, int h)
01218 {
01219
01220 if (!_settings_game.station.distant_join_stations) return false;
01221
01222
01223
01224 Window *selection_window = FindWindowById(WC_SELECT_STATION, 0);
01225 if (selection_window != NULL) {
01226 if (!_ctrl_pressed) return true;
01227
01228
01229 delete selection_window;
01230 UpdateTileSelection();
01231 }
01232
01233
01234 if (!_ctrl_pressed) return false;
01235
01236
01237 if (CmdFailed(DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))))) return false;
01238
01239
01240
01241
01242 const Station *st = FindStationsNearby(cmd.tile, w, h, false);
01243 return st == NULL && (_settings_game.station.adjacent_stations || _stations_nearby_list.Length() == 0);
01244 }
01245
01252 void ShowSelectStationIfNeeded(CommandContainer cmd, int w, int h)
01253 {
01254 if (StationJoinerNeeded(cmd, w, h)) {
01255 if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
01256 if (BringWindowToFrontById(WC_SELECT_STATION, 0)) return;
01257 new SelectStationWindow(&_select_station_desc, cmd, w, h);
01258 } else {
01259 DoCommandP(&cmd);
01260 }
01261 }