OpenTTD Source  20241108-master-g80f628063a
town_gui.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "town.h"
12 #include "viewport_func.h"
13 #include "error.h"
14 #include "gui.h"
15 #include "house.h"
16 #include "newgrf_house.h"
17 #include "picker_gui.h"
18 #include "command_func.h"
19 #include "company_func.h"
20 #include "company_base.h"
21 #include "company_gui.h"
22 #include "network/network.h"
23 #include "string_func.h"
24 #include "strings_func.h"
25 #include "sound_func.h"
26 #include "tilehighlight_func.h"
27 #include "sortlist_type.h"
28 #include "road_cmd.h"
29 #include "landscape.h"
30 #include "querystring_gui.h"
31 #include "window_func.h"
32 #include "townname_func.h"
33 #include "core/backup_type.hpp"
34 #include "core/geometry_func.hpp"
35 #include "genworld.h"
36 #include "fios.h"
37 #include "stringfilter_type.h"
38 #include "dropdown_func.h"
39 #include "town_kdtree.h"
40 #include "town_cmd.h"
41 #include "timer/timer.h"
43 #include "timer/timer_window.h"
44 #include "zoom_func.h"
45 #include "hotkeys.h"
46 
47 #include "widgets/town_widget.h"
48 
49 #include "table/strings.h"
50 
51 #include "safeguards.h"
52 
53 TownKdtree _town_local_authority_kdtree(&Kdtree_TownXYFunc);
54 
56 
57 static constexpr NWidgetPart _nested_town_authority_widgets[] = {
59  NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
60  NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TA_CAPTION), SetDataTip(STR_LOCAL_AUTHORITY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
61  NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TA_ZONE_BUTTON), SetMinimalSize(50, 0), SetDataTip(STR_LOCAL_AUTHORITY_ZONE, STR_LOCAL_AUTHORITY_ZONE_TOOLTIP),
62  NWidget(WWT_SHADEBOX, COLOUR_BROWN),
63  NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
64  NWidget(WWT_STICKYBOX, COLOUR_BROWN),
65  EndContainer(),
66  NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(),
67  NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(317, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), EndContainer(),
68  NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(),
70  NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TA_EXECUTE), SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP),
71  NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
72  EndContainer()
73 };
74 
77 private:
79  int sel_index;
83  StringID action_tooltips[TACT_COUNT];
84 
87 
96  int GetNthSetBit(int n)
97  {
98  if (n >= 0) {
99  for (uint i : SetBitIterator(this->enabled_actions)) {
100  n--;
101  if (n < 0) return i;
102  }
103  }
104  return -1;
105  }
106 
113  {
114  TownActions enabled = TACT_ALL;
115 
120 
121  return enabled;
122  }
123 
124 public:
126  {
127  this->town = Town::Get(window_number);
128  this->enabled_actions = GetEnabledActions();
129 
130  auto realtime = TimerGameEconomy::UsingWallclockUnits();
131  this->action_tooltips[0] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING;
132  this->action_tooltips[1] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING;
133  this->action_tooltips[2] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING;
134  this->action_tooltips[3] = realtime ? STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION_MINUTES : STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION_MONTHS;
135  this->action_tooltips[4] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY;
136  this->action_tooltips[5] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS;
137  this->action_tooltips[6] = realtime ? STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT_MINUTES : STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT_MONTHS;
138  this->action_tooltips[7] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE;
139 
140  this->InitNested(window_number);
141  }
142 
143  void OnInit() override
144  {
145  this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
146  this->exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT);
147  }
148 
149  void OnPaint() override
150  {
151  this->available_actions = GetMaskOfTownActions(_local_company, this->town);
152  if (this->available_actions != displayed_actions_on_previous_painting) this->SetDirty();
153  displayed_actions_on_previous_painting = this->available_actions;
154 
156  this->SetWidgetDisabledState(WID_TA_EXECUTE, (this->sel_index == -1) || !HasBit(this->available_actions, this->sel_index));
157 
158  this->DrawWidgets();
159  if (!this->IsShaded())
160  {
161  this->DrawRatings();
162  this->DrawActions();
163  }
164  }
165 
167  void DrawRatings()
168  {
169  Rect r = this->GetWidget<NWidgetBase>(WID_TA_RATING_INFO)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
170 
171  int text_y_offset = (this->resize.step_height - GetCharacterHeight(FS_NORMAL)) / 2;
172  int icon_y_offset = (this->resize.step_height - this->icon_size.height) / 2;
173  int exclusive_y_offset = (this->resize.step_height - this->exclusive_size.height) / 2;
174 
175  DrawString(r.left, r.right, r.top + text_y_offset, STR_LOCAL_AUTHORITY_COMPANY_RATINGS);
176  r.top += this->resize.step_height;
177 
178  bool rtl = _current_text_dir == TD_RTL;
179  Rect icon = r.WithWidth(this->icon_size.width, rtl);
180  Rect exclusive = r.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal, rtl).WithWidth(this->exclusive_size.width, rtl);
181  Rect text = r.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal + this->exclusive_size.width + WidgetDimensions::scaled.hsep_normal, rtl);
182 
183  /* Draw list of companies */
184  for (const Company *c : Company::Iterate()) {
185  if ((HasBit(this->town->have_ratings, c->index) || this->town->exclusivity == c->index)) {
186  DrawCompanyIcon(c->index, icon.left, text.top + icon_y_offset);
187 
188  SetDParam(0, c->index);
189  SetDParam(1, c->index);
190 
191  int rating = this->town->ratings[c->index];
192  StringID str = STR_CARGO_RATING_APPALLING;
193  if (rating > RATING_APPALLING) str++;
194  if (rating > RATING_VERYPOOR) str++;
195  if (rating > RATING_POOR) str++;
196  if (rating > RATING_MEDIOCRE) str++;
197  if (rating > RATING_GOOD) str++;
198  if (rating > RATING_VERYGOOD) str++;
199  if (rating > RATING_EXCELLENT) str++;
200 
201  SetDParam(2, str);
202  if (this->town->exclusivity == c->index) {
203  DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive.left, text.top + exclusive_y_offset);
204  }
205 
206  DrawString(text.left, text.right, text.top + text_y_offset, STR_LOCAL_AUTHORITY_COMPANY_RATING);
207  text.top += this->resize.step_height;
208  }
209  }
210 
211  text.bottom = text.top - 1;
212  if (text.bottom > r.bottom) {
213  /* If the company list is too big to fit, mark ourself dirty and draw again. */
214  ResizeWindow(this, 0, text.bottom - r.bottom, false);
215  }
216  }
217 
219  void DrawActions()
220  {
221  Rect r = this->GetWidget<NWidgetBase>(WID_TA_COMMAND_LIST)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
222 
223  DrawString(r, STR_LOCAL_AUTHORITY_ACTIONS_TITLE);
224  r.top += GetCharacterHeight(FS_NORMAL);
225 
226  /* Draw list of actions */
227  for (int i = 0; i < TACT_COUNT; i++) {
228  /* Don't show actions if disabled in settings. */
229  if (!HasBit(this->enabled_actions, i)) continue;
230 
231  /* Set colour of action based on ability to execute and if selected. */
232  TextColour action_colour = TC_GREY | TC_NO_SHADE;
233  if (HasBit(this->available_actions, i)) action_colour = TC_ORANGE;
234  if (this->sel_index == i) action_colour = TC_WHITE;
235 
236  DrawString(r, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, action_colour);
237  r.top += GetCharacterHeight(FS_NORMAL);
238  }
239  }
240 
241  void SetStringParameters(WidgetID widget) const override
242  {
243  if (widget == WID_TA_CAPTION) SetDParam(0, this->window_number);
244  }
245 
246  void DrawWidget(const Rect &r, WidgetID widget) const override
247  {
248  switch (widget) {
249  case WID_TA_ACTION_INFO:
250  if (this->sel_index != -1) {
251  Money action_cost = _price[PR_TOWN_ACTION] * _town_action_costs[this->sel_index] >> 8;
252  bool affordable = Company::IsValidID(_local_company) && action_cost < GetAvailableMoney(_local_company);
253 
254  SetDParam(0, action_cost);
256  this->action_tooltips[this->sel_index],
257  affordable ? TC_YELLOW : TC_RED);
258  }
259  break;
260  }
261  }
262 
263  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
264  {
265  switch (widget) {
266  case WID_TA_ACTION_INFO: {
267  assert(size.width > padding.width && size.height > padding.height);
268  Dimension d = {0, 0};
269  for (int i = 0; i < TACT_COUNT; i++) {
270  SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[i] >> 8);
271  d = maxdim(d, GetStringMultiLineBoundingBox(this->action_tooltips[i], size));
272  }
273  d.width += padding.width;
274  d.height += padding.height;
275  size = maxdim(size, d);
276  break;
277  }
278 
279  case WID_TA_COMMAND_LIST:
280  size.height = (TACT_COUNT + 1) * GetCharacterHeight(FS_NORMAL) + padding.height;
281  size.width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width;
282  for (uint i = 0; i < TACT_COUNT; i++ ) {
283  size.width = std::max(size.width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width + padding.width);
284  }
285  size.width += padding.width;
286  break;
287 
288  case WID_TA_RATING_INFO:
289  resize.height = std::max({this->icon_size.height + WidgetDimensions::scaled.vsep_normal, this->exclusive_size.height + WidgetDimensions::scaled.vsep_normal, (uint)GetCharacterHeight(FS_NORMAL)});
290  size.height = 9 * resize.height + padding.height;
291  break;
292  }
293  }
294 
295  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
296  {
297  switch (widget) {
298  case WID_TA_ZONE_BUTTON: {
299  bool new_show_state = !this->town->show_zone;
300  TownID index = this->town->index;
301 
302  new_show_state ? _town_local_authority_kdtree.Insert(index) : _town_local_authority_kdtree.Remove(index);
303 
304  this->town->show_zone = new_show_state;
305  this->SetWidgetLoweredState(widget, new_show_state);
307  break;
308  }
309 
310  case WID_TA_COMMAND_LIST: {
312 
313  y = GetNthSetBit(y);
314  if (y >= 0) {
315  this->sel_index = y;
316  this->SetDirty();
317  }
318 
319  /* When double-clicking, continue */
320  if (click_count == 1 || y < 0 || !HasBit(this->available_actions, y)) break;
321  [[fallthrough]];
322  }
323 
324  case WID_TA_EXECUTE:
325  Command<CMD_DO_TOWN_ACTION>::Post(STR_ERROR_CAN_T_DO_THIS, this->town->xy, this->window_number, this->sel_index);
326  break;
327  }
328  }
329 
331  IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
332  this->SetDirty();
333  }};
334 
335  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
336  {
337  if (!gui_scope) return;
338 
339  this->enabled_actions = this->GetEnabledActions();
340  if (!HasBit(this->enabled_actions, this->sel_index)) {
341  this->sel_index = -1;
342  }
343  }
344 };
345 
346 static WindowDesc _town_authority_desc(
347  WDP_AUTO, "view_town_authority", 317, 222,
349  0,
350  _nested_town_authority_widgets
351 );
352 
353 static void ShowTownAuthorityWindow(uint town)
354 {
355  AllocateWindowDescFront<TownAuthorityWindow>(_town_authority_desc, town);
356 }
357 
358 
359 /* Town view window. */
361 private:
363 
364 public:
365  static const int WID_TV_HEIGHT_NORMAL = 150;
366 
368  {
369  this->CreateNestedTree();
370 
371  this->town = Town::Get(window_number);
372  if (this->town->larger_town) this->GetWidget<NWidgetCore>(WID_TV_CAPTION)->widget_data = STR_TOWN_VIEW_CITY_CAPTION;
373 
374  this->FinishInitNested(window_number);
375 
376  this->flags |= WF_DISABLE_VP_SCROLL;
377  NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_TV_VIEWPORT);
378  nvp->InitializeViewport(this, this->town->xy, ScaleZoomGUI(ZOOM_LVL_TOWN));
379 
380  /* disable renaming town in network games if you are not the server */
382  }
383 
384  void Close([[maybe_unused]] int data = 0) override
385  {
387  this->Window::Close();
388  }
389 
390  void SetStringParameters(WidgetID widget) const override
391  {
392  if (widget == WID_TV_CAPTION) SetDParam(0, this->town->index);
393  }
394 
395  void OnPaint() override
396  {
397  extern const Town *_viewport_highlight_town;
398  this->SetWidgetLoweredState(WID_TV_CATCHMENT, _viewport_highlight_town == this->town);
399 
400  this->DrawWidgets();
401  }
402 
403  void DrawWidget(const Rect &r, WidgetID widget) const override
404  {
405  if (widget != WID_TV_INFO) return;
406 
407  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
408 
409  SetDParam(0, this->town->cache.population);
410  SetDParam(1, this->town->cache.num_houses);
411  DrawString(tr, STR_TOWN_VIEW_POPULATION_HOUSES);
412  tr.top += GetCharacterHeight(FS_NORMAL);
413 
414  StringID str_last_period = TimerGameEconomy::UsingWallclockUnits() ? STR_TOWN_VIEW_CARGO_LAST_MINUTE_MAX : STR_TOWN_VIEW_CARGO_LAST_MONTH_MAX;
415 
416  for (auto tpe : {TPE_PASSENGERS, TPE_MAIL}) {
417  for (const CargoSpec *cs : CargoSpec::town_production_cargoes[tpe]) {
418  CargoID cid = cs->Index();
419  SetDParam(0, 1ULL << cid);
420  SetDParam(1, this->town->supplied[cid].old_act);
421  SetDParam(2, this->town->supplied[cid].old_max);
422  DrawString(tr, str_last_period);
423  tr.top += GetCharacterHeight(FS_NORMAL);
424  }
425  }
426 
427  bool first = true;
428  for (int i = TAE_BEGIN; i < TAE_END; i++) {
429  if (this->town->goal[i] == 0) continue;
430  if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue;
431  if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue;
432 
433  if (first) {
434  DrawString(tr, STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH);
435  tr.top += GetCharacterHeight(FS_NORMAL);
436  first = false;
437  }
438 
439  bool rtl = _current_text_dir == TD_RTL;
440 
442  assert(cargo != nullptr);
443 
444  StringID string;
445 
446  if (this->town->goal[i] == TOWN_GROWTH_DESERT || this->town->goal[i] == TOWN_GROWTH_WINTER) {
447  /* For 'original' gameplay, don't show the amount required (you need 1 or more ..) */
448  string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL;
449  if (this->town->received[i].old_act == 0) {
450  string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL;
451 
452  if (this->town->goal[i] == TOWN_GROWTH_WINTER && TileHeight(this->town->xy) < GetSnowLine()) {
453  string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER;
454  }
455  }
456 
457  SetDParam(0, cargo->name);
458  } else {
459  string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED;
460  if (this->town->received[i].old_act < this->town->goal[i]) {
461  string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED;
462  }
463 
464  SetDParam(0, cargo->Index());
465  SetDParam(1, this->town->received[i].old_act);
466  SetDParam(2, cargo->Index());
467  SetDParam(3, this->town->goal[i]);
468  }
469  DrawString(tr.Indent(20, rtl), string);
470  tr.top += GetCharacterHeight(FS_NORMAL);
471  }
472 
473  if (HasBit(this->town->flags, TOWN_IS_GROWING)) {
474  SetDParam(0, RoundDivSU(this->town->growth_rate + 1, Ticks::DAY_TICKS));
475  DrawString(tr, this->town->fund_buildings_months == 0 ? STR_TOWN_VIEW_TOWN_GROWS_EVERY : STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED);
476  tr.top += GetCharacterHeight(FS_NORMAL);
477  } else {
478  DrawString(tr, STR_TOWN_VIEW_TOWN_GROW_STOPPED);
479  tr.top += GetCharacterHeight(FS_NORMAL);
480  }
481 
482  /* only show the town noise, if the noise option is activated. */
484  SetDParam(0, this->town->noise_reached);
485  SetDParam(1, this->town->MaxTownNoise());
486  DrawString(tr, STR_TOWN_VIEW_NOISE_IN_TOWN);
487  tr.top += GetCharacterHeight(FS_NORMAL);
488  }
489 
490  if (!this->town->text.empty()) {
491  SetDParamStr(0, this->town->text);
492  tr.top = DrawStringMultiLine(tr, STR_JUST_RAW_STRING, TC_BLACK);
493  }
494  }
495 
496  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
497  {
498  switch (widget) {
499  case WID_TV_CENTER_VIEW: // scroll to location
500  if (_ctrl_pressed) {
501  ShowExtraViewportWindow(this->town->xy);
502  } else {
503  ScrollMainWindowToTile(this->town->xy);
504  }
505  break;
506 
507  case WID_TV_SHOW_AUTHORITY: // town authority
508  ShowTownAuthorityWindow(this->window_number);
509  break;
510 
511  case WID_TV_CHANGE_NAME: // rename
512  SetDParam(0, this->window_number);
513  ShowQueryString(STR_TOWN_NAME, STR_TOWN_VIEW_RENAME_TOWN_BUTTON, MAX_LENGTH_TOWN_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
514  break;
515 
516  case WID_TV_CATCHMENT:
518  break;
519 
520  case WID_TV_EXPAND: { // expand town - only available on Scenario editor
521  Command<CMD_EXPAND_TOWN>::Post(STR_ERROR_CAN_T_EXPAND_TOWN, this->window_number, 0);
522  break;
523  }
524 
525  case WID_TV_DELETE: // delete town - only available on Scenario editor
526  Command<CMD_DELETE_TOWN>::Post(STR_ERROR_TOWN_CAN_T_DELETE, this->window_number);
527  break;
528  }
529  }
530 
531  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
532  {
533  switch (widget) {
534  case WID_TV_INFO:
535  size.height = GetDesiredInfoHeight(size.width) + padding.height;
536  break;
537  }
538  }
539 
544  uint GetDesiredInfoHeight(int width) const
545  {
547 
548  bool first = true;
549  for (int i = TAE_BEGIN; i < TAE_END; i++) {
550  if (this->town->goal[i] == 0) continue;
551  if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue;
552  if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue;
553 
554  if (first) {
555  aimed_height += GetCharacterHeight(FS_NORMAL);
556  first = false;
557  }
558  aimed_height += GetCharacterHeight(FS_NORMAL);
559  }
560  aimed_height += GetCharacterHeight(FS_NORMAL);
561 
563 
564  if (!this->town->text.empty()) {
565  SetDParamStr(0, this->town->text);
566  aimed_height += GetStringHeight(STR_JUST_RAW_STRING, width - WidgetDimensions::scaled.framerect.Horizontal());
567  }
568 
569  return aimed_height;
570  }
571 
572  void ResizeWindowAsNeeded()
573  {
574  const NWidgetBase *nwid_info = this->GetWidget<NWidgetBase>(WID_TV_INFO);
575  uint aimed_height = GetDesiredInfoHeight(nwid_info->current_x);
576  if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) {
577  this->ReInit();
578  }
579  }
580 
581  void OnResize() override
582  {
583  if (this->viewport != nullptr) {
584  NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_TV_VIEWPORT);
585  nvp->UpdateViewportCoordinates(this);
586 
587  ScrollWindowToTile(this->town->xy, this, true); // Re-center viewport.
588  }
589  }
590 
591  void OnMouseWheel(int wheel) override
592  {
594  DoZoomInOutWindow(wheel < 0 ? ZOOM_IN : ZOOM_OUT, this);
595  }
596  }
597 
603  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
604  {
605  if (!gui_scope) return;
606  /* Called when setting station noise or required cargoes have changed, in order to resize the window */
607  this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading
608  this->ResizeWindowAsNeeded();
609  }
610 
611  void OnQueryTextFinished(std::optional<std::string> str) override
612  {
613  if (!str.has_value()) return;
614 
615  Command<CMD_RENAME_TOWN>::Post(STR_ERROR_CAN_T_RENAME_TOWN, this->window_number, *str);
616  }
617 
618  IntervalTimer<TimerGameCalendar> daily_interval = {{TimerGameCalendar::DAY, TimerGameCalendar::Priority::NONE}, [this](auto) {
619  /* Refresh after possible snowline change */
620  this->SetDirty();
621  }};
622 };
623 
624 static constexpr NWidgetPart _nested_town_game_view_widgets[] = {
626  NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
627  NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetDataTip(SPR_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
628  NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
629  NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetDataTip(SPR_GOTO_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
630  NWidget(WWT_SHADEBOX, COLOUR_BROWN),
631  NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
632  NWidget(WWT_STICKYBOX, COLOUR_BROWN),
633  EndContainer(),
634  NWidget(WWT_PANEL, COLOUR_BROWN),
635  NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
636  NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetResize(1, 1),
637  EndContainer(),
638  EndContainer(),
639  NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
641  NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP),
642  NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(40, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
643  NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
644  EndContainer(),
645 };
646 
647 static WindowDesc _town_game_view_desc(
648  WDP_AUTO, "view_town", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL,
650  0,
651  _nested_town_game_view_widgets
652 );
653 
654 static constexpr NWidgetPart _nested_town_editor_view_widgets[] = {
656  NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
657  NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetDataTip(SPR_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
658  NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
659  NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetDataTip(SPR_GOTO_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
660  NWidget(WWT_SHADEBOX, COLOUR_BROWN),
661  NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
662  NWidget(WWT_STICKYBOX, COLOUR_BROWN),
663  EndContainer(),
664  NWidget(WWT_PANEL, COLOUR_BROWN),
665  NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
666  NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 1), SetResize(1, 1),
667  EndContainer(),
668  EndContainer(),
669  NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
671  NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP),
672  NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP),
673  NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(40, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
674  NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
675  EndContainer(),
676 };
677 
678 static WindowDesc _town_editor_view_desc(
679  WDP_AUTO, "view_town_scen", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL,
681  0,
682  _nested_town_editor_view_widgets
683 );
684 
685 void ShowTownViewWindow(TownID town)
686 {
687  if (_game_mode == GM_EDITOR) {
688  AllocateWindowDescFront<TownViewWindow>(_town_editor_view_desc, town);
689  } else {
690  AllocateWindowDescFront<TownViewWindow>(_town_game_view_desc, town);
691  }
692 }
693 
694 static constexpr NWidgetPart _nested_town_directory_widgets[] = {
696  NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
697  NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TD_CAPTION), SetDataTip(STR_TOWN_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
698  NWidget(WWT_SHADEBOX, COLOUR_BROWN),
699  NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
700  NWidget(WWT_STICKYBOX, COLOUR_BROWN),
701  EndContainer(),
705  NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
706  NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA),
707  NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_TD_FILTER), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
708  EndContainer(),
709  NWidget(WWT_PANEL, COLOUR_BROWN, WID_TD_LIST), SetDataTip(0x0, STR_TOWN_DIRECTORY_LIST_TOOLTIP),
711  NWidget(WWT_PANEL, COLOUR_BROWN),
712  NWidget(WWT_TEXT, COLOUR_BROWN, WID_TD_WORLD_POPULATION), SetPadding(2, 0, 2, 2), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TOWN_POPULATION, STR_NULL),
713  EndContainer(),
714  EndContainer(),
716  NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TD_SCROLLBAR),
717  NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
718  EndContainer(),
719  EndContainer(),
720 };
721 
725 };
726 
728 struct TownDirectoryWindow : public Window {
729 private:
730  /* Runtime saved values */
731  static Listing last_sorting;
732 
733  /* Constants for sorting towns */
734  static inline const StringID sorter_names[] = {
735  STR_SORT_BY_NAME,
736  STR_SORT_BY_POPULATION,
737  STR_SORT_BY_RATING,
738  };
739  static const std::initializer_list<GUITownList::SortFunction * const> sorter_funcs;
740 
743 
744  GUITownList towns{TownDirectoryWindow::last_sorting.order};
745 
746  Scrollbar *vscroll;
747 
748  void BuildSortTownList()
749  {
750  if (this->towns.NeedRebuild()) {
751  this->towns.clear();
752  this->towns.reserve(Town::GetNumItems());
753 
754  for (const Town *t : Town::Iterate()) {
755  if (this->string_filter.IsEmpty()) {
756  this->towns.push_back(t);
757  continue;
758  }
759  this->string_filter.ResetState();
760  this->string_filter.AddLine(t->GetCachedName());
761  if (this->string_filter.GetState()) this->towns.push_back(t);
762  }
763 
764  this->towns.RebuildDone();
765  this->vscroll->SetCount(this->towns.size()); // Update scrollbar as well.
766  }
767  /* Always sort the towns. */
768  this->towns.Sort();
769  this->SetWidgetDirty(WID_TD_LIST); // Force repaint of the displayed towns.
770  }
771 
773  static bool TownNameSorter(const Town * const &a, const Town * const &b, const bool &)
774  {
775  return StrNaturalCompare(a->GetCachedName(), b->GetCachedName()) < 0; // Sort by name (natural sorting).
776  }
777 
779  static bool TownPopulationSorter(const Town * const &a, const Town * const &b, const bool &order)
780  {
781  uint32_t a_population = a->cache.population;
782  uint32_t b_population = b->cache.population;
783  if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b, order);
784  return a_population < b_population;
785  }
786 
788  static bool TownRatingSorter(const Town * const &a, const Town * const &b, const bool &order)
789  {
790  bool before = !order; // Value to get 'a' before 'b'.
791 
792  /* Towns without rating are always after towns with rating. */
795  int16_t a_rating = a->ratings[_local_company];
796  int16_t b_rating = b->ratings[_local_company];
797  if (a_rating == b_rating) return TownDirectoryWindow::TownNameSorter(a, b, order);
798  return a_rating < b_rating;
799  }
800  return before;
801  }
802  if (HasBit(b->have_ratings, _local_company)) return !before;
803 
804  /* Sort unrated towns always on ascending town name. */
805  if (before) return TownDirectoryWindow::TownNameSorter(a, b, order);
806  return TownDirectoryWindow::TownNameSorter(b, a, order);
807  }
808 
809 public:
811  {
812  this->CreateNestedTree();
813 
814  this->vscroll = this->GetScrollbar(WID_TD_SCROLLBAR);
815 
816  this->towns.SetListing(this->last_sorting);
818  this->towns.ForceRebuild();
819  this->BuildSortTownList();
820 
821  this->FinishInitNested(0);
822 
824  this->townname_editbox.cancel_button = QueryString::ACTION_CLEAR;
825  }
826 
827  void SetStringParameters(WidgetID widget) const override
828  {
829  switch (widget) {
830  case WID_TD_CAPTION:
831  SetDParam(0, this->vscroll->GetCount());
833  break;
834 
837  break;
838 
840  SetDParam(0, TownDirectoryWindow::sorter_names[this->towns.SortType()]);
841  break;
842  }
843  }
844 
850  static StringID GetTownString(const Town *t)
851  {
852  return t->larger_town ? STR_TOWN_DIRECTORY_CITY : STR_TOWN_DIRECTORY_TOWN;
853  }
854 
855  void DrawWidget(const Rect &r, WidgetID widget) const override
856  {
857  switch (widget) {
858  case WID_TD_SORT_ORDER:
859  this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
860  break;
861 
862  case WID_TD_LIST: {
863  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
864  if (this->towns.empty()) { // No towns available.
865  DrawString(tr, STR_TOWN_DIRECTORY_NONE);
866  break;
867  }
868 
869  /* At least one town available. */
870  bool rtl = _current_text_dir == TD_RTL;
871  Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD);
872  int icon_x = tr.WithWidth(icon_size.width, rtl).left;
873  tr = tr.Indent(icon_size.width + WidgetDimensions::scaled.hsep_normal, rtl);
874 
875  auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->towns);
876  for (auto it = first; it != last; ++it) {
877  const Town *t = *it;
878  assert(t->xy != INVALID_TILE);
879 
880  /* Draw rating icon. */
881  if (_game_mode == GM_EDITOR || !HasBit(t->have_ratings, _local_company)) {
882  DrawSprite(SPR_TOWN_RATING_NA, PAL_NONE, icon_x, tr.top + (this->resize.step_height - icon_size.height) / 2);
883  } else {
884  SpriteID icon = SPR_TOWN_RATING_APALLING;
885  if (t->ratings[_local_company] > RATING_VERYPOOR) icon = SPR_TOWN_RATING_MEDIOCRE;
886  if (t->ratings[_local_company] > RATING_GOOD) icon = SPR_TOWN_RATING_GOOD;
887  DrawSprite(icon, PAL_NONE, icon_x, tr.top + (this->resize.step_height - icon_size.height) / 2);
888  }
889 
890  SetDParam(0, t->index);
891  SetDParam(1, t->cache.population);
892  DrawString(tr.left, tr.right, tr.top + (this->resize.step_height - GetCharacterHeight(FS_NORMAL)) / 2, GetTownString(t));
893 
894  tr.top += this->resize.step_height;
895  }
896  break;
897  }
898  }
899  }
900 
901  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
902  {
903  switch (widget) {
904  case WID_TD_SORT_ORDER: {
905  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
906  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
907  d.height += padding.height;
908  size = maxdim(size, d);
909  break;
910  }
911  case WID_TD_SORT_CRITERIA: {
912  Dimension d = GetStringListBoundingBox(TownDirectoryWindow::sorter_names);
913  d.width += padding.width;
914  d.height += padding.height;
915  size = maxdim(size, d);
916  break;
917  }
918  case WID_TD_LIST: {
919  Dimension d = GetStringBoundingBox(STR_TOWN_DIRECTORY_NONE);
920  for (uint i = 0; i < this->towns.size(); i++) {
921  const Town *t = this->towns[i];
922 
923  assert(t != nullptr);
924 
925  SetDParam(0, t->index);
926  SetDParamMaxDigits(1, 8);
928  }
929  Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD);
930  d.width += icon_size.width + 2;
931  d.height = std::max(d.height, icon_size.height);
932  resize.height = d.height;
933  d.height *= 5;
934  d.width += padding.width;
935  d.height += padding.height;
936  size = maxdim(size, d);
937  break;
938  }
940  SetDParamMaxDigits(0, 10);
941  Dimension d = GetStringBoundingBox(STR_TOWN_POPULATION);
942  d.width += padding.width;
943  d.height += padding.height;
944  size = maxdim(size, d);
945  break;
946  }
947  }
948  }
949 
950  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
951  {
952  switch (widget) {
953  case WID_TD_SORT_ORDER: // Click on sort order button
954  if (this->towns.SortType() != 2) { // A different sort than by rating.
955  this->towns.ToggleSortOrder();
956  this->last_sorting = this->towns.GetListing(); // Store new sorting order.
957  } else {
958  /* Some parts are always sorted ascending on name. */
959  this->last_sorting.order = !this->last_sorting.order;
960  this->towns.SetListing(this->last_sorting);
961  this->towns.ForceResort();
962  this->towns.Sort();
963  }
964  this->SetDirty();
965  break;
966 
967  case WID_TD_SORT_CRITERIA: // Click on sort criteria dropdown
968  ShowDropDownMenu(this, TownDirectoryWindow::sorter_names, this->towns.SortType(), WID_TD_SORT_CRITERIA, 0, 0);
969  break;
970 
971  case WID_TD_LIST: { // Click on Town Matrix
972  auto it = this->vscroll->GetScrolledItemFromWidget(this->towns, pt.y, this, WID_TD_LIST, WidgetDimensions::scaled.framerect.top);
973  if (it == this->towns.end()) return; // click out of town bounds
974 
975  const Town *t = *it;
976  assert(t != nullptr);
977  if (_ctrl_pressed) {
979  } else {
981  }
982  break;
983  }
984  }
985  }
986 
987  void OnDropdownSelect(WidgetID widget, int index) override
988  {
989  if (widget != WID_TD_SORT_CRITERIA) return;
990 
991  if (this->towns.SortType() != index) {
992  this->towns.SetSortType(index);
993  this->last_sorting = this->towns.GetListing(); // Store new sorting order.
994  this->BuildSortTownList();
995  }
996  }
997 
998  void OnPaint() override
999  {
1000  if (this->towns.NeedRebuild()) this->BuildSortTownList();
1001  this->DrawWidgets();
1002  }
1003 
1005  IntervalTimer<TimerWindow> rebuild_interval = {std::chrono::seconds(3), [this](auto) {
1006  this->BuildSortTownList();
1007  this->SetDirty();
1008  }};
1009 
1010  void OnResize() override
1011  {
1012  this->vscroll->SetCapacityFromWidget(this, WID_TD_LIST, WidgetDimensions::scaled.framerect.Vertical());
1013  }
1014 
1015  void OnEditboxChanged(WidgetID wid) override
1016  {
1017  if (wid == WID_TD_FILTER) {
1018  this->string_filter.SetFilterTerm(this->townname_editbox.text.buf);
1019  this->InvalidateData(TDIWD_FORCE_REBUILD);
1020  }
1021  }
1022 
1028  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1029  {
1030  switch (data) {
1031  case TDIWD_FORCE_REBUILD:
1032  /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
1033  this->towns.ForceRebuild();
1034  break;
1035 
1036  case TDIWD_POPULATION_CHANGE:
1037  if (this->towns.SortType() == 1) this->towns.ForceResort();
1038  break;
1039 
1040  default:
1041  this->towns.ForceResort();
1042  }
1043  }
1044 
1045  EventState OnHotkey(int hotkey) override
1046  {
1047  switch (hotkey) {
1048  case TDHK_FOCUS_FILTER_BOX:
1050  SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused.
1051  break;
1052  default:
1053  return ES_NOT_HANDLED;
1054  }
1055  return ES_HANDLED;
1056  }
1057 
1058  static inline HotkeyList hotkeys {"towndirectory", {
1059  Hotkey('F', "focus_filter_box", TDHK_FOCUS_FILTER_BOX),
1060  }};
1061 };
1062 
1063 Listing TownDirectoryWindow::last_sorting = {false, 0};
1064 
1066 const std::initializer_list<GUITownList::SortFunction * const> TownDirectoryWindow::sorter_funcs = {
1067  &TownNameSorter,
1068  &TownPopulationSorter,
1069  &TownRatingSorter,
1070 };
1071 
1072 static WindowDesc _town_directory_desc(
1073  WDP_AUTO, "list_towns", 208, 202,
1075  0,
1076  _nested_town_directory_widgets,
1077  &TownDirectoryWindow::hotkeys
1078 );
1079 
1080 void ShowTownDirectory()
1081 {
1082  if (BringWindowToFrontById(WC_TOWN_DIRECTORY, 0)) return;
1083  new TownDirectoryWindow(_town_directory_desc);
1084 }
1085 
1086 void CcFoundTown(Commands, const CommandCost &result, TileIndex tile)
1087 {
1088  if (result.Failed()) return;
1089 
1090  if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, tile);
1092 }
1093 
1094 void CcFoundRandomTown(Commands, const CommandCost &result, Money, TownID town_id)
1095 {
1096  if (result.Succeeded()) ScrollMainWindowToTile(Town::Get(town_id)->xy);
1097 }
1098 
1099 static constexpr NWidgetPart _nested_found_town_widgets[] = {
1101  NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
1102  NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_FOUND_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1103  NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
1104  NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
1105  EndContainer(),
1106  /* Construct new town(s) buttons. */
1107  NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
1109  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_NEW_TOWN), SetDataTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetFill(1, 0),
1110  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetDataTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetFill(1, 0),
1111  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetFill(1, 0),
1112  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_LOAD_FROM_FILE), SetDataTip(STR_FOUND_TOWN_LOAD_FROM_FILE, STR_FOUND_TOWN_LOAD_FROM_FILE_TOOLTIP), SetFill(1, 0),
1113  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_EXPAND_ALL_TOWNS), SetDataTip(STR_FOUND_TOWN_EXPAND_ALL_TOWNS, STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP), SetFill(1, 0),
1114 
1115  /* Town name selection. */
1116  NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_FOUND_TOWN_NAME_TITLE, STR_NULL),
1117  NWidget(WWT_EDITBOX, COLOUR_GREY, WID_TF_TOWN_NAME_EDITBOX), SetDataTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_HELP), SetFill(1, 0),
1118  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_TOWN_NAME_RANDOM), SetDataTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP), SetFill(1, 0),
1119 
1120  /* Town size selection. */
1121  NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE, STR_NULL),
1124  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_SMALL), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1125  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_MEDIUM), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1126  EndContainer(),
1128  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_LARGE), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1129  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_RANDOM), SetDataTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1130  EndContainer(),
1131  EndContainer(),
1132  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_CITY), SetDataTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0),
1133 
1134  /* Town roads selection. */
1135  NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_FOUND_TOWN_ROAD_LAYOUT, STR_NULL),
1138  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_ORIGINAL), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0),
1139  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_BETTER), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0),
1140  EndContainer(),
1142  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID2), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0),
1143  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID3), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0),
1144  EndContainer(),
1145  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_RANDOM), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0),
1146  EndContainer(),
1147  EndContainer(),
1148  EndContainer(),
1149 };
1150 
1153 private:
1156  bool city;
1159  uint32_t townnameparts;
1161 
1162 public:
1164  Window(desc),
1168  params(_settings_game.game_creation.town_name)
1169  {
1170  this->InitNested(window_number);
1172  this->RandomTownName();
1173  this->UpdateButtons(true);
1174  }
1175 
1176  void RandomTownName()
1177  {
1178  this->townnamevalid = GenerateTownName(_interactive_random, &this->townnameparts);
1179 
1180  if (!this->townnamevalid) {
1181  this->townname_editbox.text.DeleteAll();
1182  } else {
1183  this->townname_editbox.text.Assign(GetTownName(&this->params, this->townnameparts));
1184  }
1186 
1188  }
1189 
1190  void UpdateButtons(bool check_availability)
1191  {
1192  if (check_availability && _game_mode != GM_EDITOR) {
1197  }
1198 
1199  for (WidgetID i = WID_TF_SIZE_SMALL; i <= WID_TF_SIZE_RANDOM; i++) {
1200  this->SetWidgetLoweredState(i, i == WID_TF_SIZE_SMALL + this->town_size);
1201  }
1202 
1203  this->SetWidgetLoweredState(WID_TF_CITY, this->city);
1204 
1206  this->SetWidgetLoweredState(i, i == WID_TF_LAYOUT_ORIGINAL + this->town_layout);
1207  }
1208 
1209  this->SetDirty();
1210  }
1211 
1212  template <typename Tcallback>
1213  void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, Tcallback cc)
1214  {
1215  std::string name;
1216 
1217  if (!this->townnamevalid) {
1218  name = this->townname_editbox.text.buf;
1219  } else {
1220  /* If user changed the name, send it */
1221  std::string original_name = GetTownName(&this->params, this->townnameparts);
1222  if (original_name != this->townname_editbox.text.buf) name = this->townname_editbox.text.buf;
1223  }
1224 
1225  bool success = Command<CMD_FOUND_TOWN>::Post(errstr, cc,
1226  tile, this->town_size, this->city, this->town_layout, random, townnameparts, name);
1227 
1228  /* Rerandomise name, if success and no cost-estimation. */
1229  if (success && !_shift_pressed) this->RandomTownName();
1230  }
1231 
1232  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1233  {
1234  switch (widget) {
1235  case WID_TF_NEW_TOWN:
1236  HandlePlacePushButton(this, WID_TF_NEW_TOWN, SPR_CURSOR_TOWN, HT_RECT);
1237  break;
1238 
1239  case WID_TF_RANDOM_TOWN:
1240  this->ExecuteFoundTownCommand(0, true, STR_ERROR_CAN_T_GENERATE_TOWN, CcFoundRandomTown);
1241  break;
1242 
1244  this->RandomTownName();
1246  break;
1247 
1248  case WID_TF_MANY_RANDOM_TOWNS: {
1249  Backup<bool> old_generating_world(_generating_world, true);
1251  if (!GenerateTowns(this->town_layout)) {
1252  ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_TOWN, STR_ERROR_NO_SPACE_FOR_TOWN, WL_INFO);
1253  }
1255  old_generating_world.Restore();
1256  break;
1257  }
1258 
1259  case WID_TF_LOAD_FROM_FILE:
1261  break;
1262 
1264  for (Town *t : Town::Iterate()) {
1266  }
1267  break;
1268 
1270  this->town_size = (TownSize)(widget - WID_TF_SIZE_SMALL);
1271  this->UpdateButtons(false);
1272  break;
1273 
1274  case WID_TF_CITY:
1275  this->city ^= true;
1276  this->SetWidgetLoweredState(WID_TF_CITY, this->city);
1277  this->SetDirty();
1278  break;
1279 
1282  this->town_layout = (TownLayout)(widget - WID_TF_LAYOUT_ORIGINAL);
1283 
1284  /* If we are in the editor, sync the settings of the current game to the chosen layout,
1285  * so that importing towns from file uses the selected layout. */
1286  if (_game_mode == GM_EDITOR) _settings_game.economy.town_layout = this->town_layout;
1287 
1288  this->UpdateButtons(false);
1289  break;
1290  }
1291  }
1292 
1293  void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
1294  {
1295  this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown);
1296  }
1297 
1298  void OnPlaceObjectAbort() override
1299  {
1300  this->RaiseButtons();
1301  this->UpdateButtons(false);
1302  }
1303 
1309  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1310  {
1311  if (!gui_scope) return;
1312  this->UpdateButtons(true);
1313  }
1314 };
1315 
1316 static WindowDesc _found_town_desc(
1317  WDP_AUTO, "build_town", 160, 162,
1320  _nested_found_town_widgets
1321 );
1322 
1323 void ShowFoundTownWindow()
1324 {
1325  if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
1326  AllocateWindowDescFront<FoundTownWindow>(_found_town_desc, 0);
1327 }
1328 
1329 void InitializeTownGui()
1330 {
1331  _town_local_authority_kdtree.Clear();
1332 }
1333 
1342 void DrawNewHouseTileInGUI(int x, int y, const HouseSpec *spec, HouseID house_id, int view)
1343 {
1344  HouseResolverObject object(house_id, INVALID_TILE, nullptr, CBID_NO_CALLBACK, 0, 0, true, view);
1345  const SpriteGroup *group = object.Resolve();
1346  if (group == nullptr || group->type != SGT_TILELAYOUT) return;
1347 
1348  uint8_t stage = TOWN_HOUSE_COMPLETED;
1349  const DrawTileSprites *dts = reinterpret_cast<const TileLayoutSpriteGroup *>(group)->ProcessRegisters(&stage);
1350 
1351  PaletteID palette = GENERAL_SPRITE_COLOUR(spec->random_colour[0]);
1352  if (HasBit(spec->callback_mask, CBM_HOUSE_COLOUR)) {
1353  uint16_t callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, nullptr, INVALID_TILE, true, view);
1354  if (callback != CALLBACK_FAILED) {
1355  /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
1356  palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
1357  }
1358  }
1359 
1360  SpriteID image = dts->ground.sprite;
1361  PaletteID pal = dts->ground.pal;
1362 
1363  if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage;
1364  if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage;
1365 
1366  if (GB(image, 0, SPRITE_WIDTH) != 0) {
1367  DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
1368  }
1369 
1370  DrawNewGRFTileSeqInGUI(x, y, dts, stage, palette);
1371 }
1372 
1380 void DrawHouseInGUI(int x, int y, HouseID house_id, int view)
1381 {
1382  auto draw = [](int x, int y, HouseID house_id, int view) {
1383  if (house_id >= NEW_HOUSE_OFFSET) {
1384  /* Houses don't necessarily need new graphics. If they don't have a
1385  * spritegroup associated with them, then the sprite for the substitute
1386  * house id is drawn instead. */
1387  const HouseSpec *spec = HouseSpec::Get(house_id);
1388  if (spec->grf_prop.spritegroup[0] != nullptr) {
1389  DrawNewHouseTileInGUI(x, y, spec, house_id, view);
1390  return;
1391  } else {
1392  house_id = HouseSpec::Get(house_id)->grf_prop.subst_id;
1393  }
1394  }
1395 
1396  /* Retrieve data from the draw town tile struct */
1397  const DrawBuildingsTileStruct &dcts = GetTownDrawTileData()[house_id << 4 | view << 2 | TOWN_HOUSE_COMPLETED];
1398  DrawSprite(dcts.ground.sprite, dcts.ground.pal, x, y);
1399 
1400  /* Add a house on top of the ground? */
1401  if (dcts.building.sprite != 0) {
1402  Point pt = RemapCoords(dcts.subtile_x, dcts.subtile_y, 0);
1403  DrawSprite(dcts.building.sprite, dcts.building.pal, x + UnScaleGUI(pt.x), y + UnScaleGUI(pt.y));
1404  }
1405  };
1406 
1407  /* Houses can have 1x1, 1x2, 2x1 and 2x2 layouts which are individual HouseIDs. For the GUI we need
1408  * draw all of the tiles with appropriate positions. */
1409  int x_delta = ScaleGUITrad(TILE_PIXELS);
1410  int y_delta = ScaleGUITrad(TILE_PIXELS / 2);
1411 
1412  const HouseSpec *hs = HouseSpec::Get(house_id);
1413  if (hs->building_flags & TILE_SIZE_2x2) {
1414  draw(x, y - y_delta - y_delta, house_id, view); // North corner.
1415  draw(x + x_delta, y - y_delta, house_id + 1, view); // West corner.
1416  draw(x - x_delta, y - y_delta, house_id + 2, view); // East corner.
1417  draw(x, y, house_id + 3, view); // South corner.
1418  } else if (hs->building_flags & TILE_SIZE_2x1) {
1419  draw(x + x_delta / 2, y - y_delta, house_id, view); // North east tile.
1420  draw(x - x_delta / 2, y, house_id + 1, view); // South west tile.
1421  } else if (hs->building_flags & TILE_SIZE_1x2) {
1422  draw(x - x_delta / 2, y - y_delta, house_id, view); // North west tile.
1423  draw(x + x_delta / 2, y, house_id + 1, view); // South east tile.
1424  } else {
1425  draw(x, y, house_id, view);
1426  }
1427 }
1428 
1429 
1431 public:
1432  HousePickerCallbacks() : PickerCallbacks("fav_houses") {}
1433 
1438  {
1440  case LT_TEMPERATE: this->climate_mask = HZ_TEMP; break;
1441  case LT_ARCTIC: this->climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break;
1442  case LT_TROPIC: this->climate_mask = HZ_SUBTROPIC; break;
1443  case LT_TOYLAND: this->climate_mask = HZ_TOYLND; break;
1444  default: NOT_REACHED();
1445  }
1446 
1447  /* In some cases, not all 'classes' (house zones) have distinct houses, so we need to disable those.
1448  * As we need to check all types, and this cannot change with the picker window open, pre-calculate it.
1449  * This loop calls GetTypeName() instead of directly checking properties so that there is no discrepancy. */
1450  this->class_mask = 0;
1451 
1452  int num_classes = this->GetClassCount();
1453  for (int cls_id = 0; cls_id < num_classes; ++cls_id) {
1454  int num_types = this->GetTypeCount(cls_id);
1455  for (int id = 0; id < num_types; ++id) {
1456  if (this->GetTypeName(cls_id, id) != INVALID_STRING_ID) {
1457  SetBit(this->class_mask, cls_id);
1458  break;
1459  }
1460  }
1461  }
1462  }
1463 
1464  HouseZones climate_mask;
1465  uint8_t class_mask;
1466 
1467  static inline int sel_class;
1468  static inline int sel_type;
1469  static inline int sel_view;
1470 
1471  /* Houses do not have classes like NewGRFClass. We'll make up fake classes based on town zone
1472  * availability instead. */
1473  static inline const std::array<StringID, HZB_END> zone_names = {
1474  STR_HOUSE_PICKER_CLASS_ZONE1,
1475  STR_HOUSE_PICKER_CLASS_ZONE2,
1476  STR_HOUSE_PICKER_CLASS_ZONE3,
1477  STR_HOUSE_PICKER_CLASS_ZONE4,
1478  STR_HOUSE_PICKER_CLASS_ZONE5,
1479  };
1480 
1481  StringID GetClassTooltip() const override { return STR_PICKER_HOUSE_CLASS_TOOLTIP; }
1482  StringID GetTypeTooltip() const override { return STR_PICKER_HOUSE_TYPE_TOOLTIP; }
1483  bool IsActive() const override { return true; }
1484 
1485  bool HasClassChoice() const override { return true; }
1486  int GetClassCount() const override { return static_cast<int>(zone_names.size()); }
1487 
1488  void Close([[maybe_unused]] int data) override { ResetObjectToPlace(); }
1489 
1490  int GetSelectedClass() const override { return HousePickerCallbacks::sel_class; }
1491  void SetSelectedClass(int cls_id) const override { HousePickerCallbacks::sel_class = cls_id; }
1492 
1493  StringID GetClassName(int id) const override
1494  {
1495  if (id >= GetClassCount()) return INVALID_STRING_ID;
1496  if (!HasBit(this->class_mask, id)) return INVALID_STRING_ID;
1497  return zone_names[id];
1498  }
1499 
1500  int GetTypeCount(int cls_id) const override
1501  {
1502  if (cls_id < GetClassCount()) return static_cast<int>(HouseSpec::Specs().size());
1503  return 0;
1504  }
1505 
1506  PickerItem GetPickerItem(int cls_id, int id) const override
1507  {
1508  const auto *spec = HouseSpec::Get(id);
1509  if (spec->grf_prop.grffile == nullptr) return {0, spec->Index(), cls_id, id};
1510  return {spec->grf_prop.grffile->grfid, spec->grf_prop.local_id, cls_id, id};
1511  }
1512 
1513  int GetSelectedType() const override { return sel_type; }
1514  void SetSelectedType(int id) const override { sel_type = id; }
1515 
1516  StringID GetTypeName(int cls_id, int id) const override
1517  {
1518  const HouseSpec *spec = HouseSpec::Get(id);
1519  if (spec == nullptr) return INVALID_STRING_ID;
1520  if (!spec->enabled) return INVALID_STRING_ID;
1521  if ((spec->building_availability & climate_mask) == 0) return INVALID_STRING_ID;
1522  if (!HasBit(spec->building_availability, cls_id)) return INVALID_STRING_ID;
1523  for (int i = 0; i < cls_id; i++) {
1524  /* Don't include if it's already included in an earlier zone. */
1525  if (HasBit(spec->building_availability, i)) return INVALID_STRING_ID;
1526  }
1527 
1528  return spec->building_name;
1529  }
1530 
1531  bool IsTypeAvailable(int, int id) const override
1532  {
1533  const HouseSpec *hs = HouseSpec::Get(id);
1534  return hs->enabled;
1535  }
1536 
1537  void DrawType(int x, int y, int, int id) const override
1538  {
1540  }
1541 
1542  void FillUsedItems(std::set<PickerItem> &items) override
1543  {
1544  auto id_count = GetBuildingHouseIDCounts();
1545  for (auto it = id_count.begin(); it != id_count.end(); ++it) {
1546  if (*it == 0) continue;
1547  HouseID house = static_cast<HouseID>(std::distance(id_count.begin(), it));
1548  const HouseSpec *hs = HouseSpec::Get(house);
1549  int class_index = FindFirstBit(hs->building_availability & HZ_ZONALL);
1550  items.insert({0, house, class_index, house});
1551  }
1552  }
1553 
1554  std::set<PickerItem> UpdateSavedItems(const std::set<PickerItem> &src) override
1555  {
1556  if (src.empty()) return src;
1557 
1558  const auto specs = HouseSpec::Specs();
1559  std::set<PickerItem> dst;
1560  for (const auto &item : src) {
1561  if (item.grfid == 0) {
1562  dst.insert(item);
1563  } else {
1564  /* Search for spec by grfid and local index. */
1565  auto it = std::find_if(specs.begin(), specs.end(), [&item](const HouseSpec &spec) { return spec.grf_prop.grffile != nullptr && spec.grf_prop.grffile->grfid == item.grfid && spec.grf_prop.local_id == item.local_id; });
1566  if (it == specs.end()) {
1567  /* Not preset, hide from UI. */
1568  dst.insert({item.grfid, item.local_id, -1, -1});
1569  } else {
1570  int class_index = FindFirstBit(it->building_availability & HZ_ZONALL);
1571  dst.insert( {item.grfid, item.local_id, class_index, it->Index()});
1572  }
1573  }
1574  }
1575 
1576  return dst;
1577  }
1578 
1579  static HousePickerCallbacks instance;
1580 };
1581 /* static */ HousePickerCallbacks HousePickerCallbacks::instance;
1582 
1584  BuildHouseWindow(WindowDesc &desc, Window *parent) : PickerWindow(desc, parent, 0, HousePickerCallbacks::instance)
1585  {
1586  HousePickerCallbacks::instance.SetClimateMask();
1587  this->ConstructWindow();
1588  this->InvalidateData();
1589  }
1590 
1591  void UpdateSelectSize(const HouseSpec *spec)
1592  {
1593  if (spec == nullptr) {
1594  SetTileSelectSize(1, 1);
1596  } else {
1597  SetObjectToPlaceWnd(SPR_CURSOR_TOWN, PAL_NONE, HT_RECT | HT_DIAGONAL, this);
1598  if (spec->building_flags & TILE_SIZE_2x2) {
1599  SetTileSelectSize(2, 2);
1600  } else if (spec->building_flags & TILE_SIZE_2x1) {
1601  SetTileSelectSize(2, 1);
1602  } else if (spec->building_flags & TILE_SIZE_1x2) {
1603  SetTileSelectSize(1, 2);
1604  } else if (spec->building_flags & TILE_SIZE_1x1) {
1605  SetTileSelectSize(1, 1);
1606  }
1607  }
1608  }
1609 
1610  void OnInvalidateData(int data = 0, bool gui_scope = true) override
1611  {
1612  this->PickerWindow::OnInvalidateData(data, gui_scope);
1613  if (!gui_scope) return;
1614 
1615  if ((data & PickerWindow::PFI_POSITION) != 0) {
1617  UpdateSelectSize(spec);
1618  }
1619  }
1620 
1621  void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
1622  {
1624  Command<CMD_PLACE_HOUSE>::Post(STR_ERROR_CAN_T_BUILD_HOUSE, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index());
1625  }
1626 
1627  IntervalTimer<TimerWindow> view_refresh_interval = {std::chrono::milliseconds(2500), [this](auto) {
1628  /* There are four different 'views' that are random based on house tile position. As this is not
1629  * user-controllable, instead we automatically cycle through them. */
1631  this->SetDirty();
1632  }};
1633 
1634  static inline HotkeyList hotkeys{"buildhouse", {
1635  Hotkey('F', "focus_filter_box", PCWHK_FOCUS_FILTER_BOX),
1636  }};
1637 };
1638 
1642  NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
1643  NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_HOUSE_PICKER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1644  NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
1645  NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
1646  NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
1647  EndContainer(),
1651  EndContainer(),
1652 };
1653 
1654 static WindowDesc _build_house_desc(
1655  WDP_AUTO, "build_house", 0, 0,
1659  &BuildHouseWindow::hotkeys
1660 );
1661 
1662 void ShowBuildHousePicker(Window *parent)
1663 {
1664  if (BringWindowToFrontById(WC_BUILD_HOUSE, 0)) return;
1665  new BuildHouseWindow(_build_house_desc, parent);
1666 }
Class for backupping variables and making sure they are restored later.
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
#define CLRBITS(x, y)
Clears several bits in a variable.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
constexpr static debug_inline uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition: cargo_type.h:22
@ TPE_PASSENGERS
Cargo behaves passenger-like for production.
Definition: cargotype.h:36
@ TPE_MAIL
Cargo behaves mail-like for production.
Definition: cargotype.h:37
TownAcceptanceEffect
Town growth effect when delivering cargo.
Definition: cargotype.h:21
@ TAE_END
End of town effects.
Definition: cargotype.h:29
Common return value for all commands.
Definition: command_type.h:23
bool Succeeded() const
Did this command succeed?
Definition: command_type.h:162
bool Failed() const
Did this command fail?
Definition: command_type.h:171
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetListing(Listing l)
Import sort conditions.
bool IsDescSortOrder() const
Check if the sort order is descending.
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
bool Sort(Comp compare)
Sort the list.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
uint8_t SortType() const
Get the sorttype of the list.
Listing GetListing() const
Export current sort conditions.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
PickerItem GetPickerItem(int cls_id, int id) const override
Get data about an item.
Definition: town_gui.cpp:1506
bool IsActive() const override
Should picker class/type selection be enabled?
Definition: town_gui.cpp:1483
void SetClimateMask()
Set climate mask for filtering buildings from current landscape.
Definition: town_gui.cpp:1437
void SetSelectedClass(int cls_id) const override
Set the selected class.
Definition: town_gui.cpp:1491
StringID GetClassTooltip() const override
Get the tooltip string for the class list.
Definition: town_gui.cpp:1481
void DrawType(int x, int y, int, int id) const override
Draw preview image of an item.
Definition: town_gui.cpp:1537
static int sel_view
Currently selected 'view'. This is not controllable as its based on random data.
Definition: town_gui.cpp:1469
int GetClassCount() const override
Get the number of classes.
Definition: town_gui.cpp:1486
std::set< PickerItem > UpdateSavedItems(const std::set< PickerItem > &src) override
Update link between grfid/localidx and class_index/index in saved items.
Definition: town_gui.cpp:1554
void FillUsedItems(std::set< PickerItem > &items) override
Fill a set with all items that are used by the current player.
Definition: town_gui.cpp:1542
static int sel_type
Currently selected HouseID.
Definition: town_gui.cpp:1468
int GetSelectedClass() const override
Get the index of the selected class.
Definition: town_gui.cpp:1490
StringID GetTypeTooltip() const override
Get the tooltip string for the type grid.
Definition: town_gui.cpp:1482
void SetSelectedType(int id) const override
Set the selected type.
Definition: town_gui.cpp:1514
StringID GetTypeName(int cls_id, int id) const override
Get the item of a type.
Definition: town_gui.cpp:1516
int GetSelectedType() const override
Get the selected type.
Definition: town_gui.cpp:1513
bool IsTypeAvailable(int, int id) const override
Test if an item is currently buildable.
Definition: town_gui.cpp:1531
bool HasClassChoice() const override
Are there multiple classes to chose from?
Definition: town_gui.cpp:1485
uint8_t class_mask
Mask of available 'classes'.
Definition: town_gui.cpp:1465
int GetTypeCount(int cls_id) const override
Get the number of types in a class.
Definition: town_gui.cpp:1500
StringID GetClassName(int id) const override
Get the name of a class.
Definition: town_gui.cpp:1493
static int sel_class
Currently selected 'class'.
Definition: town_gui.cpp:1467
K-dimensional tree, specialised for 2-dimensional space.
Definition: kdtree.hpp:35
void Insert(const T &element)
Insert a single element in the tree.
Definition: kdtree.hpp:398
void Remove(const T &element)
Remove a single element from the tree, if it exists.
Definition: kdtree.hpp:417
void Clear()
Clear the tree.
Definition: kdtree.hpp:377
Baseclass for nested widgets.
Definition: widget_type.h:144
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:243
uint smallest_y
Smallest vertical size of the widget in a filled window.
Definition: widget_type.h:241
uint current_y
Current vertical size (after resizing).
Definition: widget_type.h:244
Nested widget to display a viewport in a window.
Definition: widget_type.h:680
void UpdateViewportCoordinates(Window *w)
Update the position and size of the viewport (after eg a resize).
Definition: widget.cpp:2297
void InitializeViewport(Window *w, std::variant< TileIndex, VehicleID > focus, ZoomLevel zoom)
Initialize the viewport of the window.
Definition: widget.cpp:2288
Class for PickerClassWindow to collect information and retain state.
Definition: picker_gui.h:37
@ PCWHK_FOCUS_FILTER_BOX
Focus the edit box for editing the filter string.
Definition: picker_gui.h:185
@ PFI_POSITION
Update scroll positions.
Definition: picker_gui.h:159
Scrollbar data structure.
Definition: widget_type.h:694
void SetCount(size_t num)
Sets the number of elements in the list.
Definition: widget_type.h:780
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
Definition: widget_type.h:879
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition: widget.cpp:2394
size_type GetCount() const
Gets the number of elements in the list.
Definition: widget_type.h:722
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
Definition: widget_type.h:860
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
RectPadding framerect
Standard padding inside many panels.
Definition: window_gui.h:42
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
int vsep_normal
Normal vertical spacing.
Definition: window_gui.h:60
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition: window_gui.h:67
int hsep_normal
Normal horizontal spacing.
Definition: window_gui.h:63
Functions related to commands.
@ DC_EXEC
execute the given command
Definition: command_type.h:376
Commands
List of commands.
Definition: command_type.h:187
Definition of stuff that is very close to a company, like the company struct itself.
void DrawCompanyIcon(CompanyID c, int x, int y)
Draw the icon of a company.
Money GetAvailableMoney(CompanyID company)
Get the amount of money that a company has available, or INT64_MAX if there is no such valid company.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
Functions related to companies.
GUI Functions related to companies.
void ShowDropDownMenu(Window *w, std::span< const StringID > strings, int selected, WidgetID button, uint32_t disabled_mask, uint32_t hidden_mask, uint width)
Show a dropdown menu window near a widget of the parent window.
Definition: dropdown.cpp:441
Functions related to the drop down widget.
Functions related to errors.
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
Definition: error_gui.cpp:367
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition: error.h:24
@ FT_TOWN_DATA
town data file
Definition: fileio_type.h:21
@ SLO_LOAD
File is being loaded.
Definition: fileio_type.h:55
Declarations for savegames operations.
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Launch save/load dialog in the given mode.
Definition: fios_gui.cpp:986
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:77
bool _generating_world
Whether we are generating the map or not.
Definition: genworld.cpp:67
Functions related to world/map generation.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition: gfx.cpp:704
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:922
bool _shift_pressed
Is Shift pressed?
Definition: gfx.cpp:39
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:851
Dimension GetStringListBoundingBox(std::span< const StringID > list, FontSize fontsize)
Get maximum dimension of a list of strings.
Definition: gfx.cpp:889
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:657
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:38
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition: gfx.cpp:988
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion)
Calculate string bounding box for multi-line strings.
Definition: gfx.cpp:740
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:774
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
uint32_t PaletteID
The number of the palette.
Definition: gfx_type.h:19
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:260
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition: gfx_type.h:284
constexpr NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
Definition: widget_type.h:1330
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
Definition: widget_type.h:1181
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
Definition: widget_type.h:1260
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1284
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
Definition: widget_type.h:1228
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1202
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition: widget_type.h:1137
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1309
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1191
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlags::ResizeX)
Widget part function for setting the aspect ratio.
Definition: widget_type.h:1295
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
uint8_t LowestSnowLine()
Get the lowest possible snow line height, either variable or static.
Definition: landscape.cpp:632
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
Definition: landscape.cpp:609
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:940
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition: gfx.cpp:1529
GUI functions that shouldn't be here.
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
Hotkey related functions.
definition of HouseSpec and accessors
static const HouseID NEW_HOUSE_OFFSET
Offset for new houses.
Definition: house.h:28
static const uint8_t TOWN_HOUSE_COMPLETED
Simple value that indicates the house has reached the final stage of construction.
Definition: house.h:23
HouseZones
Definition: house.h:66
@ HZ_SUBARTC_BELOW
13 2000 can appear in sub-arctic climate below the snow line
Definition: house.h:76
@ HZ_ZONALL
1F This is just to englobe all above types at once
Definition: house.h:73
@ HZ_TEMP
12 1000 can appear in temperate climate
Definition: house.h:75
@ HZ_TOYLND
15 8000 can appear in toyland climate
Definition: house.h:78
@ HZ_SUBTROPIC
14 4000 can appear in subtropical climate
Definition: house.h:77
@ HZ_SUBARTC_ABOVE
11 800 can appear in sub-arctic climate above the snow line
Definition: house.h:74
uint16_t HouseID
OpenTTD ID of house types.
Definition: house_type.h:13
Functions related to OTTD's landscape.
Point RemapCoords(int x, int y, int z)
Map 3D world or tile coordinate to equivalent 2D coordinate as used in the viewports and smallmap.
Definition: landscape.h:79
bool DoZoomInOutWindow(ZoomStateChange how, Window *w)
Zooms a viewport in a window in or out.
Definition: main_gui.cpp:93
bool HandlePlacePushButton(Window *w, WidgetID widget, CursorID cursor, HighLightStyle mode)
This code is shared for the majority of the pushbuttons.
Definition: main_gui.cpp:63
constexpr int RoundDivSU(int a, uint b)
Computes round(a / b) for signed a and unsigned b.
Definition: math_func.hpp:342
void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
Definition: misc_gui.cpp:1079
bool _networking
are we in networking mode?
Definition: network.cpp:65
bool _network_server
network-server is active
Definition: network.cpp:66
Basic functions/variables used all over the place.
@ CBID_HOUSE_COLOUR
Called to determine the colour of a town building.
@ CBID_NO_CALLBACK
Set when using the callback resolve system, but not to resolve a callback.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
@ CBM_HOUSE_COLOUR
decide the colour of the building
std::span< const uint > GetBuildingHouseIDCounts()
Get read-only span of total HouseID building counts.
Functions related to NewGRF houses.
void UpdateOSKOriginalText(const Window *parent, WidgetID button)
Updates the original text of the OSK so when the 'parent' changes the original and you press on cance...
Definition: osk_gui.cpp:410
std::unique_ptr< NWidgetBase > MakePickerTypeWidgets()
Create nested widgets for the type picker widgets.
Definition: picker_gui.cpp:646
std::unique_ptr< NWidgetBase > MakePickerClassWidgets()
Create nested widgets for the class picker widgets.
Definition: picker_gui.cpp:623
Functions/types etc.
Base for the GUIs that have an edit box in them.
Randomizer _interactive_random
Random used everywhere else, where it does not (directly) influence the game state.
Definition: random_func.cpp:37
void UpdateNearestTownForRoadTiles(bool invalidate)
Updates cached nearest town for all road tiles.
Definition: road_cmd.cpp:1918
Road related functions.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:57
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
@ SWS_OFF
Scroll wheel has no effect.
Base types for having sorted lists in GUIs.
Functions related to sound.
@ SND_1F_CONSTRUCTION_OTHER
29 == 0x1D Construction: other (non-water, non-rail, non-bridge)
Definition: sound_type.h:68
void DrawNewGRFTileSeqInGUI(int x, int y, const DrawTileSprites *dts, uint32_t stage, PaletteID default_palette)
Draw NewGRF object in GUI.
Definition: sprite.h:133
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition: sprite.h:168
static constexpr uint8_t SPRITE_MODIFIER_CUSTOM_SPRITE
these masks change the colours of the palette for a sprite.
Definition: sprites.h:1545
static constexpr uint8_t SPRITE_WIDTH
number of bits for the sprite number
Definition: sprites.h:1535
Definition of base types and functions in a cross-platform compatible way.
int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:589
Functions related to low-level strings.
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition: string_type.h:25
Searching and filtering using a stringterm.
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:56
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:357
void SetDParamMaxDigits(size_t n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:143
Functions related to OTTD's strings.
@ TD_RTL
Text is written right-to-left by default.
Definition: strings_type.h:24
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
static const int MAX_CHAR_LENGTH
Max. length of UTF-8 encoded unicode character.
Definition: strings_type.h:18
Class to backup a specific variable and restore it later.
Definition: backup_type.hpp:21
Specification of a cargo type.
Definition: cargotype.h:71
CargoID Index() const
Determines index of this cargospec.
Definition: cargotype.h:105
StringID name
Name of this type of cargo.
Definition: cargotype.h:88
static std::array< std::vector< const CargoSpec * >, NUM_TPE > town_production_cargoes
List of cargo specs for each Town Product Effect.
Definition: cargotype.h:193
SoundSettings sound
sound effect settings
GUISettings gui
settings related to the GUI
Dimensions (a width and height) of a rectangle in 2D.
This structure is the same for both Industries and Houses.
Definition: sprite.h:67
Ground palette sprite of a tile, together with its sprite layout.
Definition: sprite.h:58
PalSpriteID ground
Palette and sprite for the ground.
Definition: sprite.h:59
bool bribe
enable bribing the local authority
TownFounding found_town
town founding.
bool exclusive_rights
allow buying exclusive rights
TownLayout town_layout
select town layout,
bool station_noise_level
build new airports when the town noise level is still within accepted limits
bool fund_buildings
allow funding new buildings
bool fund_roads
allow funding local road reconstruction
Found a town window class.
Definition: town_gui.cpp:1152
uint32_t townnameparts
Generated town name.
Definition: town_gui.cpp:1159
TownLayout town_layout
Selected town layout.
Definition: town_gui.cpp:1155
QueryString townname_editbox
Townname editbox.
Definition: town_gui.cpp:1157
TownSize town_size
Selected town size.
Definition: town_gui.cpp:1154
bool townnamevalid
Is generated town name valid?
Definition: town_gui.cpp:1158
TownNameParams params
Town name parameters.
Definition: town_gui.cpp:1160
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
Definition: town_gui.cpp:1309
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
Definition: town_gui.cpp:1298
bool city
Are we building a city?
Definition: town_gui.cpp:1156
std::array< const struct SpriteGroup *, Tcnt > spritegroup
pointers to the different sprites of the entity
bool persistent_buildingtools
keep the building tools active after usage
uint8_t scrollwheel_scrolling
scrolling using the scroll wheel?
uint8_t landscape
the landscape we're currently in
EconomySettings economy
settings to change the economy
GameCreationSettings game_creation
settings used during the creation of a game (map)
List of hotkeys for a window.
Definition: hotkeys.h:37
All data for a single hotkey.
Definition: hotkeys.h:21
Resolver object to be used for houses (feature 07 spritegroups).
Definition: newgrf_house.h:52
bool enabled
the house is available to build (true by default, but can be disabled by newgrf)
Definition: house.h:107
static HouseSpec * Get(size_t house_id)
Get the spec for a house ID.
BuildingFlags building_flags
some flags that describe the house (size, stadium etc...)
Definition: house.h:105
HouseID Index() const
Gets the index of this spec.
StringID building_name
building name
Definition: house.h:99
GRFFileProps grf_prop
Properties related the the grf file.
Definition: house.h:110
Colours random_colour[4]
4 "random" colours
Definition: house.h:112
uint16_t callback_mask
Bitmask of house callbacks that have to be called.
Definition: house.h:111
HouseZones building_availability
where can it be built (climates, zones)
Definition: house.h:106
static std::vector< HouseSpec > & Specs()
Get a reference to all HouseSpecs.
Data structure describing how to show the list (what sort direction and criteria).
Definition: sortlist_type.h:30
bool order
Ascending/descending.
Definition: sortlist_type.h:31
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1075
SpriteID sprite
The 'real' sprite.
Definition: gfx_type.h:24
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition: gfx_type.h:25
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static size_t GetNumItems()
Returns number of valid items in the pool.
Definition: pool_type.hpp:369
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
Data stored about a string that can be modified in the GUI.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
static const int ACTION_CLEAR
Clear editbox.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
uint step_height
Step-size of height resize changes.
Definition: window_gui.h:214
Iterable ensemble of each set bit in a value.
bool confirm
Play sound effect on successful constructions or other actions.
virtual const SpriteGroup * Resolve([[maybe_unused]] ResolverObject &object) const
Base sprite group resolver.
String filter and state.
bool IsEmpty() const
Check whether any filter words were entered.
void SetFilterTerm(const char *str)
Set the term to filter on.
void ResetState()
Reset the matching state to process a new item.
void AddLine(const char *str)
Pass another text line from the current item to the filter.
bool GetState() const
Get the matching state of the current item.
void DeleteAll()
Delete every character in the textbuffer.
Definition: textbuf.cpp:114
void Assign(StringID string)
Render a string into the textbuffer.
Definition: textbuf.cpp:431
char *const buf
buffer in which text is saved
Definition: textbuf_type.h:32
Action 2 sprite layout for houses, industry tiles, objects and airport tiles.
Town authority window.
Definition: town_gui.cpp:76
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
Definition: town_gui.cpp:335
void DrawActions()
Draws the contents of the actions panel.
Definition: town_gui.cpp:219
Dimension icon_size
Dimensions of company icon.
Definition: town_gui.cpp:85
void OnInit() override
Notification that the nested widget tree gets initialized.
Definition: town_gui.cpp:143
Town * town
Town being displayed.
Definition: town_gui.cpp:78
TownActions enabled_actions
Actions that are enabled in settings.
Definition: town_gui.cpp:81
int sel_index
Currently selected town action, 0 to TACT_COUNT-1, -1 means no action selected.
Definition: town_gui.cpp:79
TownActions available_actions
Actions that are available to execute for the current company.
Definition: town_gui.cpp:82
void DrawRatings()
Draw the contents of the ratings panel.
Definition: town_gui.cpp:167
int GetNthSetBit(int n)
Get the position of the Nth set bit.
Definition: town_gui.cpp:96
uint displayed_actions_on_previous_painting
Actions that were available on the previous call to OnPaint()
Definition: town_gui.cpp:80
Dimension exclusive_size
Dimensions of exlusive icon.
Definition: town_gui.cpp:86
IntervalTimer< TimerWindow > redraw_interval
Redraw the whole window on a regular interval.
Definition: town_gui.cpp:331
static TownActions GetEnabledActions()
Gets all town authority actions enabled in settings.
Definition: town_gui.cpp:112
void OnPaint() override
The window must be repainted.
Definition: town_gui.cpp:149
uint32_t population
Current population of people.
Definition: town.h:44
uint32_t num_houses
Amount of houses.
Definition: town.h:43
Town directory window class.
Definition: town_gui.cpp:728
static const std::initializer_list< GUITownList::SortFunction *const > sorter_funcs
Available town directory sorting functions.
Definition: town_gui.cpp:739
static bool TownPopulationSorter(const Town *const &a, const Town *const &b, const bool &order)
Sort by population (default descending, as big towns are of the most interest).
Definition: town_gui.cpp:779
IntervalTimer< TimerWindow > rebuild_interval
Redraw the whole window on a regular interval.
Definition: town_gui.cpp:1005
QueryString townname_editbox
Filter editbox.
Definition: town_gui.cpp:742
static bool TownRatingSorter(const Town *const &a, const Town *const &b, const bool &order)
Sort by town rating.
Definition: town_gui.cpp:788
void OnResize() override
Called after the window got resized.
Definition: town_gui.cpp:1010
StringFilter string_filter
Filter for towns.
Definition: town_gui.cpp:741
EventState OnHotkey(int hotkey) override
A hotkey has been pressed.
Definition: town_gui.cpp:1045
void OnPaint() override
The window must be repainted.
Definition: town_gui.cpp:998
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
Definition: town_gui.cpp:1028
static StringID GetTownString(const Town *t)
Get the string to draw the town name.
Definition: town_gui.cpp:850
static bool TownNameSorter(const Town *const &a, const Town *const &b, const bool &)
Sort by town name.
Definition: town_gui.cpp:773
Struct holding parameters used to generate town name.
Definition: townname_type.h:28
Town * town
Town displayed by the window.
Definition: town_gui.cpp:362
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
Definition: town_gui.cpp:603
uint GetDesiredInfoHeight(int width) const
Gets the desired height for the information panel.
Definition: town_gui.cpp:544
void OnPaint() override
The window must be repainted.
Definition: town_gui.cpp:395
void OnResize() override
Called after the window got resized.
Definition: town_gui.cpp:581
Town data structure.
Definition: town.h:54
bool larger_town
if this is a larger town and should grow more quickly
Definition: town.h:101
TransportedCargoStat< uint32_t > supplied[NUM_CARGO]
Cargo statistics about supplied cargo.
Definition: town.h:79
TileIndex xy
town center tile
Definition: town.h:55
uint8_t fund_buildings_months
fund buildings program in action?
Definition: town.h:98
uint16_t noise_reached
level of noise that all the airports are generating
Definition: town.h:68
int16_t ratings[MAX_COMPANIES]
ratings of each company for this town
Definition: town.h:77
TransportedCargoStat< uint16_t > received[NUM_TAE]
Cargo statistics about received cargotypes.
Definition: town.h:80
uint16_t MaxTownNoise() const
Calculate the max town noise.
Definition: town.h:125
uint8_t flags
See TownFlags.
Definition: town.h:66
TownCache cache
Container for all cacheable data.
Definition: town.h:57
CompanyID exclusivity
which company has exclusivity
Definition: town.h:75
bool show_zone
NOSAVE: mark town to show the local authority zone in the viewports.
Definition: town.h:104
uint32_t goal[NUM_TAE]
Amount of cargo required for the town to grow.
Definition: town.h:81
std::string text
General text with additional information.
Definition: town.h:83
CompanyMask have_ratings
which companies have a rating
Definition: town.h:73
uint16_t growth_rate
town growth rate
Definition: town.h:96
Tstorage old_max
Maximum amount last month.
Definition: town_type.h:114
Tstorage old_act
Actually transported last month.
Definition: town_type.h:116
High level window description.
Definition: window_gui.h:159
Data structure for an opened window.
Definition: window_gui.h:273
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition: window.cpp:952
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition: window.cpp:1047
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition: widget.cpp:780
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1733
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition: window_gui.h:320
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:731
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition: window.cpp:3151
Window * parent
Parent window.
Definition: window_gui.h:328
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:551
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition: widget.cpp:763
ResizeInfo resize
Resize information.
Definition: window_gui.h:314
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition: window_gui.h:521
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1723
ViewportData * viewport
Pointer to viewport data, if present.
Definition: window_gui.h:318
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition: window.cpp:486
bool IsWidgetLowered(WidgetID widget_index) const
Gets the lowered state of a widget.
Definition: window_gui.h:497
void RaiseButtons(bool autoraise=false)
Raise the buttons of the window.
Definition: window.cpp:525
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition: window_gui.h:447
bool IsShaded() const
Is window shaded currently?
Definition: window_gui.h:563
int GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height=-1) const
Compute the row of a widget that a user clicked in.
Definition: window.cpp:213
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1746
WindowFlags flags
Window flags.
Definition: window_gui.h:300
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:314
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:387
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:302
@ QSF_ENABLE_DEFAULT
enable the 'Default' button ("\0" is returned)
Definition: textbuf_gui.h:21
@ QSF_LEN_IN_CHARS
the length of the string is counted in characters
Definition: textbuf_gui.h:22
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition: tile_map.h:238
static debug_inline uint TileHeight(Tile tile)
Returns the height of a tile.
Definition: tile_map.h:29
@ TROPICZONE_DESERT
Tile is desert.
Definition: tile_type.h:78
static const uint TILE_PIXELS
Pixel distance between tile columns/rows in #ZOOM_BASE.
Definition: tile_type.h:17
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition: viewport.cpp:3498
void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
Change the cursor and mouse click/drag handling to a mode for performing special operations like tile...
Definition: viewport.cpp:3435
@ HT_DIAGONAL
Also allow 'diagonal rectangles'. Only usable in combination with HT_RECT or HT_POINT.
@ HT_RECT
rectangle (stations, depots, ...)
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the Window system.
Base of the town class.
static const uint TOWN_GROWTH_WINTER
The town only needs this cargo in the winter (any amount)
Definition: town.h:33
const CargoSpec * FindFirstCargoWithTownAcceptanceEffect(TownAcceptanceEffect effect)
Determines the first cargo with a certain town effect.
Definition: town_cmd.cpp:3026
TownActions GetMaskOfTownActions(CompanyID cid, const Town *t)
Get a list of available town authority actions.
Definition: town_cmd.cpp:3579
static const uint TOWN_GROWTH_DESERT
The town needs the cargo for growth when on desert (any amount)
Definition: town.h:34
@ TOWN_IS_GROWING
Conditions for town growth are met. Grow according to Town::growth_rate.
Definition: town.h:196
uint32_t GetWorldPopulation()
Get the total population, the sum of all towns in the world.
Definition: town_cmd.cpp:462
TownActions
Town actions of a company.
Definition: town.h:212
@ TACT_ROAD_REBUILD
Rebuild the roads.
Definition: town.h:218
@ TACT_BUY_RIGHTS
Buy exclusive transport rights.
Definition: town.h:221
@ TACT_BRIBE
Try to bribe the council.
Definition: town.h:222
@ TACT_COUNT
Number of available town actions.
Definition: town.h:224
@ TACT_ALL
All possible actions.
Definition: town.h:229
@ TACT_FUND_BUILDINGS
Fund new buildings.
Definition: town.h:220
@ TACT_NONE
Empty action set.
Definition: town.h:213
const uint8_t _town_action_costs[TACT_COUNT]
Factor in the cost of each town action.
Definition: town_cmd.cpp:3288
bool GenerateTowns(TownLayout layout)
Generate a number of towns with a given layout.
Definition: town_cmd.cpp:2386
Command definitions related to towns.
static constexpr NWidgetPart _nested_build_house_widgets[]
Nested widget definition for the build NewGRF rail waypoint window.
Definition: town_gui.cpp:1640
void DrawHouseInGUI(int x, int y, HouseID house_id, int view)
Draw a house that does not exist.
Definition: town_gui.cpp:1380
void DrawNewHouseTileInGUI(int x, int y, const HouseSpec *spec, HouseID house_id, int view)
Draw representation of a house tile for GUI purposes.
Definition: town_gui.cpp:1342
TownDirectoryHotkeys
Enum referring to the Hotkeys in the town directory window.
Definition: town_gui.cpp:723
@ TDHK_FOCUS_FILTER_BOX
Focus the filter box.
Definition: town_gui.cpp:724
Declarations for accessing the k-d tree of towns.
TownLayout
Town Layouts.
Definition: town_type.h:79
@ TF_CUSTOM_LAYOUT
Allowed, with custom town layout.
Definition: town_type.h:97
TownSize
Supported initial town sizes.
Definition: town_type.h:19
@ TSZ_MEDIUM
Medium town.
Definition: town_type.h:21
static const uint MAX_LENGTH_TOWN_NAME_CHARS
The maximum length of a town name in characters including '\0'.
Definition: town_type.h:109
Types related to the town widgets.
@ WID_TA_EXECUTE
Do-it button.
Definition: town_widget.h:32
@ WID_TA_ACTION_INFO
Additional information about the action.
Definition: town_widget.h:31
@ WID_TA_RATING_INFO
Overview with ratings for each company.
Definition: town_widget.h:28
@ WID_TA_CAPTION
Caption of window.
Definition: town_widget.h:26
@ WID_TA_ZONE_BUTTON
Turn on/off showing local authority zone.
Definition: town_widget.h:27
@ WID_TA_COMMAND_LIST
List of commands for the player.
Definition: town_widget.h:29
@ WID_TV_VIEWPORT
View of the center of the town.
Definition: town_widget.h:38
@ WID_TV_INFO
General information about the town.
Definition: town_widget.h:39
@ WID_TV_EXPAND
Expand this town (scenario editor only).
Definition: town_widget.h:44
@ WID_TV_CATCHMENT
Toggle catchment area highlight.
Definition: town_widget.h:43
@ WID_TV_SHOW_AUTHORITY
Show the town authority window.
Definition: town_widget.h:41
@ WID_TV_CHANGE_NAME
Change the name of this town.
Definition: town_widget.h:42
@ WID_TV_CENTER_VIEW
Center the main view on this town.
Definition: town_widget.h:40
@ WID_TV_DELETE
Delete this town (scenario editor only).
Definition: town_widget.h:45
@ WID_TV_CAPTION
Caption of window.
Definition: town_widget.h:37
@ WID_TF_LAYOUT_RANDOM
Selection for a randomly chosen town layout.
Definition: town_widget.h:66
@ WID_TF_LOAD_FROM_FILE
Load town data from file.
Definition: town_widget.h:53
@ WID_TF_SIZE_LARGE
Selection for a large town.
Definition: town_widget.h:59
@ WID_TF_NEW_TOWN
Create a new town.
Definition: town_widget.h:50
@ WID_TF_EXPAND_ALL_TOWNS
Make all towns grow slightly.
Definition: town_widget.h:54
@ WID_TF_MANY_RANDOM_TOWNS
Randomly place many towns.
Definition: town_widget.h:52
@ WID_TF_SIZE_SMALL
Selection for a small town.
Definition: town_widget.h:57
@ WID_TF_LAYOUT_GRID2
Selection for the 2x2 grid town layout.
Definition: town_widget.h:64
@ WID_TF_LAYOUT_ORIGINAL
Selection for the original town layout.
Definition: town_widget.h:62
@ WID_TF_SIZE_RANDOM
Selection for a randomly sized town.
Definition: town_widget.h:60
@ WID_TF_TOWN_NAME_EDITBOX
Editor for the town name.
Definition: town_widget.h:55
@ WID_TF_SIZE_MEDIUM
Selection for a medium town.
Definition: town_widget.h:58
@ WID_TF_CITY
Selection for the town's city state.
Definition: town_widget.h:61
@ WID_TF_RANDOM_TOWN
Randomly place a town.
Definition: town_widget.h:51
@ WID_TF_LAYOUT_BETTER
Selection for the better town layout.
Definition: town_widget.h:63
@ WID_TF_LAYOUT_GRID3
Selection for the 3x3 grid town layout.
Definition: town_widget.h:65
@ WID_TF_TOWN_NAME_RANDOM
Generate a random town name.
Definition: town_widget.h:56
@ WID_TD_LIST
List of towns.
Definition: town_widget.h:19
@ WID_TD_CAPTION
Caption of the window.
Definition: town_widget.h:15
@ WID_TD_FILTER
Filter of name.
Definition: town_widget.h:18
@ WID_TD_SORT_ORDER
Direction of sort dropdown.
Definition: town_widget.h:16
@ WID_TD_WORLD_POPULATION
The world's population.
Definition: town_widget.h:21
@ WID_TD_SCROLLBAR
Scrollbar for the town list.
Definition: town_widget.h:20
@ WID_TD_SORT_CRITERIA
Criteria of sort dropdown.
Definition: town_widget.h:17
bool GenerateTownName(Randomizer &randomizer, uint32_t *townnameparts, TownNames *town_names)
Generates valid town name.
Definition: townname.cpp:136
static void GetTownName(StringBuilder &builder, const TownNameParams *par, uint32_t townnameparts)
Fills builder with specified town name.
Definition: townname.cpp:48
Town name generator stuff.
bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
Scrolls the viewport in a window to a given location.
Definition: viewport.cpp:2504
void SetTileSelectSize(int w, int h)
Highlight w by h tiles at the cursor.
Definition: viewport.cpp:2542
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2515
void SetViewportCatchmentTown(const Town *t, bool sel)
Select or deselect town for coverage area highlight.
Definition: viewport.cpp:3658
const Town * _viewport_highlight_town
Currently selected town for coverage area highlight.
Definition: viewport.cpp:1007
Functions related to (drawing on) viewports.
@ ZOOM_IN
Zoom in (get more detailed view).
Definition: viewport_type.h:77
@ ZOOM_OUT
Zoom out (get helicopter view).
Definition: viewport_type.h:78
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:524
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:112
@ WWT_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition: widget_type.h:51
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
Definition: widget_type.h:113
@ WWT_LABEL
Centered label.
Definition: widget_type.h:57
@ WWT_EDITBOX
a textbox for typing
Definition: widget_type.h:71
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:75
@ WWT_TEXTBTN
(Toggle) Button with text
Definition: widget_type.h:55
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:66
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:64
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:84
@ NWID_VERTICAL
Vertical container.
Definition: widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:69
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition: widget_type.h:65
@ NWID_VIEWPORT
Nested widget containing a viewport.
Definition: widget_type.h:81
@ WWT_DROPDOWN
Drop down list.
Definition: widget_type.h:70
@ WWT_TEXT
Pure simple text.
Definition: widget_type.h:58
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition: window.cpp:1223
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Definition: window.cpp:2022
void SetFocusedWindow(Window *w)
Set the window that has the focus.
Definition: window.cpp:422
Window functions not directly related to making/drawing windows.
@ SBS_DOWN
Sort ascending.
Definition: window_gui.h:220
@ SBS_UP
Sort descending.
Definition: window_gui.h:221
@ WF_DISABLE_VP_SCROLL
Window does not do autoscroll,.
Definition: window_gui.h:235
@ WDF_CONSTRUCTION
This window is used for construction; close it whenever changing company.
Definition: window_gui.h:203
@ WDP_AUTO
Find a place automatically.
Definition: window_gui.h:147
int WidgetID
Widget ID.
Definition: window_type.h:18
int32_t WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:737
EventState
State of handling an event.
Definition: window_type.h:743
@ ES_HANDLED
The passed event is handled.
Definition: window_type.h:744
@ ES_NOT_HANDLED
The passed event is not handled.
Definition: window_type.h:745
@ WC_TOWN_AUTHORITY
Town authority; Window numbers:
Definition: window_type.h:194
@ WC_FOUND_TOWN
Found a town; Window numbers:
Definition: window_type.h:435
@ WC_BUILD_HOUSE
Build house; Window numbers:
Definition: window_type.h:382
@ WC_BUILD_TOOLBAR
Build toolbar; Window numbers:
Definition: window_type.h:73
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
@ WC_TOWN_VIEW
Town view; Window numbers:
Definition: window_type.h:333
@ WC_TOWN_DIRECTORY
Town directory; Window numbers:
Definition: window_type.h:254
Functions related to zooming.
int ScaleGUITrad(int value)
Scale traditional pixel dimensions to GUI zoom level.
Definition: zoom_func.h:117
ZoomLevel ScaleZoomGUI(ZoomLevel value)
Scale zoom level relative to GUI zoom.
Definition: zoom_func.h:87
int UnScaleGUI(int value)
Short-hand to apply GUI zoom level.
Definition: zoom_func.h:77
@ ZOOM_LVL_TOWN
Default zoom level for the town view.
Definition: zoom_type.h:31