OpenTTD Source 20250613-master-ga1786fa1f4
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_cargo.h"
17#include "newgrf_house.h"
18#include "newgrf_text.h"
19#include "picker_gui.h"
20#include "command_func.h"
21#include "company_func.h"
22#include "company_base.h"
23#include "company_gui.h"
24#include "network/network.h"
25#include "string_func.h"
26#include "strings_func.h"
27#include "sound_func.h"
28#include "tilehighlight_func.h"
29#include "sortlist_type.h"
30#include "road_cmd.h"
31#include "landscape.h"
32#include "querystring_gui.h"
33#include "window_func.h"
34#include "townname_func.h"
35#include "core/backup_type.hpp"
38#include "genworld.h"
39#include "fios.h"
40#include "stringfilter_type.h"
41#include "dropdown_func.h"
42#include "town_kdtree.h"
43#include "town_cmd.h"
44#include "timer/timer.h"
46#include "timer/timer_window.h"
47#include "zoom_func.h"
48#include "hotkeys.h"
49
50#include "widgets/town_widget.h"
51
52#include "table/strings.h"
53
54#include "safeguards.h"
55
56TownKdtree _town_local_authority_kdtree{};
57
59
60static constexpr NWidgetPart _nested_town_authority_widgets[] = {
62 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
63 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TA_CAPTION),
64 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TA_ZONE_BUTTON), SetMinimalSize(50, 0), SetStringTip(STR_LOCAL_AUTHORITY_ZONE, STR_LOCAL_AUTHORITY_ZONE_TOOLTIP),
65 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
66 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
67 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
69 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(),
70 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(317, 52), SetResize(1, 0), SetToolTip(STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), EndContainer(),
71 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(),
73 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TA_EXECUTE), SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP),
74 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
76};
77
80private:
81 Town *town = nullptr;
82 TownAction sel_action = TownAction::End;
86 std::array<StringID, to_underlying(TownAction::End)> action_tooltips{};
87
90
97 {
98 TownActions enabled{};
99 enabled.Set();
100
104 if (!_settings_game.economy.bribe) enabled.Reset(TownAction::Bribe);
105
106 return enabled;
107 }
108
109public:
111 {
112 this->town = Town::Get(window_number);
114
116 this->action_tooltips[0] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING;
117 this->action_tooltips[1] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING;
118 this->action_tooltips[2] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING;
119 this->action_tooltips[3] = realtime ? STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION_MINUTES : STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION_MONTHS;
120 this->action_tooltips[4] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY;
121 this->action_tooltips[5] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS;
122 this->action_tooltips[6] = realtime ? STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT_MINUTES : STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT_MONTHS;
123 this->action_tooltips[7] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE;
124
125 this->InitNested(window_number);
126 }
127
128 void OnInit() override
129 {
130 this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
131 this->exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT);
132 }
133
134 void OnPaint() override
135 {
139
141 this->SetWidgetDisabledState(WID_TA_EXECUTE, (this->sel_action == TownAction::End) || !this->available_actions.Test(this->sel_action));
142
143 this->DrawWidgets();
144 if (!this->IsShaded())
145 {
146 this->DrawRatings();
147 this->DrawActions();
148 }
149 }
150
151 StringID GetRatingString(int rating) const
152 {
153 if (rating > RATING_EXCELLENT) return STR_CARGO_RATING_OUTSTANDING;
154 if (rating > RATING_VERYGOOD) return STR_CARGO_RATING_EXCELLENT;
155 if (rating > RATING_GOOD) return STR_CARGO_RATING_VERY_GOOD;
156 if (rating > RATING_MEDIOCRE) return STR_CARGO_RATING_GOOD;
157 if (rating > RATING_POOR) return STR_CARGO_RATING_MEDIOCRE;
158 if (rating > RATING_VERYPOOR) return STR_CARGO_RATING_POOR;
159 if (rating > RATING_APPALLING) return STR_CARGO_RATING_VERY_POOR;
160 return STR_CARGO_RATING_APPALLING;
161 }
162
165 {
166 Rect r = this->GetWidget<NWidgetBase>(WID_TA_RATING_INFO)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
167
168 int text_y_offset = (this->resize.step_height - GetCharacterHeight(FS_NORMAL)) / 2;
169 int icon_y_offset = (this->resize.step_height - this->icon_size.height) / 2;
170 int exclusive_y_offset = (this->resize.step_height - this->exclusive_size.height) / 2;
171
172 DrawString(r.left, r.right, r.top + text_y_offset, STR_LOCAL_AUTHORITY_COMPANY_RATINGS);
173 r.top += this->resize.step_height;
174
175 bool rtl = _current_text_dir == TD_RTL;
176 Rect icon = r.WithWidth(this->icon_size.width, rtl);
177 Rect exclusive = r.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal, rtl).WithWidth(this->exclusive_size.width, rtl);
178 Rect text = r.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal + this->exclusive_size.width + WidgetDimensions::scaled.hsep_normal, rtl);
179
180 /* Draw list of companies */
181 for (const Company *c : Company::Iterate()) {
182 if ((this->town->have_ratings.Test(c->index) || this->town->exclusivity == c->index)) {
183 DrawCompanyIcon(c->index, icon.left, text.top + icon_y_offset);
184
185 if (this->town->exclusivity == c->index) {
186 DrawSprite(SPR_EXCLUSIVE_TRANSPORT, GetCompanyPalette(c->index), exclusive.left, text.top + exclusive_y_offset);
187 }
188
189 int rating = this->town->ratings[c->index];
190 DrawString(text.left, text.right, text.top + text_y_offset, GetString(STR_LOCAL_AUTHORITY_COMPANY_RATING, c->index, c->index, GetRatingString(rating)));
191 text.top += this->resize.step_height;
192 }
193 }
194
195 text.bottom = text.top - 1;
196 if (text.bottom > r.bottom) {
197 /* If the company list is too big to fit, mark ourself dirty and draw again. */
198 ResizeWindow(this, 0, text.bottom - r.bottom, false);
199 }
200 }
201
204 {
205 Rect r = this->GetWidget<NWidgetBase>(WID_TA_COMMAND_LIST)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
206
207 DrawString(r, STR_LOCAL_AUTHORITY_ACTIONS_TITLE);
209
210 /* Draw list of actions */
211 for (TownAction i = {}; i != TownAction::End; ++i) {
212 /* Don't show actions if disabled in settings. */
213 if (!this->enabled_actions.Test(i)) continue;
214
215 /* Set colour of action based on ability to execute and if selected. */
216 TextColour action_colour = TC_GREY | TC_NO_SHADE;
217 if (this->available_actions.Test(i)) action_colour = TC_ORANGE;
218 if (this->sel_action == i) action_colour = TC_WHITE;
219
220 DrawString(r, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + to_underlying(i), action_colour);
222 }
223 }
224
225 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
226 {
227 if (widget == WID_TA_CAPTION) return GetString(STR_LOCAL_AUTHORITY_CAPTION, this->window_number);
228
229 return this->Window::GetWidgetString(widget, stringid);
230 }
231
232 void DrawWidget(const Rect &r, WidgetID widget) const override
233 {
234 switch (widget) {
236 if (this->sel_action != TownAction::End) {
237 Money action_cost = _price[PR_TOWN_ACTION] * GetTownActionCost(this->sel_action) >> 8;
238 bool affordable = Company::IsValidID(_local_company) && action_cost < GetAvailableMoney(_local_company);
239
241 GetString(this->action_tooltips[to_underlying(this->sel_action)], action_cost),
242 affordable ? TC_YELLOW : TC_RED);
243 }
244 break;
245 }
246 }
247
248 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
249 {
250 switch (widget) {
251 case WID_TA_ACTION_INFO: {
252 assert(size.width > padding.width && size.height > padding.height);
253 Dimension d = {0, 0};
254 for (TownAction i = {}; i != TownAction::End; ++i) {
255 Money price = _price[PR_TOWN_ACTION] * GetTownActionCost(i) >> 8;
256 d = maxdim(d, GetStringMultiLineBoundingBox(GetString(this->action_tooltips[to_underlying(i)], price), size));
257 }
258 d.width += padding.width;
259 d.height += padding.height;
260 size = maxdim(size, d);
261 break;
262 }
263
265 size.height = (to_underlying(TownAction::End) + 1) * GetCharacterHeight(FS_NORMAL) + padding.height;
266 size.width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width;
267 for (TownAction i = {}; i != TownAction::End; ++i) {
268 size.width = std::max(size.width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + to_underlying(i)).width + padding.width);
269 }
270 size.width += padding.width;
271 break;
272
275 size.height = 9 * resize.height + padding.height;
276 break;
277 }
278 }
279
280 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
281 {
282 switch (widget) {
283 case WID_TA_ZONE_BUTTON: {
284 bool new_show_state = !this->town->show_zone;
285 TownID index = this->town->index;
286
287 new_show_state ? _town_local_authority_kdtree.Insert(index) : _town_local_authority_kdtree.Remove(index);
288
289 this->town->show_zone = new_show_state;
290 this->SetWidgetLoweredState(widget, new_show_state);
292 break;
293 }
294
295 case WID_TA_COMMAND_LIST: {
297
298 auto action = this->enabled_actions.GetNthSetBit(y);
299 if (!action.has_value()) break;
300
301 this->sel_action = *action;
302 this->SetDirty();
303
304 /* When double-clicking, continue */
305 if (click_count == 1 || !this->available_actions.Test(this->sel_action)) break;
306 [[fallthrough]];
307 }
308
309 case WID_TA_EXECUTE:
310 Command<CMD_DO_TOWN_ACTION>::Post(STR_ERROR_CAN_T_DO_THIS, this->town->xy, static_cast<TownID>(this->window_number), this->sel_action);
311 break;
312 }
313 }
314
316 const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
317 this->SetDirty();
318 }};
319
320 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
321 {
322 if (!gui_scope) return;
323
324 this->enabled_actions = this->GetEnabledActions();
325 if (!this->enabled_actions.Test(this->sel_action)) {
326 this->sel_action = TownAction::End;
327 }
328 }
329};
330
331static WindowDesc _town_authority_desc(
332 WDP_AUTO, "view_town_authority", 317, 222,
334 {},
335 _nested_town_authority_widgets
336);
337
338static void ShowTownAuthorityWindow(uint town)
339{
340 AllocateWindowDescFront<TownAuthorityWindow>(_town_authority_desc, town);
341}
342
343
344/* Town view window. */
346private:
347 Town *town = nullptr;
348
349public:
350 static const int WID_TV_HEIGHT_NORMAL = 150;
351
353 {
354 this->CreateNestedTree();
355
356 this->town = Town::Get(window_number);
357
358 this->FinishInitNested(window_number);
359
361 NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_TV_VIEWPORT);
362 nvp->InitializeViewport(this, this->town->xy, ScaleZoomGUI(ZoomLevel::Town));
363
364 /* disable renaming town in network games if you are not the server */
366 }
367
368 void Close([[maybe_unused]] int data = 0) override
369 {
371 this->Window::Close();
372 }
373
374 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
375 {
376 if (widget == WID_TV_CAPTION) return GetString(this->town->larger_town ? STR_TOWN_VIEW_CITY_CAPTION : STR_TOWN_VIEW_TOWN_CAPTION, this->town->index);
377
378 return this->Window::GetWidgetString(widget, stringid);
379 }
380
381 void OnPaint() override
382 {
383 extern const Town *_viewport_highlight_town;
384 this->SetWidgetLoweredState(WID_TV_CATCHMENT, _viewport_highlight_town == this->town);
385
386 this->DrawWidgets();
387 }
388
389 void DrawWidget(const Rect &r, WidgetID widget) const override
390 {
391 if (widget != WID_TV_INFO) return;
392
393 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
394
395 DrawString(tr, GetString(STR_TOWN_VIEW_POPULATION_HOUSES, this->town->cache.population, this->town->cache.num_houses));
396 tr.top += GetCharacterHeight(FS_NORMAL);
397
398 StringID str_last_period = TimerGameEconomy::UsingWallclockUnits() ? STR_TOWN_VIEW_CARGO_LAST_MINUTE_MAX : STR_TOWN_VIEW_CARGO_LAST_MONTH_MAX;
399
400 for (auto tpe : {TPE_PASSENGERS, TPE_MAIL}) {
401 for (const CargoSpec *cs : CargoSpec::town_production_cargoes[tpe]) {
402 CargoType cargo_type = cs->Index();
403 DrawString(tr, GetString(str_last_period, 1ULL << cargo_type, this->town->supplied[cargo_type].old_act, this->town->supplied[cargo_type].old_max));
404 tr.top += GetCharacterHeight(FS_NORMAL);
405 }
406 }
407
408 bool first = true;
409 for (int i = TAE_BEGIN; i < TAE_END; i++) {
410 if (this->town->goal[i] == 0) continue;
411 if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue;
412 if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue;
413
414 if (first) {
415 DrawString(tr, STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH);
416 tr.top += GetCharacterHeight(FS_NORMAL);
417 first = false;
418 }
419
420 bool rtl = _current_text_dir == TD_RTL;
421
423 assert(cargo != nullptr);
424
425 StringID string;
426
427 if (this->town->goal[i] == TOWN_GROWTH_DESERT || this->town->goal[i] == TOWN_GROWTH_WINTER) {
428 /* For 'original' gameplay, don't show the amount required (you need 1 or more ..) */
429 string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL;
430 if (this->town->received[i].old_act == 0) {
431 string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL;
432
433 if (this->town->goal[i] == TOWN_GROWTH_WINTER && TileHeight(this->town->xy) < GetSnowLine()) {
434 string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER;
435 }
436 }
437
438 DrawString(tr.Indent(20, rtl), GetString(string, cargo->name));
439 } else {
440 string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED;
441 if (this->town->received[i].old_act < this->town->goal[i]) {
442 string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED;
443 }
444 DrawString(tr.Indent(20, rtl), GetString(string, cargo->Index(), this->town->received[i].old_act, cargo->Index(), this->town->goal[i]));
445 }
446 tr.top += GetCharacterHeight(FS_NORMAL);
447 }
448
449 if (HasBit(this->town->flags, TOWN_IS_GROWING)) {
450 DrawString(tr, GetString(this->town->fund_buildings_months == 0 ? STR_TOWN_VIEW_TOWN_GROWS_EVERY : STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED, RoundDivSU(this->town->growth_rate + 1, Ticks::DAY_TICKS)));
451 tr.top += GetCharacterHeight(FS_NORMAL);
452 } else {
453 DrawString(tr, STR_TOWN_VIEW_TOWN_GROW_STOPPED);
454 tr.top += GetCharacterHeight(FS_NORMAL);
455 }
456
457 /* only show the town noise, if the noise option is activated. */
459 DrawString(tr, GetString(STR_TOWN_VIEW_NOISE_IN_TOWN, this->town->noise_reached, this->town->MaxTownNoise()));
460 tr.top += GetCharacterHeight(FS_NORMAL);
461 }
462
463 if (!this->town->text.empty()) {
464 tr.top = DrawStringMultiLine(tr, this->town->text.GetDecodedString(), TC_BLACK);
465 }
466 }
467
468 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
469 {
470 switch (widget) {
471 case WID_TV_CENTER_VIEW: // scroll to location
472 if (_ctrl_pressed) {
473 ShowExtraViewportWindow(this->town->xy);
474 } else {
475 ScrollMainWindowToTile(this->town->xy);
476 }
477 break;
478
479 case WID_TV_SHOW_AUTHORITY: // town authority
480 ShowTownAuthorityWindow(this->window_number);
481 break;
482
483 case WID_TV_CHANGE_NAME: // rename
485 break;
486
487 case WID_TV_CATCHMENT:
489 break;
490
491 case WID_TV_EXPAND: // expand town - only available on Scenario editor
492 Command<CMD_EXPAND_TOWN>::Post(STR_ERROR_CAN_T_EXPAND_TOWN, static_cast<TownID>(this->window_number), 0, {TownExpandMode::Buildings, TownExpandMode::Roads});
493 break;
494
495 case WID_TV_EXPAND_BUILDINGS: // expand buildings of town - only available on Scenario editor
496 Command<CMD_EXPAND_TOWN>::Post(STR_ERROR_CAN_T_EXPAND_TOWN, static_cast<TownID>(this->window_number), 0, {TownExpandMode::Buildings});
497 break;
498
499 case WID_TV_EXPAND_ROADS: // expand roads of town - only available on Scenario editor
500 Command<CMD_EXPAND_TOWN>::Post(STR_ERROR_CAN_T_EXPAND_TOWN, static_cast<TownID>(this->window_number), 0, {TownExpandMode::Roads});
501 break;
502
503 case WID_TV_DELETE: // delete town - only available on Scenario editor
504 Command<CMD_DELETE_TOWN>::Post(STR_ERROR_TOWN_CAN_T_DELETE, static_cast<TownID>(this->window_number));
505 break;
506 }
507 }
508
509 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
510 {
511 switch (widget) {
512 case WID_TV_INFO:
513 size.height = GetDesiredInfoHeight(size.width) + padding.height;
514 break;
515 }
516 }
517
523 {
525
526 bool first = true;
527 for (int i = TAE_BEGIN; i < TAE_END; i++) {
528 if (this->town->goal[i] == 0) continue;
529 if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue;
530 if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue;
531
532 if (first) {
533 aimed_height += GetCharacterHeight(FS_NORMAL);
534 first = false;
535 }
536 aimed_height += GetCharacterHeight(FS_NORMAL);
537 }
538 aimed_height += GetCharacterHeight(FS_NORMAL);
539
541
542 if (!this->town->text.empty()) {
544 }
545
546 return aimed_height;
547 }
548
549 void ResizeWindowAsNeeded()
550 {
551 const NWidgetBase *nwid_info = this->GetWidget<NWidgetBase>(WID_TV_INFO);
552 uint aimed_height = GetDesiredInfoHeight(nwid_info->current_x);
553 if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) {
554 this->ReInit();
555 }
556 }
557
558 void OnResize() override
559 {
560 if (this->viewport != nullptr) {
561 NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_TV_VIEWPORT);
562 nvp->UpdateViewportCoordinates(this);
563
564 ScrollWindowToTile(this->town->xy, this, true); // Re-center viewport.
565 }
566 }
567
568 void OnMouseWheel(int wheel, WidgetID widget) override
569 {
570 if (widget != WID_TV_VIEWPORT) return;
572 DoZoomInOutWindow(wheel < 0 ? ZOOM_IN : ZOOM_OUT, this);
573 }
574 }
575
581 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
582 {
583 if (!gui_scope) return;
584 /* Called when setting station noise or required cargoes have changed, in order to resize the window */
585 this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading
586 this->ResizeWindowAsNeeded();
587 }
588
589 void OnQueryTextFinished(std::optional<std::string> str) override
590 {
591 if (!str.has_value()) return;
592
593 Command<CMD_RENAME_TOWN>::Post(STR_ERROR_CAN_T_RENAME_TOWN, static_cast<TownID>(this->window_number), *str);
594 }
595
596 const IntervalTimer<TimerGameCalendar> daily_interval = {{TimerGameCalendar::DAY, TimerGameCalendar::Priority::NONE}, [this](auto) {
597 /* Refresh after possible snowline change */
598 this->SetDirty();
599 }};
600};
601
602static constexpr NWidgetPart _nested_town_game_view_widgets[] = {
604 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
605 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
606 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION),
607 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetSpriteTip(SPR_GOTO_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
608 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
609 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
610 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
611 EndContainer(),
612 NWidget(WWT_PANEL, COLOUR_BROWN),
613 NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
614 NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetResize(1, 1),
615 EndContainer(),
616 EndContainer(),
617 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
619 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP),
620 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(40, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
621 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
622 EndContainer(),
623};
624
625static WindowDesc _town_game_view_desc(
626 WDP_AUTO, "view_town", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL,
628 {},
629 _nested_town_game_view_widgets
630);
631
632static constexpr NWidgetPart _nested_town_editor_view_widgets[] = {
634 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
635 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
636 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetToolTip(STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
637 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetSpriteTip(SPR_GOTO_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
638 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
639 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
640 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
641 EndContainer(),
642 NWidget(WWT_PANEL, COLOUR_BROWN),
643 NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
644 NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 1), SetResize(1, 1),
645 EndContainer(),
646 EndContainer(),
647 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
649 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP),
650 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND_BUILDINGS), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_EXPAND_BUILDINGS_BUTTON, STR_TOWN_VIEW_EXPAND_BUILDINGS_TOOLTIP),
651 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND_ROADS), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_EXPAND_ROADS_BUTTON, STR_TOWN_VIEW_EXPAND_ROADS_TOOLTIP),
652 EndContainer(),
654 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP),
655 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
656 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
657 EndContainer(),
658};
659
660static WindowDesc _town_editor_view_desc(
661 WDP_AUTO, "view_town_scen", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL,
663 {},
664 _nested_town_editor_view_widgets
665);
666
667void ShowTownViewWindow(TownID town)
668{
669 if (_game_mode == GM_EDITOR) {
670 AllocateWindowDescFront<TownViewWindow>(_town_editor_view_desc, town);
671 } else {
672 AllocateWindowDescFront<TownViewWindow>(_town_game_view_desc, town);
673 }
674}
675
676static constexpr NWidgetPart _nested_town_directory_widgets[] = {
678 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
679 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TD_CAPTION),
680 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
681 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
682 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
683 EndContainer(),
687 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetStringTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
688 NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetToolTip(STR_TOOLTIP_SORT_CRITERIA),
689 NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_TD_FILTER), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
690 EndContainer(),
691 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TD_LIST), SetToolTip(STR_TOWN_DIRECTORY_LIST_TOOLTIP),
693 NWidget(WWT_PANEL, COLOUR_BROWN),
694 NWidget(WWT_TEXT, INVALID_COLOUR, WID_TD_WORLD_POPULATION), SetPadding(2, 0, 2, 2), SetFill(1, 0), SetResize(1, 0),
695 EndContainer(),
696 EndContainer(),
699 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
700 EndContainer(),
701 EndContainer(),
702};
703
708
711private:
712 /* Runtime saved values */
713 static Listing last_sorting;
714
715 /* Constants for sorting towns */
716 static inline const StringID sorter_names[] = {
717 STR_SORT_BY_NAME,
718 STR_SORT_BY_POPULATION,
719 STR_SORT_BY_RATING,
720 };
721 static const std::initializer_list<GUITownList::SortFunction * const> sorter_funcs;
722
725
726 GUITownList towns{TownDirectoryWindow::last_sorting.order};
727
728 Scrollbar *vscroll = nullptr;
729
730 void BuildSortTownList()
731 {
732 if (this->towns.NeedRebuild()) {
733 this->towns.clear();
734 this->towns.reserve(Town::GetNumItems());
735
736 for (const Town *t : Town::Iterate()) {
737 if (this->string_filter.IsEmpty()) {
738 this->towns.push_back(t);
739 continue;
740 }
742 this->string_filter.AddLine(t->GetCachedName());
743 if (this->string_filter.GetState()) this->towns.push_back(t);
744 }
745
746 this->towns.RebuildDone();
747 this->vscroll->SetCount(this->towns.size()); // Update scrollbar as well.
748 }
749 /* Always sort the towns. */
750 this->towns.Sort();
751 this->SetWidgetDirty(WID_TD_LIST); // Force repaint of the displayed towns.
752 }
753
755 static bool TownNameSorter(const Town * const &a, const Town * const &b, const bool &)
756 {
757 return StrNaturalCompare(a->GetCachedName(), b->GetCachedName()) < 0; // Sort by name (natural sorting).
758 }
759
761 static bool TownPopulationSorter(const Town * const &a, const Town * const &b, const bool &order)
762 {
763 uint32_t a_population = a->cache.population;
764 uint32_t b_population = b->cache.population;
765 if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b, order);
766 return a_population < b_population;
767 }
768
770 static bool TownRatingSorter(const Town * const &a, const Town * const &b, const bool &order)
771 {
772 bool before = !order; // Value to get 'a' before 'b'.
773
774 /* Towns without rating are always after towns with rating. */
777 int16_t a_rating = a->ratings[_local_company];
778 int16_t b_rating = b->ratings[_local_company];
779 if (a_rating == b_rating) return TownDirectoryWindow::TownNameSorter(a, b, order);
780 return a_rating < b_rating;
781 }
782 return before;
783 }
784 if (b->have_ratings.Test(_local_company)) return !before;
785
786 /* Sort unrated towns always on ascending town name. */
787 if (before) return TownDirectoryWindow::TownNameSorter(a, b, order);
788 return TownDirectoryWindow::TownNameSorter(b, a, order);
789 }
790
791public:
793 {
794 this->CreateNestedTree();
795
796 this->vscroll = this->GetScrollbar(WID_TD_SCROLLBAR);
797
798 this->towns.SetListing(this->last_sorting);
800 this->towns.ForceRebuild();
801 this->BuildSortTownList();
802
803 this->FinishInitNested(0);
804
806 this->townname_editbox.cancel_button = QueryString::ACTION_CLEAR;
807 }
808
809 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
810 {
811 switch (widget) {
812 case WID_TD_CAPTION:
813 return GetString(STR_TOWN_DIRECTORY_CAPTION, this->vscroll->GetCount(), Town::GetNumItems());
814
816 return GetString(STR_TOWN_POPULATION, GetWorldPopulation());
817
819 return GetString(TownDirectoryWindow::sorter_names[this->towns.SortType()]);
820
821 default:
822 return this->Window::GetWidgetString(widget, stringid);
823 }
824 }
825
831 static std::string GetTownString(const Town *t, uint64_t population)
832 {
833 return GetString(t->larger_town ? STR_TOWN_DIRECTORY_CITY : STR_TOWN_DIRECTORY_TOWN, t->index, population);
834 }
835
836 void DrawWidget(const Rect &r, WidgetID widget) const override
837 {
838 switch (widget) {
840 this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
841 break;
842
843 case WID_TD_LIST: {
844 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
845 if (this->towns.empty()) { // No towns available.
846 DrawString(tr, STR_TOWN_DIRECTORY_NONE);
847 break;
848 }
849
850 /* At least one town available. */
851 bool rtl = _current_text_dir == TD_RTL;
852 Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD);
853 int icon_x = tr.WithWidth(icon_size.width, rtl).left;
854 tr = tr.Indent(icon_size.width + WidgetDimensions::scaled.hsep_normal, rtl);
855
856 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->towns);
857 for (auto it = first; it != last; ++it) {
858 const Town *t = *it;
859 assert(t->xy != INVALID_TILE);
860
861 /* Draw rating icon. */
862 if (_game_mode == GM_EDITOR || !t->have_ratings.Test(_local_company)) {
863 DrawSprite(SPR_TOWN_RATING_NA, PAL_NONE, icon_x, tr.top + (this->resize.step_height - icon_size.height) / 2);
864 } else {
865 SpriteID icon = SPR_TOWN_RATING_APALLING;
866 if (t->ratings[_local_company] > RATING_VERYPOOR) icon = SPR_TOWN_RATING_MEDIOCRE;
867 if (t->ratings[_local_company] > RATING_GOOD) icon = SPR_TOWN_RATING_GOOD;
868 DrawSprite(icon, PAL_NONE, icon_x, tr.top + (this->resize.step_height - icon_size.height) / 2);
869 }
870
871 DrawString(tr.left, tr.right, tr.top + (this->resize.step_height - GetCharacterHeight(FS_NORMAL)) / 2, GetTownString(t, t->cache.population));
872
873 tr.top += this->resize.step_height;
874 }
875 break;
876 }
877 }
878 }
879
880 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
881 {
882 switch (widget) {
883 case WID_TD_SORT_ORDER: {
884 Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->GetString());
885 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
886 d.height += padding.height;
887 size = maxdim(size, d);
888 break;
889 }
891 Dimension d = GetStringListBoundingBox(TownDirectoryWindow::sorter_names);
892 d.width += padding.width;
893 d.height += padding.height;
894 size = maxdim(size, d);
895 break;
896 }
897 case WID_TD_LIST: {
898 Dimension d = GetStringBoundingBox(STR_TOWN_DIRECTORY_NONE);
899 uint64_t max_value = GetParamMaxDigits(8);
900 for (uint i = 0; i < this->towns.size(); i++) {
901 const Town *t = this->towns[i];
902
903 assert(t != nullptr);
904
905 d = maxdim(d, GetStringBoundingBox(GetTownString(t, max_value)));
906 }
907 Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD);
908 d.width += icon_size.width + 2;
909 d.height = std::max(d.height, icon_size.height);
910 resize.height = d.height;
911 d.height *= 5;
912 d.width += padding.width;
913 d.height += padding.height;
914 size = maxdim(size, d);
915 break;
916 }
918 Dimension d = GetStringBoundingBox(GetString(STR_TOWN_POPULATION, GetParamMaxDigits(10)));
919 d.width += padding.width;
920 d.height += padding.height;
921 size = maxdim(size, d);
922 break;
923 }
924 }
925 }
926
927 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
928 {
929 switch (widget) {
930 case WID_TD_SORT_ORDER: // Click on sort order button
931 if (this->towns.SortType() != 2) { // A different sort than by rating.
932 this->towns.ToggleSortOrder();
933 this->last_sorting = this->towns.GetListing(); // Store new sorting order.
934 } else {
935 /* Some parts are always sorted ascending on name. */
936 this->last_sorting.order = !this->last_sorting.order;
937 this->towns.SetListing(this->last_sorting);
938 this->towns.ForceResort();
939 this->towns.Sort();
940 }
941 this->SetDirty();
942 break;
943
944 case WID_TD_SORT_CRITERIA: // Click on sort criteria dropdown
945 ShowDropDownMenu(this, TownDirectoryWindow::sorter_names, this->towns.SortType(), WID_TD_SORT_CRITERIA, 0, 0);
946 break;
947
948 case WID_TD_LIST: { // Click on Town Matrix
949 auto it = this->vscroll->GetScrolledItemFromWidget(this->towns, pt.y, this, WID_TD_LIST, WidgetDimensions::scaled.framerect.top);
950 if (it == this->towns.end()) return; // click out of town bounds
951
952 const Town *t = *it;
953 assert(t != nullptr);
954 if (_ctrl_pressed) {
956 } else {
958 }
959 break;
960 }
961 }
962 }
963
964 void OnDropdownSelect(WidgetID widget, int index, int) override
965 {
966 if (widget != WID_TD_SORT_CRITERIA) return;
967
968 if (this->towns.SortType() != index) {
969 this->towns.SetSortType(index);
970 this->last_sorting = this->towns.GetListing(); // Store new sorting order.
971 this->BuildSortTownList();
972 }
973 }
974
975 void OnPaint() override
976 {
977 if (this->towns.NeedRebuild()) this->BuildSortTownList();
978 this->DrawWidgets();
979 }
980
982 const IntervalTimer<TimerWindow> rebuild_interval = {std::chrono::seconds(3), [this](auto) {
983 this->BuildSortTownList();
984 this->SetDirty();
985 }};
986
987 void OnResize() override
988 {
989 this->vscroll->SetCapacityFromWidget(this, WID_TD_LIST, WidgetDimensions::scaled.framerect.Vertical());
990 }
991
992 void OnEditboxChanged(WidgetID wid) override
993 {
994 if (wid == WID_TD_FILTER) {
995 this->string_filter.SetFilterTerm(this->townname_editbox.text.GetText());
996 this->InvalidateData(TDIWD_FORCE_REBUILD);
997 }
998 }
999
1005 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1006 {
1007 switch (data) {
1008 case TDIWD_FORCE_REBUILD:
1009 /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
1010 this->towns.ForceRebuild();
1011 break;
1012
1013 case TDIWD_POPULATION_CHANGE:
1014 if (this->towns.SortType() == 1) this->towns.ForceResort();
1015 break;
1016
1017 default:
1018 this->towns.ForceResort();
1019 }
1020 }
1021
1022 EventState OnHotkey(int hotkey) override
1023 {
1024 switch (hotkey) {
1027 SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused.
1028 break;
1029 default:
1030 return ES_NOT_HANDLED;
1031 }
1032 return ES_HANDLED;
1033 }
1034
1035 static inline HotkeyList hotkeys {"towndirectory", {
1036 Hotkey('F', "focus_filter_box", TDHK_FOCUS_FILTER_BOX),
1037 }};
1038};
1039
1040Listing TownDirectoryWindow::last_sorting = {false, 0};
1041
1043const std::initializer_list<GUITownList::SortFunction * const> TownDirectoryWindow::sorter_funcs = {
1044 &TownNameSorter,
1045 &TownPopulationSorter,
1046 &TownRatingSorter,
1047};
1048
1049static WindowDesc _town_directory_desc(
1050 WDP_AUTO, "list_towns", 208, 202,
1052 {},
1053 _nested_town_directory_widgets,
1054 &TownDirectoryWindow::hotkeys
1055);
1056
1057void ShowTownDirectory()
1058{
1060 new TownDirectoryWindow(_town_directory_desc);
1061}
1062
1063void CcFoundTown(Commands, const CommandCost &result, TileIndex tile)
1064{
1065 if (result.Failed()) return;
1066
1067 if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, tile);
1069}
1070
1071void CcFoundRandomTown(Commands, const CommandCost &result, Money, TownID town_id)
1072{
1073 if (result.Succeeded()) ScrollMainWindowToTile(Town::Get(town_id)->xy);
1074}
1075
1076static constexpr NWidgetPart _nested_found_town_widgets[] = {
1078 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
1079 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_FOUND_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1080 NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
1081 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
1082 EndContainer(),
1083 /* Construct new town(s) buttons. */
1084 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
1086 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_NEW_TOWN), SetStringTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetFill(1, 0),
1089 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetStringTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetFill(1, 0),
1090 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetStringTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetFill(1, 0),
1091 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_LOAD_FROM_FILE), SetStringTip(STR_FOUND_TOWN_LOAD_FROM_FILE, STR_FOUND_TOWN_LOAD_FROM_FILE_TOOLTIP), SetFill(1, 0),
1092 EndContainer(),
1093 EndContainer(),
1094
1095 /* Town name selection. */
1096 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_FOUND_TOWN_NAME_TITLE),
1097 NWidget(WWT_EDITBOX, COLOUR_GREY, WID_TF_TOWN_NAME_EDITBOX), SetStringTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_TOOLTIP), SetFill(1, 0),
1098 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_TOWN_NAME_RANDOM), SetStringTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP), SetFill(1, 0),
1099
1100 /* Town size selection. */
1101 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE),
1104 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_SMALL), SetStringTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1105 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_MEDIUM), SetStringTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1106 EndContainer(),
1108 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_TF_SIZE_SEL),
1109 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_LARGE), SetStringTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1110 EndContainer(),
1111 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_RANDOM), SetStringTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1112 EndContainer(),
1113 EndContainer(),
1114 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_CITY), SetStringTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0),
1115
1116 /* Town roads selection. */
1119 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_FOUND_TOWN_ROAD_LAYOUT),
1122 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_ORIGINAL), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1123 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_BETTER), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1124 EndContainer(),
1126 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID2), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1127 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID3), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1128 EndContainer(),
1129 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_RANDOM), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1130 EndContainer(),
1131 EndContainer(),
1132 EndContainer(),
1133
1134 /* Town expansion selection. */
1137 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_FOUND_TOWN_EXPAND_MODE),
1138 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_EXPAND_ALL_TOWNS), SetStringTip(STR_FOUND_TOWN_EXPAND_ALL_TOWNS, STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP), SetFill(1, 0),
1140 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_EXPAND_BUILDINGS), SetStringTip(STR_FOUND_TOWN_EXPAND_BUILDINGS, STR_FOUND_TOWN_EXPAND_BUILDINGS_TOOLTIP), SetFill(1, 0),
1141 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_EXPAND_ROADS), SetStringTip(STR_FOUND_TOWN_EXPAND_ROADS, STR_FOUND_TOWN_EXPAND_ROADS_TOOLTIP), SetFill(1, 0),
1142 EndContainer(),
1143 EndContainer(),
1144 EndContainer(),
1145 EndContainer(),
1146 EndContainer(),
1147};
1148
1151private:
1154 bool city = false;
1156 bool townnamevalid = false;
1157 uint32_t townnameparts = 0;
1160
1161public:
1163 Window(desc),
1166 params(_settings_game.game_creation.town_name)
1167 {
1168 this->InitNested(window_number);
1170 this->RandomTownName();
1171 this->UpdateButtons(true);
1172 }
1173
1174 void OnInit() override
1175 {
1176 if (_game_mode == GM_EDITOR) return;
1177
1178 this->GetWidget<NWidgetStacked>(WID_TF_TOWN_ACTION_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL);
1179 this->GetWidget<NWidgetStacked>(WID_TF_TOWN_EXPAND_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL);
1180 this->GetWidget<NWidgetStacked>(WID_TF_SIZE_SEL)->SetDisplayedPlane(SZSP_VERTICAL);
1182 this->GetWidget<NWidgetStacked>(WID_TF_ROAD_LAYOUT_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL);
1183 } else {
1184 this->GetWidget<NWidgetStacked>(WID_TF_ROAD_LAYOUT_SEL)->SetDisplayedPlane(0);
1185 }
1186 }
1187
1188 void RandomTownName()
1189 {
1190 this->townnamevalid = GenerateTownName(_interactive_random, &this->townnameparts);
1191
1192 if (!this->townnamevalid) {
1193 this->townname_editbox.text.DeleteAll();
1194 } else {
1195 this->townname_editbox.text.Assign(GetTownName(&this->params, this->townnameparts));
1196 }
1198
1200 }
1201
1202 void UpdateButtons(bool check_availability)
1203 {
1204 if (check_availability && _game_mode != GM_EDITOR) {
1206 this->ReInit();
1207 }
1208
1209 for (WidgetID i = WID_TF_SIZE_SMALL; i <= WID_TF_SIZE_RANDOM; i++) {
1210 this->SetWidgetLoweredState(i, i == WID_TF_SIZE_SMALL + this->town_size);
1211 }
1212
1213 this->SetWidgetLoweredState(WID_TF_CITY, this->city);
1214
1217 }
1218
1219 this->SetWidgetLoweredState(WID_TF_EXPAND_BUILDINGS, FoundTownWindow::expand_modes.Test(TownExpandMode::Buildings));
1220 this->SetWidgetLoweredState(WID_TF_EXPAND_ROADS, FoundTownWindow::expand_modes.Test(TownExpandMode::Roads));
1221
1222 this->SetDirty();
1223 }
1224
1225 template <typename Tcallback>
1226 void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, Tcallback cc)
1227 {
1228 std::string name;
1229
1230 if (!this->townnamevalid) {
1231 name = this->townname_editbox.text.GetText();
1232 } else {
1233 /* If user changed the name, send it */
1234 std::string original_name = GetTownName(&this->params, this->townnameparts);
1235 if (original_name != this->townname_editbox.text.GetText()) name = this->townname_editbox.text.GetText();
1236 }
1237
1238 bool success = Command<CMD_FOUND_TOWN>::Post(errstr, cc,
1239 tile, this->town_size, this->city, this->town_layout, random, townnameparts, name);
1240
1241 /* Rerandomise name, if success and no cost-estimation. */
1242 if (success && !_shift_pressed) this->RandomTownName();
1243 }
1244
1245 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1246 {
1247 switch (widget) {
1248 case WID_TF_NEW_TOWN:
1249 HandlePlacePushButton(this, WID_TF_NEW_TOWN, SPR_CURSOR_TOWN, HT_RECT);
1250 break;
1251
1252 case WID_TF_RANDOM_TOWN:
1253 this->ExecuteFoundTownCommand(TileIndex{}, true, STR_ERROR_CAN_T_GENERATE_TOWN, CcFoundRandomTown);
1254 break;
1255
1257 this->RandomTownName();
1259 break;
1260
1262 std::string default_town_number = fmt::format("{}", GetDefaultTownsForMapSize());
1263 ShowQueryString(default_town_number, STR_MAPGEN_NUMBER_OF_TOWNS, 5, this, CS_NUMERAL, {QueryStringFlag::AcceptUnchanged});
1264 break;
1265 }
1268 break;
1269
1271 for (Town *t : Town::Iterate()) {
1272 Command<CMD_EXPAND_TOWN>::Do(DoCommandFlag::Execute, t->index, 0, FoundTownWindow::expand_modes);
1273 }
1274 break;
1275
1277 this->town_size = (TownSize)(widget - WID_TF_SIZE_SMALL);
1278 this->UpdateButtons(false);
1279 break;
1280
1281 case WID_TF_CITY:
1282 this->city ^= true;
1283 this->SetWidgetLoweredState(WID_TF_CITY, this->city);
1284 this->SetDirty();
1285 break;
1286
1288 FoundTownWindow::expand_modes.Flip(TownExpandMode::Buildings);
1289 this->UpdateButtons(false);
1290 break;
1291
1293 FoundTownWindow::expand_modes.Flip(TownExpandMode::Roads);
1294 this->UpdateButtons(false);
1295 break;
1296
1299 this->town_layout = (TownLayout)(widget - WID_TF_LAYOUT_ORIGINAL);
1300
1301 /* If we are in the editor, sync the settings of the current game to the chosen layout,
1302 * so that importing towns from file uses the selected layout. */
1303 if (_game_mode == GM_EDITOR) _settings_game.economy.town_layout = this->town_layout;
1304
1305 this->UpdateButtons(false);
1306 break;
1307 }
1308 }
1309
1310 void OnQueryTextFinished(std::optional<std::string> str) override
1311 {
1312 /* Was 'cancel' pressed? */
1313 if (!str.has_value()) return;
1314
1315 auto value = ParseInteger(*str, 10, true);
1316 if (!value.has_value()) return;
1317
1318 Backup<bool> old_generating_world(_generating_world, true);
1320 if (!GenerateTowns(this->town_layout, value)) {
1321 ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_GENERATE_TOWN), GetEncodedString(STR_ERROR_NO_SPACE_FOR_TOWN), WL_INFO);
1322 }
1324 old_generating_world.Restore();
1325 }
1326
1327 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
1328 {
1329 this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown);
1330 }
1331
1332 void OnPlaceObjectAbort() override
1333 {
1334 this->RaiseButtons();
1335 this->UpdateButtons(false);
1336 }
1337
1343 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1344 {
1345 if (!gui_scope) return;
1346 this->UpdateButtons(true);
1347 }
1348};
1349
1350static WindowDesc _found_town_desc(
1351 WDP_AUTO, "build_town", 160, 162,
1354 _nested_found_town_widgets
1355);
1356
1357void ShowFoundTownWindow()
1358{
1359 if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
1360 AllocateWindowDescFront<FoundTownWindow>(_found_town_desc, 0);
1361}
1362
1363void InitializeTownGui()
1364{
1365 _town_local_authority_kdtree.Clear();
1366}
1367
1375void DrawHouseInGUI(int x, int y, HouseID house_id, int view)
1376{
1377 auto draw = [](int x, int y, HouseID house_id, int view) {
1378 if (house_id >= NEW_HOUSE_OFFSET) {
1379 /* Houses don't necessarily need new graphics. If they don't have a
1380 * spritegroup associated with them, then the sprite for the substitute
1381 * house id is drawn instead. */
1382 const HouseSpec *spec = HouseSpec::Get(house_id);
1383 if (spec->grf_prop.HasSpriteGroups()) {
1384 DrawNewHouseTileInGUI(x, y, spec, house_id, view);
1385 return;
1386 } else {
1387 house_id = HouseSpec::Get(house_id)->grf_prop.subst_id;
1388 }
1389 }
1390
1391 /* Retrieve data from the draw town tile struct */
1392 const DrawBuildingsTileStruct &dcts = GetTownDrawTileData()[house_id << 4 | view << 2 | TOWN_HOUSE_COMPLETED];
1393 DrawSprite(dcts.ground.sprite, dcts.ground.pal, x, y);
1394
1395 /* Add a house on top of the ground? */
1396 if (dcts.building.sprite != 0) {
1397 Point pt = RemapCoords(dcts.subtile_x, dcts.subtile_y, 0);
1398 DrawSprite(dcts.building.sprite, dcts.building.pal, x + ScaleSpriteTrad(pt.x), y + ScaleSpriteTrad(pt.y));
1399 }
1400 };
1401
1402 /* Houses can have 1x1, 1x2, 2x1 and 2x2 layouts which are individual HouseIDs. For the GUI we need
1403 * draw all of the tiles with appropriate positions. */
1404 int x_delta = ScaleSpriteTrad(TILE_PIXELS);
1405 int y_delta = ScaleSpriteTrad(TILE_PIXELS / 2);
1406
1407 const HouseSpec *hs = HouseSpec::Get(house_id);
1408 if (hs->building_flags.Test(BuildingFlag::Size2x2)) {
1409 draw(x, y - y_delta - y_delta, house_id, view); // North corner.
1410 draw(x + x_delta, y - y_delta, house_id + 1, view); // West corner.
1411 draw(x - x_delta, y - y_delta, house_id + 2, view); // East corner.
1412 draw(x, y, house_id + 3, view); // South corner.
1413 } else if (hs->building_flags.Test(BuildingFlag::Size2x1)) {
1414 draw(x + x_delta / 2, y - y_delta, house_id, view); // North east tile.
1415 draw(x - x_delta / 2, y, house_id + 1, view); // South west tile.
1416 } else if (hs->building_flags.Test(BuildingFlag::Size1x2)) {
1417 draw(x - x_delta / 2, y - y_delta, house_id, view); // North west tile.
1418 draw(x + x_delta / 2, y, house_id + 1, view); // South east tile.
1419 } else {
1420 draw(x, y, house_id, view);
1421 }
1422}
1423
1430{
1431 std::array<int32_t, 1> regs100;
1432 uint16_t callback_res = GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, 1, 0, hs->Index(), nullptr, INVALID_TILE, regs100, true);
1433 if (callback_res != CALLBACK_FAILED && callback_res != 0x400) {
1434 StringID new_name = STR_NULL;
1435 if (callback_res == 0x40F) {
1436 new_name = GetGRFStringID(hs->grf_prop.grffile->grfid, static_cast<GRFStringID>(regs100[0]));
1437 } else if (callback_res > 0x400) {
1439 } else {
1440 new_name = GetGRFStringID(hs->grf_prop.grffile->grfid, GRFSTR_MISC_GRF_TEXT + callback_res);
1441 }
1442 if (new_name != STR_NULL && new_name != STR_UNDEFINED) {
1443 return new_name;
1444 }
1445 }
1446
1447 return hs->building_name;
1448}
1449
1451public:
1452 HousePickerCallbacks() : PickerCallbacks("fav_houses") {}
1453
1458 {
1459 this->climate_mask = GetClimateMaskForLandscape();
1460
1461 /* In some cases, not all 'classes' (house zones) have distinct houses, so we need to disable those.
1462 * As we need to check all types, and this cannot change with the picker window open, pre-calculate it.
1463 * This loop calls GetTypeName() instead of directly checking properties so that there is no discrepancy. */
1464 this->class_mask = 0;
1465
1466 int num_classes = this->GetClassCount();
1467 for (int cls_id = 0; cls_id < num_classes; ++cls_id) {
1468 int num_types = this->GetTypeCount(cls_id);
1469 for (int id = 0; id < num_types; ++id) {
1470 if (this->GetTypeName(cls_id, id) != INVALID_STRING_ID) {
1471 SetBit(this->class_mask, cls_id);
1472 break;
1473 }
1474 }
1475 }
1476 }
1477
1478 HouseZones climate_mask{};
1479 uint8_t class_mask = 0;
1480
1481 static inline int sel_class;
1482 static inline int sel_type;
1483 static inline int sel_view;
1484
1485 /* Houses do not have classes like NewGRFClass. We'll make up fake classes based on town zone
1486 * availability instead. */
1487 static inline const std::array<StringID, NUM_HOUSE_ZONES> zone_names = {
1488 STR_HOUSE_PICKER_CLASS_ZONE1,
1489 STR_HOUSE_PICKER_CLASS_ZONE2,
1490 STR_HOUSE_PICKER_CLASS_ZONE3,
1491 STR_HOUSE_PICKER_CLASS_ZONE4,
1492 STR_HOUSE_PICKER_CLASS_ZONE5,
1493 };
1494
1495 GrfSpecFeature GetFeature() const override { return GSF_HOUSES; }
1496
1497 StringID GetClassTooltip() const override { return STR_PICKER_HOUSE_CLASS_TOOLTIP; }
1498 StringID GetTypeTooltip() const override { return STR_PICKER_HOUSE_TYPE_TOOLTIP; }
1499 bool IsActive() const override { return true; }
1500
1501 bool HasClassChoice() const override { return true; }
1502 int GetClassCount() const override { return static_cast<int>(zone_names.size()); }
1503
1504 void Close([[maybe_unused]] int data) override { ResetObjectToPlace(); }
1505
1506 int GetSelectedClass() const override { return HousePickerCallbacks::sel_class; }
1507 void SetSelectedClass(int cls_id) const override { HousePickerCallbacks::sel_class = cls_id; }
1508
1509 StringID GetClassName(int id) const override
1510 {
1511 if (id >= GetClassCount()) return INVALID_STRING_ID;
1512 if (!HasBit(this->class_mask, id)) return INVALID_STRING_ID;
1513 return zone_names[id];
1514 }
1515
1516 int GetTypeCount(int cls_id) const override
1517 {
1518 if (cls_id < GetClassCount()) return static_cast<int>(HouseSpec::Specs().size());
1519 return 0;
1520 }
1521
1522 PickerItem GetPickerItem(int cls_id, int id) const override
1523 {
1524 const auto *spec = HouseSpec::Get(id);
1525 if (!spec->grf_prop.HasGrfFile()) return {0, spec->Index(), cls_id, id};
1526 return {spec->grf_prop.grfid, spec->grf_prop.local_id, cls_id, id};
1527 }
1528
1529 int GetSelectedType() const override { return sel_type; }
1530 void SetSelectedType(int id) const override { sel_type = id; }
1531
1532 static HouseZone GetHouseZoneFromClassId(int cls_id) { return static_cast<HouseZone>(to_underlying(HouseZone::TownEdge) + cls_id); }
1533 static int GetClassIdFromHouseZone(HouseZones zones) { return FindFirstBit((zones & HZ_ZONE_ALL).base()) - to_underlying(HouseZone::TownEdge); }
1534
1535 StringID GetTypeName(int cls_id, int id) const override
1536 {
1537 const HouseSpec *spec = HouseSpec::Get(id);
1538 if (spec == nullptr) return INVALID_STRING_ID;
1539 if (!spec->enabled) return INVALID_STRING_ID;
1540 if (!spec->building_availability.Any(climate_mask)) return INVALID_STRING_ID;
1541 if (!spec->building_availability.Test(GetHouseZoneFromClassId(cls_id))) return INVALID_STRING_ID;
1542 for (int i = 0; i < cls_id; i++) {
1543 /* Don't include if it's already included in an earlier zone. */
1544 if (spec->building_availability.Test(GetHouseZoneFromClassId(i))) return INVALID_STRING_ID;
1545 }
1546
1547 return GetHouseName(spec);
1548 }
1549
1550 std::span<const BadgeID> GetTypeBadges(int cls_id, int id) const override
1551 {
1552 const auto *spec = HouseSpec::Get(id);
1553 if (spec == nullptr) return {};
1554 if (!spec->enabled) return {};
1555 if (!spec->building_availability.Any(climate_mask)) return {};
1556 if (!spec->building_availability.Test(GetHouseZoneFromClassId(cls_id))) return {};
1557 for (int i = 0; i < cls_id; i++) {
1558 /* Don't include if it's already included in an earlier zone. */
1559 if (spec->building_availability.Test(GetHouseZoneFromClassId(i))) return {};
1560 }
1561
1562 return spec->badges;
1563 }
1564
1565 bool IsTypeAvailable(int, int id) const override
1566 {
1567 const HouseSpec *hs = HouseSpec::Get(id);
1568 return hs->enabled;
1569 }
1570
1571 void DrawType(int x, int y, int, int id) const override
1572 {
1574 }
1575
1576 void FillUsedItems(std::set<PickerItem> &items) override
1577 {
1578 auto id_count = GetBuildingHouseIDCounts();
1579 for (auto it = id_count.begin(); it != id_count.end(); ++it) {
1580 if (*it == 0) continue;
1581 HouseID house = static_cast<HouseID>(std::distance(id_count.begin(), it));
1582 const HouseSpec *hs = HouseSpec::Get(house);
1583 int class_index = GetClassIdFromHouseZone(hs->building_availability);
1584 items.insert({0, house, class_index, house});
1585 }
1586 }
1587
1588 std::set<PickerItem> UpdateSavedItems(const std::set<PickerItem> &src) override
1589 {
1590 if (src.empty()) return src;
1591
1592 const auto &specs = HouseSpec::Specs();
1593 std::set<PickerItem> dst;
1594 for (const auto &item : src) {
1595 if (item.grfid == 0) {
1596 dst.insert(item);
1597 } else {
1598 /* Search for spec by grfid and local index. */
1599 auto it = std::ranges::find_if(specs, [&item](const HouseSpec &spec) { return spec.grf_prop.grfid == item.grfid && spec.grf_prop.local_id == item.local_id; });
1600 if (it == specs.end()) {
1601 /* Not preset, hide from UI. */
1602 dst.insert({item.grfid, item.local_id, -1, -1});
1603 } else {
1604 int class_index = GetClassIdFromHouseZone(it->building_availability);
1605 dst.insert( {item.grfid, item.local_id, class_index, it->Index()});
1606 }
1607 }
1608 }
1609
1610 return dst;
1611 }
1612
1613 static HousePickerCallbacks instance;
1614};
1615/* static */ HousePickerCallbacks HousePickerCallbacks::instance;
1616
1622static CargoTypes GetProducedCargoOfHouse(const HouseSpec *hs)
1623{
1624 CargoTypes produced{};
1626 for (uint i = 0; i < 256; i++) {
1627 uint16_t callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, hs->Index(), nullptr, INVALID_TILE, {}, true);
1628
1629 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
1630
1631 CargoType cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grf_prop.grffile);
1632 if (!IsValidCargoType(cargo)) continue;
1633
1634 uint amt = GB(callback, 0, 8);
1635 if (amt == 0) continue;
1636
1637 SetBit(produced, cargo);
1638 }
1639 } else {
1640 /* Cargo is not controlled by NewGRF, town production effect is used instead. */
1641 for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_PASSENGERS]) SetBit(produced, cs->Index());
1642 for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_MAIL]) SetBit(produced, cs->Index());
1643 }
1644 return produced;
1645}
1646
1648 std::string house_info{};
1649 bool house_protected = false;
1650
1651 BuildHouseWindow(WindowDesc &desc, Window *parent) : PickerWindow(desc, parent, 0, HousePickerCallbacks::instance)
1652 {
1653 HousePickerCallbacks::instance.SetClimateMask();
1654 this->ConstructWindow();
1655 }
1656
1657 void UpdateSelectSize(const HouseSpec *spec)
1658 {
1659 if (spec == nullptr) {
1660 SetTileSelectSize(1, 1);
1662 } else {
1663 SetObjectToPlaceWnd(SPR_CURSOR_TOWN, PAL_NONE, HT_RECT | HT_DIAGONAL, this);
1664 if (spec->building_flags.Test(BuildingFlag::Size2x2)) {
1665 SetTileSelectSize(2, 2);
1666 } else if (spec->building_flags.Test(BuildingFlag::Size2x1)) {
1667 SetTileSelectSize(2, 1);
1668 } else if (spec->building_flags.Test(BuildingFlag::Size1x2)) {
1669 SetTileSelectSize(1, 2);
1670 } else if (spec->building_flags.Test(BuildingFlag::Size1x1)) {
1671 SetTileSelectSize(1, 1);
1672 }
1673 }
1674 }
1675
1682 static std::string GetHouseYear(TimerGameCalendar::Year min_year, TimerGameCalendar::Year max_year)
1683 {
1684 if (min_year == CalendarTime::MIN_YEAR) {
1685 if (max_year == CalendarTime::MAX_YEAR) {
1686 return GetString(STR_HOUSE_PICKER_YEARS_ANY);
1687 }
1688 return GetString(STR_HOUSE_PICKER_YEARS_UNTIL, max_year);
1689 }
1690 if (max_year == CalendarTime::MAX_YEAR) {
1691 return GetString(STR_HOUSE_PICKER_YEARS_FROM, min_year);
1692 }
1693 return GetString(STR_HOUSE_PICKER_YEARS, min_year, max_year);
1694 }
1695
1701 static std::string GetHouseInformation(const HouseSpec *hs)
1702 {
1703 std::stringstream line;
1704
1705 line << GetString(STR_HOUSE_PICKER_NAME, GetHouseName(hs));
1706 line << "\n";
1707
1708 line << GetString(STR_HOUSE_PICKER_POPULATION, hs->population);
1709 line << "\n";
1710
1711 line << GetHouseYear(hs->min_year, hs->max_year);
1712 line << "\n";
1713
1714 uint8_t size = 0;
1715 if (hs->building_flags.Test(BuildingFlag::Size1x1)) size = 0x11;
1716 if (hs->building_flags.Test(BuildingFlag::Size2x1)) size = 0x21;
1717 if (hs->building_flags.Test(BuildingFlag::Size1x2)) size = 0x12;
1718 if (hs->building_flags.Test(BuildingFlag::Size2x2)) size = 0x22;
1719 line << GetString(STR_HOUSE_PICKER_SIZE, GB(size, 0, 4), GB(size, 4, 4));
1720
1721 auto cargo_string = BuildCargoAcceptanceString(GetAcceptedCargoOfHouse(hs), STR_HOUSE_PICKER_CARGO_ACCEPTED);
1722 if (cargo_string.has_value()) {
1723 line << "\n";
1724 line << *cargo_string;
1725 }
1726
1727 CargoTypes produced = GetProducedCargoOfHouse(hs);
1728 if (produced != 0) {
1729 line << "\n";
1730 line << GetString(STR_HOUSE_PICKER_CARGO_PRODUCED, produced);
1731 }
1732
1733 return line.str();
1734 }
1735
1736 void OnInit() override
1737 {
1738 this->InvalidateData(PICKER_INVALIDATION_ALL);
1739 this->PickerWindow::OnInit();
1740 }
1741
1742 void DrawWidget(const Rect &r, WidgetID widget) const override
1743 {
1744 if (widget == WID_BH_INFO) {
1745 if (!this->house_info.empty()) DrawStringMultiLine(r, this->house_info);
1746 } else {
1747 this->PickerWindow::DrawWidget(r, widget);
1748 }
1749 }
1750
1751 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1752 {
1753 switch (widget) {
1754 case WID_BH_PROTECT_OFF:
1755 case WID_BH_PROTECT_ON:
1756 this->house_protected = (widget == WID_BH_PROTECT_ON);
1757 this->SetWidgetLoweredState(WID_BH_PROTECT_OFF, !this->house_protected);
1758 this->SetWidgetLoweredState(WID_BH_PROTECT_ON, this->house_protected);
1759
1761 this->SetDirty();
1762 break;
1763
1764 default:
1765 this->PickerWindow::OnClick(pt, widget, click_count);
1766 break;
1767 }
1768 }
1769
1770 void OnInvalidateData(int data = 0, bool gui_scope = true) override
1771 {
1772 this->PickerWindow::OnInvalidateData(data, gui_scope);
1773 if (!gui_scope) return;
1774
1776
1777 PickerInvalidations pi(data);
1779 UpdateSelectSize(spec);
1780 this->house_info = GetHouseInformation(spec);
1781 }
1782
1783 /* If house spec already has the protected flag, handle it automatically and disable the buttons. */
1785 if (hasflag) this->house_protected = true;
1786
1787 this->SetWidgetLoweredState(WID_BH_PROTECT_OFF, !this->house_protected);
1788 this->SetWidgetLoweredState(WID_BH_PROTECT_ON, this->house_protected);
1789
1792 }
1793
1794 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
1795 {
1797 Command<CMD_PLACE_HOUSE>::Post(STR_ERROR_CAN_T_BUILD_HOUSE, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index(), this->house_protected);
1798 }
1799
1800 const IntervalTimer<TimerWindow> view_refresh_interval = {std::chrono::milliseconds(2500), [this](auto) {
1801 /* There are four different 'views' that are random based on house tile position. As this is not
1802 * user-controllable, instead we automatically cycle through them. */
1804 this->SetDirty();
1805 }};
1806
1807 static inline HotkeyList hotkeys{"buildhouse", {
1808 Hotkey('F', "focus_filter_box", PCWHK_FOCUS_FILTER_BOX),
1809 }};
1810};
1811
1815 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
1816 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_HOUSE_PICKER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1817 NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
1818 NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
1819 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
1820 EndContainer(),
1824 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
1826 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BH_INFO), SetFill(1, 1), SetMinimalTextLines(10, 0),
1827 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_HOUSE_PICKER_PROTECT_TITLE, STR_NULL), SetFill(1, 0),
1829 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BH_PROTECT_OFF), SetMinimalSize(60, 12), SetStringTip(STR_HOUSE_PICKER_PROTECT_OFF, STR_HOUSE_PICKER_PROTECT_TOOLTIP),
1830 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BH_PROTECT_ON), SetMinimalSize(60, 12), SetStringTip(STR_HOUSE_PICKER_PROTECT_ON, STR_HOUSE_PICKER_PROTECT_TOOLTIP),
1831 EndContainer(),
1832 EndContainer(),
1833 EndContainer(),
1834
1835 EndContainer(),
1837 EndContainer(),
1838};
1839
1840static WindowDesc _build_house_desc(
1841 WDP_AUTO, "build_house", 0, 0,
1845 &BuildHouseWindow::hotkeys
1846);
1847
1848void ShowBuildHousePicker(Window *parent)
1849{
1850 if (BringWindowToFrontById(WC_BUILD_HOUSE, 0)) return;
1851 new BuildHouseWindow(_build_house_desc, parent);
1852}
Class for backupping variables and making sure they are restored later.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
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.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
std::optional< std::string > BuildCargoAcceptanceString(const CargoArray &acceptance, StringID label)
Build comma-separated cargo acceptance string.
@ TPE_PASSENGERS
Cargo behaves passenger-like for production.
Definition cargotype.h:37
@ TPE_MAIL
Cargo behaves mail-like for production.
Definition cargotype.h:38
TownAcceptanceEffect
Town growth effect when delivering cargo.
Definition cargotype.h:22
@ TAE_END
End of town effects.
Definition cargotype.h:30
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Flip(Tvalue_type value)
Flip the value-th bit.
constexpr Timpl & Set()
Set all bits.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
std::optional< Tvalue_type > GetNthSetBit(uint n) const
Get the value of the Nth set bit.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
bool Failed() const
Did this command fail?
std::string GetDecodedString() const
Decode the encoded string.
Definition strings.cpp:208
List template of 'things' T to sort in a GUI.
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.
bool IsActive() const override
Should picker class/type selection be enabled?
void SetClimateMask()
Set climate mask for filtering buildings from current landscape.
void SetSelectedClass(int cls_id) const override
Set the selected class.
StringID GetClassTooltip() const override
Get the tooltip string for the class list.
std::span< const BadgeID > GetTypeBadges(int cls_id, int id) const override
Get the item of a type.
void DrawType(int x, int y, int, int id) const override
Draw preview image of an item.
static int sel_view
Currently selected 'view'. This is not controllable as its based on random data.
int GetClassCount() const override
Get the number of classes.
void FillUsedItems(std::set< PickerItem > &items) override
Fill a set with all items that are used by the current player.
static int sel_type
Currently selected HouseID.
int GetSelectedClass() const override
Get the index of the selected class.
std::set< PickerItem > UpdateSavedItems(const std::set< PickerItem > &src) override
Update link between grfid/localidx and class_index/index in saved items.
StringID GetTypeTooltip() const override
Get the tooltip string for the type grid.
void SetSelectedType(int id) const override
Set the selected type.
StringID GetTypeName(int cls_id, int id) const override
Get the item of a type.
int GetSelectedType() const override
Get the selected type.
bool IsTypeAvailable(int, int id) const override
Test if an item is currently buildable.
bool HasClassChoice() const override
Are there multiple classes to chose from?
uint8_t class_mask
Mask of available 'classes'.
int GetTypeCount(int cls_id) const override
Get the number of types in a class.
StringID GetClassName(int id) const override
Get the name of a class.
static int sel_class
Currently selected 'class'.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
K-dimensional tree, specialised for 2-dimensional space.
Definition kdtree.hpp:33
void Insert(const T &element)
Insert a single element in the tree.
Definition kdtree.hpp:396
void Remove(const T &element)
Remove a single element from the tree, if it exists.
Definition kdtree.hpp:415
void Clear()
Clear the tree.
Definition kdtree.hpp:375
Baseclass for nested widgets.
uint current_x
Current horizontal size (after resizing).
uint smallest_y
Smallest vertical size of the widget in a filled window.
uint current_y
Current vertical size (after resizing).
Nested widget to display a viewport in a window.
void UpdateViewportCoordinates(Window *w)
Update the position and size of the viewport (after eg a resize).
Definition widget.cpp:2411
void InitializeViewport(Window *w, std::variant< TileIndex, VehicleID > focus, ZoomLevel zoom)
Initialize the viewport of the window.
Definition widget.cpp:2402
Class for PickerClassWindow to collect information and retain state.
Definition picker_gui.h:39
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
@ Position
Update scroll positions.
@ PCWHK_FOCUS_FILTER_BOX
Focus the edit box for editing the filter string.
Definition picker_gui.h:198
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnInit() override
Notification that the nested widget tree gets initialized.
Scrollbar data structure.
void SetCount(size_t num)
Sets the number of elements in the list.
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.
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:2508
size_type GetCount() const
Gets the number of elements in the list.
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static constexpr TimerGame< struct Calendar >::Year MIN_YEAR
The absolute minimum year in OTTD.
static constexpr TimerGame< struct Calendar >::Year MAX_YEAR
MAX_YEAR, nicely rounded value of the number of years that can be encoded in a single 32 bits date,...
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:40
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
int vsep_normal
Normal vertical spacing.
Definition window_gui.h:58
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
Functions related to commands.
@ Execute
execute the given command
Commands
List of commands.
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.
PaletteID GetCompanyPalette(CompanyID company)
Get the palette for recolouring with a company colour.
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.
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:451
Functions related to the drop down widget.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
Functions related to errors.
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition error.h:24
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
@ SLO_LOAD
File is being loaded.
Definition fileio_type.h:54
@ FT_TOWN_DATA
town data file
Definition fileio_type.h:22
Declarations for savegames operations.
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Launch save/load dialog in the given mode.
Definition fios_gui.cpp:984
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:74
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:705
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:958
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:887
Dimension GetStringListBoundingBox(std::span< const StringID > list, FontSize fontsize)
Get maximum dimension of a list of strings.
Definition gfx.cpp:925
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:658
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:1024
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion)
Calculate string bounding box for multi-line strings.
Definition gfx.cpp:741
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:775
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:251
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:302
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition gfx_type.h:326
constexpr NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
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.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlag::ResizeX)
Widget part function for setting the aspect ratio.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
constexpr NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post)
Widget part function for setting a pre/inter/post ratio.
uint8_t LowestSnowLine()
Get the lowest possible snow line height, either variable or static.
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:955
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1535
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
@ BuildingIsProtected
towns and AI will not remove this house, while human players will be able to
HouseZones GetClimateMaskForLandscape()
Get the HouseZones climate mask for the current landscape type.
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:25
HouseZone
Definition house.h:55
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.
void ShowQueryString(std::string_view str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
bool _networking
are we in networking mode?
Definition network.cpp:67
bool _network_server
network-server is active
Definition network.cpp:68
Basic functions/variables used all over the place.
GrfSpecFeature
Definition newgrf.h:69
@ CBID_HOUSE_CUSTOM_NAME
Called on the Get Tile Description for an house tile.
@ CBID_HOUSE_PRODUCE_CARGO
Called to determine how much cargo a town building produces.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
@ ProduceCargo
custom cargo production
static const uint CALLBACK_HOUSEPRODCARGO_END
Sentinel indicating that the loop for CBID_HOUSE_PRODUCE_CARGO has ended.
CargoType GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoType.
Cargo support for NewGRFs.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
std::span< const uint > GetBuildingHouseIDCounts()
Get read-only span of total HouseID building counts.
void DrawNewHouseTileInGUI(int x, int y, const HouseSpec *spec, HouseID house_id, int view)
Draw representation of a house tile for GUI purposes.
Functions related to NewGRF houses.
StringID GetGRFStringID(uint32_t grfid, GRFStringID stringid)
Returns the index for this stringid associated with its grfID.
Header of Action 04 "universal holder" structure and functions.
static constexpr GRFStringID GRFSTR_MISC_GRF_TEXT
Miscellaneous GRF text range.
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:406
std::unique_ptr< NWidgetBase > MakePickerClassWidgets()
Create nested widgets for the class picker widgets.
std::unique_ptr< NWidgetBase > MakePickerTypeWidgets()
Create nested widgets for the type picker widgets.
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.
void UpdateNearestTownForRoadTiles(bool invalidate)
Updates cached nearest town for all road tiles.
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:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
@ SWS_OFF
Scroll wheel has no effect.
Base types for having sorted lists in GUIs.
Functions related to sound.
@ SND_15_BEEP
19 == 0x13 GUI button click
Definition sound_type.h:66
@ SND_1F_CONSTRUCTION_OTHER
29 == 0x1D Construction: other (non-water, non-rail, non-bridge)
Definition sound_type.h:76
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:425
Parse strings.
static std::optional< T > ParseInteger(std::string_view arg, int base=10, bool clamp=false)
Change a string into its number representation.
Functions related to low-level strings.
@ CS_NUMERAL
Only numeric ones.
Definition string_type.h:26
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition string_type.h:25
Searching and filtering using a stringterm.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:91
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:415
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:57
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:219
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
@ TD_RTL
Text is written right-to-left by default.
static const int MAX_CHAR_LENGTH
Max. length of UTF-8 encoded unicode character.
Class to backup a specific variable and restore it later.
void Restore()
Restore the variable.
static std::string GetHouseYear(TimerGameCalendar::Year min_year, TimerGameCalendar::Year max_year)
Get a date range string for house availability year.
void OnPlaceObject(Point pt, TileIndex tile) override
The user clicked some place on the map when a tile highlight mode has been set.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
static std::string GetHouseInformation(const HouseSpec *hs)
Get information string for a house.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnInit() override
Notification that the nested widget tree gets initialized.
Specification of a cargo type.
Definition cargotype.h:74
CargoType Index() const
Determines index of this cargospec.
Definition cargotype.h:108
StringID name
Name of this type of cargo.
Definition cargotype.h:91
static std::array< std::vector< const CargoSpec * >, NUM_TPE > town_production_cargoes
List of cargo specs for each Town Product Effect.
Definition cargotype.h:25
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:72
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.
uint32_t townnameparts
Generated town name.
TownLayout town_layout
Selected town layout.
void OnPlaceObject(Point pt, TileIndex tile) override
The user clicked some place on the map when a tile highlight mode has been set.
QueryString townname_editbox
Townname editbox.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnInit() override
Notification that the nested widget tree gets initialized.
TownSize town_size
Selected town size.
bool townnamevalid
Is generated town name valid?
TownNameParams params
Town name parameters.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
bool city
Are we building a city?
const struct GRFFile * grffile
grf file that introduced this entity
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced this entity.
bool persistent_buildingtools
keep the building tools active after usage
uint8_t scrollwheel_scrolling
scrolling using the scroll wheel?
EconomySettings economy
settings to change the economy
List of hotkeys for a window.
Definition hotkeys.h:37
All data for a single hotkey.
Definition hotkeys.h:21
SubstituteGRFFileProps grf_prop
Properties related the the grf file.
Definition house.h:114
bool enabled
the house is available to build (true by default, but can be disabled by newgrf)
Definition house.h:111
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:109
TimerGameCalendar::Year max_year
last year it can be built
Definition house.h:101
HouseCallbackMasks callback_mask
Bitmask of house callbacks that have to be called.
Definition house.h:115
uint8_t population
population (Zero on other tiles in multi tile house.)
Definition house.h:102
HouseExtraFlags extra_flags
some more flags
Definition house.h:118
TimerGameCalendar::Year min_year
introduction year of the house
Definition house.h:100
HouseID Index() const
Gets the index of this spec.
StringID building_name
building name
Definition house.h:104
HouseZones building_availability
where can it be built (climates, zones)
Definition house.h:110
static std::vector< HouseSpec > & Specs()
Get a reference to all HouseSpecs.
Data structure describing how to show the list (what sort direction and criteria).
bool order
Ascending/descending.
Partial widget specification to allow NWidgets to be written nested.
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
Coordinates of a point in 2D.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
static size_t GetNumItems()
Returns number of valid items in the pool.
Tindex index
Index of this pool item.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
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.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
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:212
bool click_beep
Beep on a random selection of buttons.
bool confirm
Play sound effect on successful constructions or other actions.
bool HasSpriteGroups() const
Check whether the entity has sprite groups.
String filter and state.
bool IsEmpty() const
Check whether any filter words were entered.
void SetFilterTerm(std::string_view str)
Set the term to filter on.
void ResetState()
Reset the matching state to process a new item.
bool GetState() const
Get the matching state of the current item.
void DeleteAll()
Delete every character in the textbuffer.
Definition textbuf.cpp:112
std::string_view GetText() const
Get the current text.
Definition textbuf.cpp:284
void Assign(std::string_view text)
Copy a string into the textbuffer.
Definition textbuf.cpp:420
Town authority window.
Definition town_gui.cpp:79
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition town_gui.cpp:320
void DrawActions()
Draws the contents of the actions panel.
Definition town_gui.cpp:203
Dimension icon_size
Dimensions of company icon.
Definition town_gui.cpp:88
void OnInit() override
Notification that the nested widget tree gets initialized.
Definition town_gui.cpp:128
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition town_gui.cpp:232
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
Definition town_gui.cpp:248
Town * town
Town being displayed.
Definition town_gui.cpp:81
TownActions enabled_actions
Actions that are enabled in settings.
Definition town_gui.cpp:84
TownAction sel_action
Currently selected town action, TownAction::End means no action selected.
Definition town_gui.cpp:82
TownActions available_actions
Actions that are available to execute for the current company.
Definition town_gui.cpp:85
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition town_gui.cpp:280
void DrawRatings()
Draw the contents of the ratings panel.
Definition town_gui.cpp:164
const IntervalTimer< TimerWindow > redraw_interval
Redraw the whole window on a regular interval.
Definition town_gui.cpp:316
Dimension exclusive_size
Dimensions of exclusive icon.
Definition town_gui.cpp:89
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition town_gui.cpp:225
static TownActions GetEnabledActions()
Gets all town authority actions enabled in settings.
Definition town_gui.cpp:96
void OnPaint() override
The window must be repainted.
Definition town_gui.cpp:134
TownActions displayed_actions_on_previous_painting
Actions that were available on the previous call to OnPaint()
Definition town_gui.cpp:83
uint32_t population
Current population of people.
Definition town.h:42
Town directory window class.
Definition town_gui.cpp:710
static const std::initializer_list< GUITownList::SortFunction *const > sorter_funcs
Available town directory sorting functions.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition town_gui.cpp:836
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:761
QueryString townname_editbox
Filter editbox.
Definition town_gui.cpp:724
void OnEditboxChanged(WidgetID wid) override
The text in an editbox has been edited.
Definition town_gui.cpp:992
static bool TownRatingSorter(const Town *const &a, const Town *const &b, const bool &order)
Sort by town rating.
Definition town_gui.cpp:770
void OnResize() override
Called after the window got resized.
Definition town_gui.cpp:987
StringFilter string_filter
Filter for towns.
Definition town_gui.cpp:723
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
EventState OnHotkey(int hotkey) override
A hotkey has been pressed.
const IntervalTimer< TimerWindow > rebuild_interval
Redraw the whole window on a regular interval.
Definition town_gui.cpp:982
void OnPaint() override
The window must be repainted.
Definition town_gui.cpp:975
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
Definition town_gui.cpp:964
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition town_gui.cpp:927
static std::string GetTownString(const Town *t, uint64_t population)
Get the string to draw the town name.
Definition town_gui.cpp:831
static bool TownNameSorter(const Town *const &a, const Town *const &b, const bool &)
Sort by town name.
Definition town_gui.cpp:755
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
Definition town_gui.cpp:880
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition town_gui.cpp:809
Struct holding parameters used to generate town name.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition town_gui.cpp:468
Town * town
Town displayed by the window.
Definition town_gui.cpp:347
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition town_gui.cpp:581
void OnMouseWheel(int wheel, WidgetID widget) override
The mouse wheel has been turned.
Definition town_gui.cpp:568
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
Definition town_gui.cpp:509
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition town_gui.cpp:389
uint GetDesiredInfoHeight(int width) const
Gets the desired height for the information panel.
Definition town_gui.cpp:522
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition town_gui.cpp:374
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Definition town_gui.cpp:368
void OnPaint() override
The window must be repainted.
Definition town_gui.cpp:381
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
Definition town_gui.cpp:589
void OnResize() override
Called after the window got resized.
Definition town_gui.cpp:558
Town data structure.
Definition town.h:52
EncodedString text
General text with additional information.
Definition town.h:81
bool larger_town
if this is a larger town and should grow more quickly
Definition town.h:99
TileIndex xy
town center tile
Definition town.h:53
uint8_t fund_buildings_months
fund buildings program in action?
Definition town.h:96
uint16_t noise_reached
level of noise that all the airports are generating
Definition town.h:66
uint8_t flags
See TownFlags.
Definition town.h:64
TownCache cache
Container for all cacheable data.
Definition town.h:55
CompanyID exclusivity
which company has exclusivity
Definition town.h:73
std::array< TransportedCargoStat< uint32_t >, NUM_CARGO > supplied
Cargo statistics about supplied cargo.
Definition town.h:77
bool show_zone
NOSAVE: mark town to show the local authority zone in the viewports.
Definition town.h:102
CompanyMask have_ratings
which companies have a rating
Definition town.h:71
TypedIndexContainer< std::array< int16_t, MAX_COMPANIES >, CompanyID > ratings
ratings of each company for this town
Definition town.h:75
uint16_t growth_rate
town growth rate
Definition town.h:94
std::array< TransportedCargoStat< uint16_t >, NUM_TAE > received
Cargo statistics about received cargotypes.
Definition town.h:78
std::array< uint32_t, NUM_TAE > goal
Amount of cargo required for the town to grow.
Definition town.h:79
High level window description.
Definition window_gui.h:167
Number to differentiate different windows of the same class.
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:967
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1091
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:826
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1778
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:777
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3205
Window * parent
Parent window.
Definition window_gui.h:328
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:555
std::unique_ptr< ViewportData > viewport
Pointer to viewport data, if present.
Definition window_gui.h:318
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:503
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:809
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1768
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:484
bool IsWidgetLowered(WidgetID widget_index) const
Gets the lowered state of a widget.
Definition window_gui.h:491
void RaiseButtons(bool autoraise=false)
Raise the buttons of the window.
Definition window.cpp:529
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:441
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:559
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:211
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1791
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:312
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:381
AllWindows< false > Iterate
Iterate all windows in whatever order is easiest.
Definition window_gui.h:932
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
@ AcceptUnchanged
return success even when the text didn't change
@ EnableDefault
enable the 'Default' button ("\0" is returned)
@ LengthIsInChars
the length of the string is counted in characters
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
static const uint TILE_PIXELS
Pixel distance between tile columns/rows in ZOOM_BASE.
Definition tile_type.h:17
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:78
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).
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...
@ 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:31
uint GetDefaultTownsForMapSize()
Calculate the number of towns which should be on the map according to the current "town density" newg...
TownActions GetMaskOfTownActions(CompanyID cid, const Town *t)
Get a list of available town authority actions.
const CargoSpec * FindFirstCargoWithTownAcceptanceEffect(TownAcceptanceEffect effect)
Determines the first cargo with a certain town effect.
static const uint TOWN_GROWTH_DESERT
The town needs the cargo for growth when on desert (any amount)
Definition town.h:32
@ TOWN_IS_GROWING
Conditions for town growth are met. Grow according to Town::growth_rate.
Definition town.h:194
bool GenerateTowns(TownLayout layout, std::optional< uint > number=std::nullopt)
Generate a number of towns with a given layout.
uint32_t GetWorldPopulation()
Get the total population, the sum of all towns in the world.
Definition town_cmd.cpp:452
CargoArray GetAcceptedCargoOfHouse(const HouseSpec *hs)
Get accepted cargo of a house prototype.
Definition town_cmd.cpp:851
uint8_t GetTownActionCost(TownAction action)
Get cost factors for a TownAction.
TownAction
Town actions of a company.
Definition town.h:210
@ RoadRebuild
Rebuild the roads.
@ Bribe
Try to bribe the council.
@ BuyRights
Buy exclusive transport rights.
@ FundBuildings
Fund new buildings.
Command definitions related to towns.
TownDirectoryHotkeys
Enum referring to the Hotkeys in the town directory window.
Definition town_gui.cpp:705
@ TDHK_FOCUS_FILTER_BOX
Focus the filter box.
Definition town_gui.cpp:706
static constexpr NWidgetPart _nested_build_house_widgets[]
Nested widget definition for the build NewGRF rail waypoint window.
void DrawHouseInGUI(int x, int y, HouseID house_id, int view)
Draw a house that does not exist.
static StringID GetHouseName(const HouseSpec *hs)
Get name for a prototype house.
static CargoTypes GetProducedCargoOfHouse(const HouseSpec *hs)
Get the cargo types produced by a house.
Declarations for accessing the k-d tree of towns.
TownLayout
Town Layouts.
Definition town_type.h:81
@ TF_CUSTOM_LAYOUT
Allowed, with custom town layout.
Definition town_type.h:107
TownSize
Supported initial town sizes.
Definition town_type.h:21
@ TSZ_MEDIUM
Medium town.
Definition town_type.h:23
static const uint MAX_LENGTH_TOWN_NAME_CHARS
The maximum length of a town name in characters including '\0'.
Definition town_type.h:119
@ Roads
Allow town to place roads.
@ Buildings
Allow town to place buildings.
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_EXPAND_BUILDINGS
Expand number of buildings this town (scenario editor only).
Definition town_widget.h:45
@ 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:47
@ WID_TV_EXPAND_ROADS
Expand roads of this town (scenario editor only).
Definition town_widget.h:46
@ 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:71
@ WID_TF_LOAD_FROM_FILE
Load town data from file.
Definition town_widget.h:56
@ WID_TF_SIZE_SEL
Container of town size buttons.
Definition town_widget.h:60
@ WID_TF_SIZE_LARGE
Selection for a large town.
Definition town_widget.h:63
@ WID_TF_NEW_TOWN
Create a new town.
Definition town_widget.h:52
@ WID_TF_EXPAND_ALL_TOWNS
Make all towns grow slightly.
Definition town_widget.h:57
@ WID_TF_MANY_RANDOM_TOWNS
Randomly place many towns.
Definition town_widget.h:55
@ WID_TF_SIZE_SMALL
Selection for a small town.
Definition town_widget.h:61
@ WID_TF_EXPAND_BUILDINGS
Expand buildings toggle.
Definition town_widget.h:73
@ WID_TF_LAYOUT_GRID2
Selection for the 2x2 grid town layout.
Definition town_widget.h:69
@ WID_TF_LAYOUT_ORIGINAL
Selection for the original town layout.
Definition town_widget.h:67
@ WID_TF_SIZE_RANDOM
Selection for a randomly sized town.
Definition town_widget.h:64
@ WID_TF_TOWN_NAME_EDITBOX
Editor for the town name.
Definition town_widget.h:58
@ WID_TF_TOWN_ACTION_SEL
Container of town action buttons.
Definition town_widget.h:53
@ WID_TF_SIZE_MEDIUM
Selection for a medium town.
Definition town_widget.h:62
@ WID_TF_TOWN_EXPAND_SEL
Container of town expansion buttons.
Definition town_widget.h:72
@ WID_TF_EXPAND_ROADS
Expand roads toggle.
Definition town_widget.h:74
@ WID_TF_CITY
Selection for the town's city state.
Definition town_widget.h:65
@ WID_TF_RANDOM_TOWN
Randomly place a town.
Definition town_widget.h:54
@ WID_TF_LAYOUT_BETTER
Selection for the better town layout.
Definition town_widget.h:68
@ WID_TF_ROAD_LAYOUT_SEL
Container of town road layout buttons.
Definition town_widget.h:66
@ WID_TF_LAYOUT_GRID3
Selection for the 3x3 grid town layout.
Definition town_widget.h:70
@ WID_TF_TOWN_NAME_RANDOM
Generate a random town name.
Definition town_widget.h:59
@ 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
@ WID_BH_PROTECT_OFF
Button to protect the next house built.
Definition town_widget.h:80
@ WID_BH_PROTECT_ON
Button to not protect the next house built.
Definition town_widget.h:81
@ WID_BH_INFO
Information panel of selected house.
Definition town_widget.h:79
bool GenerateTownName(Randomizer &randomizer, uint32_t *townnameparts, TownNames *town_names)
Generates valid town name.
Definition townname.cpp:136
Town name generator stuff.
bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
Scrolls the viewport in a window to a given location.
void SetTileSelectSize(int w, int h)
Highlight w by h tiles at the cursor.
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
void SetViewportCatchmentTown(const Town *t, bool sel)
Select or deselect town for coverage area highlight.
const Town * _viewport_highlight_town
Currently selected town for coverage area highlight.
Functions related to (drawing on) viewports.
@ ZOOM_IN
Zoom in (get more detailed view).
@ ZOOM_OUT
Zoom out (get helicopter view).
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition widget_type.h:41
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ WWT_LABEL
Centered label.
Definition widget_type.h:49
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:63
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:67
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:45
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:58
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:53
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:77
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:69
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:61
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:38
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:60
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:57
@ NWID_VIEWPORT
Nested widget containing a viewport.
Definition widget_type.h:74
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:62
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:50
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:72
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
@ SZSP_VERTICAL
Display plane with zero size horizontally, and filling and resizing vertically.
@ EqualSize
Containers should keep all their (resizing) children equally large.
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Definition window.cpp:2067
void SetFocusedWindow(Window *w)
Set the window that has the focus.
Definition window.cpp:420
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition window.cpp:1265
Window functions not directly related to making/drawing windows.
@ Construction
This window is used for construction; close it whenever changing company.
@ DisableVpScroll
Window does not do autoscroll,.
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:218
@ SBS_UP
Sort descending.
Definition window_gui.h:219
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:20
EventState
State of handling an event.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
@ WC_TOWN_AUTHORITY
Town authority; Window numbers:
@ WC_FOUND_TOWN
Found a town; Window numbers:
@ WC_BUILD_HOUSE
Build house; Window numbers:
@ WC_BUILD_TOOLBAR
Build toolbar; Window numbers:
Definition window_type.h:75
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_TOWN_VIEW
Town view; Window numbers:
@ WC_TOWN_DIRECTORY
Town directory; Window numbers:
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition zoom_func.h:107
ZoomLevel ScaleZoomGUI(ZoomLevel value)
Scale zoom level relative to GUI zoom.
Definition zoom_func.h:87
@ Town
Default zoom level for the town view.