1
0
Fork 0

Compare commits

...

4 Commits

Author SHA1 Message Date
Peter Nelson 00d3fc3f7f
Merge 67bb5fc5c5 into 10eeba86a6 2025-07-23 19:33:26 +00:00
Peter Nelson 10eeba86a6 Codechange: Simplify/breakout logic for selecting bridge table sprites.
Move various base offsets to separate functions where they can be reused and documented.

No longer rely on coincidences to select the correct data between bridges and aqueducts.
2025-07-23 20:31:15 +01:00
Peter Nelson d99dad9e9e Codechange: Pass bridge pillar palette/sprite by reference. 2025-07-23 20:31:15 +01:00
Peter Nelson 67bb5fc5c5
Change: Merge town view and local authority windows. 2025-07-19 23:53:47 +01:00
9 changed files with 382 additions and 372 deletions

View File

@ -3691,10 +3691,15 @@ STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Town gro
STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Town is {RED}not{BLACK} growing
STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Noise limit in town: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA}
STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centre the main view on town location. Ctrl+Click to open a new viewport on town location
STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Local Authority
STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Show information on local authority
STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Change town name
STR_TOWN_VIEW_INFO :Information
STR_TOWN_VIEW_INFO_TOOLTIP :Switch to town information tab
STR_TOWN_VIEW_RATINGS :Ratings
STR_TOWN_VIEW_RATINGS_TOOLTIP :Switch to local authority ratings tab
STR_TOWN_VIEW_ACTIONS :Actions
STR_TOWN_VIEW_ACTIONS_TOOLTIP :Switch to local authority actions tab
STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Expand
STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Increase size of town
STR_TOWN_VIEW_EXPAND_BUILDINGS_BUTTON :{BLACK}Expand buildings
@ -3706,8 +3711,6 @@ STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Delete t
STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Rename Town
# Town local authority window
STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} local authority
STR_LOCAL_AUTHORITY_ZONE :{BLACK}Zone
STR_LOCAL_AUTHORITY_ZONE_TOOLTIP :{BLACK}Show zone within local authority boundaries
STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Transport company ratings:

View File

@ -599,7 +599,7 @@ static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlags flags)
if (flags.Test(DoCommandFlag::Execute)) {
Town *town = o->town;
town->statues.Reset(GetTileOwner(tile));
SetWindowDirty(WC_TOWN_AUTHORITY, town->index);
SetWindowDirty(WC_TOWN_VIEW, town->index);
}
break;
@ -882,7 +882,7 @@ static void ChangeTileOwner_Object(TileIndex tile, Owner old_owner, Owner new_ow
do_clear = true;
}
SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
SetWindowDirty(WC_TOWN_VIEW, t->index);
} else {
do_clear = true;
}

View File

@ -36,10 +36,15 @@
# define MW(a) {a, PALETTE_TO_STRUCT_WHITE}
# define MC(a) {a, PALETTE_TO_STRUCT_CONCRETE}
static const PalSpriteID _aqueduct_sprites[] = {
{ SPR_AQUEDUCT_MIDDLE_X, PAL_NONE }, { 0x0, PAL_NONE }, { SPR_AQUEDUCT_PILLAR_X, PAL_NONE }, { 0x0, PAL_NONE },
{ SPR_AQUEDUCT_MIDDLE_Y, PAL_NONE }, { 0x0, PAL_NONE }, { SPR_AQUEDUCT_PILLAR_Y, PAL_NONE }, { 0x0, PAL_NONE },
{ SPR_AQUEDUCT_RAMP_SW, PAL_NONE }, { SPR_AQUEDUCT_RAMP_SE, PAL_NONE }, { SPR_AQUEDUCT_RAMP_NE, PAL_NONE }, { SPR_AQUEDUCT_RAMP_NW, PAL_NONE },
/* Sprite table for middle part of aqueduct. */
static const PalSpriteID _aqueduct_sprite_table_middle[] = {
{SPR_AQUEDUCT_MIDDLE_X, PAL_NONE}, {0x0, PAL_NONE}, {SPR_AQUEDUCT_PILLAR_X, PAL_NONE}, {0x0, PAL_NONE}, // AXIS_X
{SPR_AQUEDUCT_MIDDLE_Y, PAL_NONE}, {0x0, PAL_NONE}, {SPR_AQUEDUCT_PILLAR_Y, PAL_NONE}, {0x0, PAL_NONE}, // AIXS_Y
};
/* Sprite table for head part of aqueduct. */
static const PalSpriteID _aqueduct_sprite_table_heads[] = {
{SPR_AQUEDUCT_RAMP_SW, PAL_NONE}, {SPR_AQUEDUCT_RAMP_SE, PAL_NONE}, {SPR_AQUEDUCT_RAMP_NE, PAL_NONE}, {SPR_AQUEDUCT_RAMP_NW, PAL_NONE},
};
static const PalSpriteID _bridge_sprite_table_4_0[] = {

View File

@ -147,7 +147,7 @@ def = true
str = STR_CONFIG_SETTING_BRIBE
strhelp = STR_CONFIG_SETTING_BRIBE_HELPTEXT
help_cb = SettingHelpWallclock
post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_AUTHORITY); }
post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_VIEW); }
cat = SC_BASIC
[SDT_BOOL]
@ -157,7 +157,7 @@ def = true
str = STR_CONFIG_SETTING_ALLOW_EXCLUSIVE
strhelp = STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT
help_cb = SettingHelpWallclock
post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_AUTHORITY); }
post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_VIEW); }
cat = SC_BASIC
[SDT_BOOL]
@ -166,7 +166,7 @@ from = SLV_165
def = true
str = STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS
strhelp = STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT
post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_AUTHORITY); }
post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_VIEW); }
cat = SC_BASIC
[SDT_BOOL]
@ -175,7 +175,7 @@ from = SLV_160
def = true
str = STR_CONFIG_SETTING_ALLOW_FUND_ROAD
strhelp = STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT
post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_AUTHORITY); }
post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_VIEW); }
cat = SC_BASIC
[SDT_BOOL]

View File

@ -3187,7 +3187,7 @@ CommandCost CmdTownRating(DoCommandFlags flags, TownID town_id, CompanyID compan
int16_t new_rating = Clamp(rating, RATING_MINIMUM, RATING_MAXIMUM);
if (flags.Test(DoCommandFlag::Execute)) {
t->ratings[company_id] = new_rating;
InvalidateWindowData(WC_TOWN_AUTHORITY, town_id);
InvalidateWindowData(WC_TOWN_VIEW, town_id);
}
return CommandCost();
@ -3583,7 +3583,7 @@ static CommandCost TownActionBribe(Town *t, DoCommandFlags flags)
*/
if (t->ratings[_current_company] > RATING_BRIBE_DOWN_TO) {
t->ratings[_current_company] = RATING_BRIBE_DOWN_TO;
SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
SetWindowDirty(WC_TOWN_VIEW, t->index);
}
} else {
ChangeTownRating(t, RATING_BRIBE_UP_STEP, RATING_BRIBE_MAXIMUM, DoCommandFlag::Execute);
@ -3684,7 +3684,7 @@ CommandCost CmdDoTownAction(DoCommandFlags flags, TownID town_id, TownAction act
if (ret.Failed()) return ret;
if (flags.Test(DoCommandFlag::Execute)) {
SetWindowDirty(WC_TOWN_AUTHORITY, town_id);
SetWindowDirty(WC_TOWN_VIEW, town_id);
}
return cost;
@ -3737,7 +3737,7 @@ static void UpdateTownRating(Town *t)
t->ratings[i] = Clamp(t->ratings[i], RATING_MINIMUM, RATING_MAXIMUM);
}
SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
SetWindowDirty(WC_TOWN_VIEW, t->index);
}
@ -4009,7 +4009,7 @@ void ChangeTownRating(Town *t, int add, int max, DoCommandFlags flags)
} else {
t->have_ratings.Set(_current_company);
t->ratings[_current_company] = rating;
SetWindowDirty(WC_TOWN_AUTHORITY, t->index);
InvalidateWindowData(WC_TOWN_VIEW, t->index);
}
}

View File

@ -57,36 +57,21 @@ TownKdtree _town_local_authority_kdtree{};
typedef GUIList<const Town*, const bool &> GUITownList;
static constexpr NWidgetPart _nested_town_authority_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TA_CAPTION),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TA_ZONE_BUTTON), SetMinimalSize(50, 0), SetStringTip(STR_LOCAL_AUTHORITY_ZONE, STR_LOCAL_AUTHORITY_ZONE_TOOLTIP),
NWidget(WWT_SHADEBOX, COLOUR_BROWN),
NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
NWidget(WWT_STICKYBOX, COLOUR_BROWN),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(317, 52), SetResize(1, 0), SetToolTip(STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(),
NWidget(NWID_HORIZONTAL),
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),
NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
EndContainer()
};
/** Town authority window. */
struct TownAuthorityWindow : Window {
/* Town view window. */
struct TownViewWindow : Window {
private:
Town *town = nullptr; ///< Town being displayed.
Town *town = nullptr; ///< Town displayed by the window.
TownAction sel_action = TownAction::End; ///< Currently selected town action, TownAction::End means no action selected.
TownActions displayed_actions_on_previous_painting{}; ///< Actions that were available on the previous call to OnPaint()
TownActions enabled_actions{}; ///< Actions that are enabled in settings.
TownActions available_actions{}; ///< Actions that are available to execute for the current company.
std::array<StringID, to_underlying(TownAction::End)> action_tooltips{};
Dimension icon_size{}; ///< Dimensions of company icon
Dimension exclusive_size{}; ///< Dimensions of exclusive icon
uint rating_line_height = 0;
static inline uint initial_visible_pane = 0;
uint visible_pane = 0;
/**
* Gets all town authority actions enabled in settings.
@ -107,10 +92,17 @@ private:
}
public:
TownAuthorityWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
static const int WID_TV_HEIGHT_NORMAL = 150;
TownViewWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
{
this->visible_pane = TownViewWindow::initial_visible_pane;
this->CreateNestedTree();
this->town = Town::Get(window_number);
this->enabled_actions = GetEnabledActions();
this->available_actions = GetMaskOfTownActions(_local_company, this->town);
auto realtime = TimerGameEconomy::UsingWallclockUnits();
this->action_tooltips[0] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING;
@ -122,238 +114,7 @@ public:
this->action_tooltips[6] = realtime ? STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT_MINUTES : STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT_MONTHS;
this->action_tooltips[7] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE;
this->InitNested(window_number);
}
void OnInit() override
{
this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
this->exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT);
}
void OnPaint() override
{
this->available_actions = GetMaskOfTownActions(_local_company, this->town);
if (this->available_actions != displayed_actions_on_previous_painting) this->SetDirty();
displayed_actions_on_previous_painting = this->available_actions;
this->SetWidgetLoweredState(WID_TA_ZONE_BUTTON, this->town->show_zone);
this->SetWidgetDisabledState(WID_TA_EXECUTE, (this->sel_action == TownAction::End) || !this->available_actions.Test(this->sel_action));
this->DrawWidgets();
if (!this->IsShaded())
{
this->DrawRatings();
this->DrawActions();
}
}
StringID GetRatingString(int rating) const
{
if (rating > RATING_EXCELLENT) return STR_CARGO_RATING_OUTSTANDING;
if (rating > RATING_VERYGOOD) return STR_CARGO_RATING_EXCELLENT;
if (rating > RATING_GOOD) return STR_CARGO_RATING_VERY_GOOD;
if (rating > RATING_MEDIOCRE) return STR_CARGO_RATING_GOOD;
if (rating > RATING_POOR) return STR_CARGO_RATING_MEDIOCRE;
if (rating > RATING_VERYPOOR) return STR_CARGO_RATING_POOR;
if (rating > RATING_APPALLING) return STR_CARGO_RATING_VERY_POOR;
return STR_CARGO_RATING_APPALLING;
}
/** Draw the contents of the ratings panel. May request a resize of the window if the contents does not fit. */
void DrawRatings()
{
Rect r = this->GetWidget<NWidgetBase>(WID_TA_RATING_INFO)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
int text_y_offset = (this->resize.step_height - GetCharacterHeight(FS_NORMAL)) / 2;
int icon_y_offset = (this->resize.step_height - this->icon_size.height) / 2;
int exclusive_y_offset = (this->resize.step_height - this->exclusive_size.height) / 2;
DrawString(r.left, r.right, r.top + text_y_offset, STR_LOCAL_AUTHORITY_COMPANY_RATINGS);
r.top += this->resize.step_height;
bool rtl = _current_text_dir == TD_RTL;
Rect icon = r.WithWidth(this->icon_size.width, rtl);
Rect exclusive = r.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal, rtl).WithWidth(this->exclusive_size.width, rtl);
Rect text = r.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal + this->exclusive_size.width + WidgetDimensions::scaled.hsep_normal, rtl);
/* Draw list of companies */
for (const Company *c : Company::Iterate()) {
if ((this->town->have_ratings.Test(c->index) || this->town->exclusivity == c->index)) {
DrawCompanyIcon(c->index, icon.left, text.top + icon_y_offset);
if (this->town->exclusivity == c->index) {
DrawSprite(SPR_EXCLUSIVE_TRANSPORT, GetCompanyPalette(c->index), exclusive.left, text.top + exclusive_y_offset);
}
int rating = this->town->ratings[c->index];
DrawString(text.left, text.right, text.top + text_y_offset, GetString(STR_LOCAL_AUTHORITY_COMPANY_RATING, c->index, c->index, GetRatingString(rating)));
text.top += this->resize.step_height;
}
}
text.bottom = text.top - 1;
if (text.bottom > r.bottom) {
/* If the company list is too big to fit, mark ourself dirty and draw again. */
ResizeWindow(this, 0, text.bottom - r.bottom, false);
}
}
/** Draws the contents of the actions panel. May re-initialise window to resize panel, if the list does not fit. */
void DrawActions()
{
Rect r = this->GetWidget<NWidgetBase>(WID_TA_COMMAND_LIST)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
DrawString(r, STR_LOCAL_AUTHORITY_ACTIONS_TITLE);
r.top += GetCharacterHeight(FS_NORMAL);
/* Draw list of actions */
for (TownAction i = {}; i != TownAction::End; ++i) {
/* Don't show actions if disabled in settings. */
if (!this->enabled_actions.Test(i)) continue;
/* Set colour of action based on ability to execute and if selected. */
TextColour action_colour = TC_GREY | TC_NO_SHADE;
if (this->available_actions.Test(i)) action_colour = TC_ORANGE;
if (this->sel_action == i) action_colour = TC_WHITE;
DrawString(r, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + to_underlying(i), action_colour);
r.top += GetCharacterHeight(FS_NORMAL);
}
}
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
{
if (widget == WID_TA_CAPTION) return GetString(STR_LOCAL_AUTHORITY_CAPTION, this->window_number);
return this->Window::GetWidgetString(widget, stringid);
}
void DrawWidget(const Rect &r, WidgetID widget) const override
{
switch (widget) {
case WID_TA_ACTION_INFO:
if (this->sel_action != TownAction::End) {
Money action_cost = _price[PR_TOWN_ACTION] * GetTownActionCost(this->sel_action) >> 8;
bool affordable = Company::IsValidID(_local_company) && action_cost < GetAvailableMoney(_local_company);
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.framerect),
GetString(this->action_tooltips[to_underlying(this->sel_action)], action_cost),
affordable ? TC_YELLOW : TC_RED);
}
break;
}
}
void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
{
switch (widget) {
case WID_TA_ACTION_INFO: {
assert(size.width > padding.width && size.height > padding.height);
Dimension d = {0, 0};
for (TownAction i = {}; i != TownAction::End; ++i) {
Money price = _price[PR_TOWN_ACTION] * GetTownActionCost(i) >> 8;
d = maxdim(d, GetStringMultiLineBoundingBox(GetString(this->action_tooltips[to_underlying(i)], price), size));
}
d.width += padding.width;
d.height += padding.height;
size = maxdim(size, d);
break;
}
case WID_TA_COMMAND_LIST:
size.height = (to_underlying(TownAction::End) + 1) * GetCharacterHeight(FS_NORMAL) + padding.height;
size.width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width;
for (TownAction i = {}; i != TownAction::End; ++i) {
size.width = std::max(size.width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + to_underlying(i)).width + padding.width);
}
size.width += padding.width;
break;
case WID_TA_RATING_INFO:
fill.height = resize.height = std::max({this->icon_size.height + WidgetDimensions::scaled.vsep_normal, this->exclusive_size.height + WidgetDimensions::scaled.vsep_normal, (uint)GetCharacterHeight(FS_NORMAL)});
size.height = 9 * resize.height + padding.height;
break;
}
}
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
switch (widget) {
case WID_TA_ZONE_BUTTON: {
bool new_show_state = !this->town->show_zone;
TownID index = this->town->index;
new_show_state ? _town_local_authority_kdtree.Insert(index) : _town_local_authority_kdtree.Remove(index);
this->town->show_zone = new_show_state;
this->SetWidgetLoweredState(widget, new_show_state);
MarkWholeScreenDirty();
break;
}
case WID_TA_COMMAND_LIST: {
int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, GetCharacterHeight(FS_NORMAL)) - 1;
auto action = this->enabled_actions.GetNthSetBit(y);
if (!action.has_value()) break;
this->sel_action = *action;
this->SetDirty();
/* When double-clicking, continue */
if (click_count == 1 || !this->available_actions.Test(this->sel_action)) break;
[[fallthrough]];
}
case WID_TA_EXECUTE:
Command<CMD_DO_TOWN_ACTION>::Post(STR_ERROR_CAN_T_DO_THIS, this->town->xy, static_cast<TownID>(this->window_number), this->sel_action);
break;
}
}
/** Redraw the whole window on a regular interval. */
const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
this->SetDirty();
}};
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
{
if (!gui_scope) return;
this->enabled_actions = this->GetEnabledActions();
if (!this->enabled_actions.Test(this->sel_action)) {
this->sel_action = TownAction::End;
}
}
};
static WindowDesc _town_authority_desc(
WDP_AUTO, "view_town_authority", 317, 222,
WC_TOWN_AUTHORITY, WC_NONE,
{},
_nested_town_authority_widgets
);
static void ShowTownAuthorityWindow(uint town)
{
AllocateWindowDescFront<TownAuthorityWindow>(_town_authority_desc, town);
}
/* Town view window. */
struct TownViewWindow : Window {
private:
Town *town = nullptr; ///< Town displayed by the window.
public:
static const int WID_TV_HEIGHT_NORMAL = 150;
TownViewWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
{
this->CreateNestedTree();
this->town = Town::Get(window_number);
this->SetPaneState();
this->FinishInitNested(window_number);
@ -365,6 +126,23 @@ public:
this->SetWidgetDisabledState(WID_TV_CHANGE_NAME, _networking && !_network_server);
}
void SetPaneState()
{
if (auto *nwid = this->GetWidget<NWidgetStacked>(WID_TV_PANE_SEL); nwid != nullptr) {
nwid->SetDisplayedPlane(this->visible_pane);
this->SetWidgetLoweredState(WID_TV_PANE_INFO, this->visible_pane == 0);
this->SetWidgetLoweredState(WID_TV_PANE_RATINGS, this->visible_pane == 1);
this->SetWidgetLoweredState(WID_TV_PANE_ACTIONS, this->visible_pane == 2);
}
}
void OnInit() override
{
this->icon_size = GetScaledSpriteSize(SPR_COMPANY_ICON);
this->exclusive_size = GetScaledSpriteSize(SPR_EXCLUSIVE_TRANSPORT);
this->rating_line_height = std::max({this->icon_size.height, this->exclusive_size.height, (uint)GetCharacterHeight(FS_NORMAL)});
}
void Close([[maybe_unused]] int data = 0) override
{
SetViewportCatchmentTown(Town::Get(this->window_number), false);
@ -382,14 +160,24 @@ public:
{
extern const Town *_viewport_highlight_town;
this->SetWidgetLoweredState(WID_TV_CATCHMENT, _viewport_highlight_town == this->town);
this->SetWidgetLoweredState(WID_TV_ZONE, this->town->show_zone);
this->SetWidgetDisabledState(WID_TV_EXECUTE, this->visible_pane != 2 || this->sel_action == TownAction::End || !this->available_actions.Test(this->sel_action));
this->DrawWidgets();
}
void DrawWidget(const Rect &r, WidgetID widget) const override
{
if (widget != WID_TV_INFO) return;
switch (widget) {
case WID_TV_INFO: this->DrawInfo(r); break;
case WID_TV_RATING_INFO: this->DrawRatings(r); break;
case WID_TV_COMMAND_LIST: this->DrawActions(r); break;
case WID_TV_ACTION_INFO: this->DrawActionInfo(r); break;
default: break;
}
}
void DrawInfo(const Rect &r) const
{
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
DrawString(tr, GetString(STR_TOWN_VIEW_POPULATION_HOUSES, this->town->cache.population, this->town->cache.num_houses));
@ -465,6 +253,86 @@ public:
}
}
static StringID GetRatingString(int rating)
{
if (rating > RATING_EXCELLENT) return STR_CARGO_RATING_OUTSTANDING;
if (rating > RATING_VERYGOOD) return STR_CARGO_RATING_EXCELLENT;
if (rating > RATING_GOOD) return STR_CARGO_RATING_VERY_GOOD;
if (rating > RATING_MEDIOCRE) return STR_CARGO_RATING_GOOD;
if (rating > RATING_POOR) return STR_CARGO_RATING_MEDIOCRE;
if (rating > RATING_VERYPOOR) return STR_CARGO_RATING_POOR;
if (rating > RATING_APPALLING) return STR_CARGO_RATING_VERY_POOR;
return STR_CARGO_RATING_APPALLING;
}
/** Draw the contents of the ratings panel. May request a resize of the window if the contents does not fit. */
void DrawRatings(const Rect &r) const
{
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
int text_y_offset = (this->rating_line_height - GetCharacterHeight(FS_NORMAL)) / 2;
int icon_y_offset = (this->rating_line_height - this->icon_size.height) / 2;
int exclusive_y_offset = (this->rating_line_height - this->exclusive_size.height) / 2;
DrawString(tr.left, tr.right, tr.top + text_y_offset, STR_LOCAL_AUTHORITY_COMPANY_RATINGS);
tr.top += this->rating_line_height;
bool rtl = _current_text_dir == TD_RTL;
Rect icon = tr.WithWidth(this->icon_size.width, rtl);
Rect exclusive = tr.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal, rtl).WithWidth(this->exclusive_size.width, rtl);
Rect text = tr.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal + this->exclusive_size.width + WidgetDimensions::scaled.hsep_normal, rtl);
/* Draw list of companies */
for (const Company *c : Company::Iterate()) {
if ((this->town->have_ratings.Test(c->index) || this->town->exclusivity == c->index)) {
DrawCompanyIcon(c->index, icon.left, text.top + icon_y_offset);
if (this->town->exclusivity == c->index) {
DrawSprite(SPR_EXCLUSIVE_TRANSPORT, GetCompanyPalette(c->index), exclusive.left, text.top + exclusive_y_offset);
}
int rating = this->town->ratings[c->index];
DrawString(text.left, text.right, text.top + text_y_offset, GetString(STR_LOCAL_AUTHORITY_COMPANY_RATING, c->index, c->index, GetRatingString(rating)));
text.top += this->rating_line_height;
}
}
}
/** Draws the contents of the actions panel. May re-initialise window to resize panel, if the list does not fit. */
void DrawActions(const Rect &r) const
{
Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
DrawString(tr, STR_LOCAL_AUTHORITY_ACTIONS_TITLE);
tr.top += GetCharacterHeight(FS_NORMAL);
/* Draw list of actions */
for (TownAction i = {}; i != TownAction::End; ++i) {
/* Don't show actions if disabled in settings. */
if (!this->enabled_actions.Test(i)) continue;
/* Set colour of action based on ability to execute and if selected. */
TextColour action_colour = TC_GREY | TC_NO_SHADE;
if (this->available_actions.Test(i)) action_colour = TC_ORANGE;
if (this->sel_action == i) action_colour = TC_WHITE;
DrawString(tr, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + to_underlying(i), action_colour);
tr.top += GetCharacterHeight(FS_NORMAL);
}
}
void DrawActionInfo(const Rect &r) const
{
if (this->sel_action == TownAction::End) return;
Money action_cost = _price[PR_TOWN_ACTION] * GetTownActionCost(this->sel_action) >> 8;
bool affordable = Company::IsValidID(_local_company) && action_cost < GetAvailableMoney(_local_company);
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.framerect),
GetString(this->action_tooltips[to_underlying(this->sel_action)], action_cost),
affordable ? TC_YELLOW : TC_RED);
}
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
switch (widget) {
@ -476,10 +344,6 @@ public:
}
break;
case WID_TV_SHOW_AUTHORITY: // town authority
ShowTownAuthorityWindow(this->window_number);
break;
case WID_TV_CHANGE_NAME: // rename
ShowQueryString(GetString(STR_TOWN_NAME, this->window_number), STR_TOWN_VIEW_RENAME_TOWN_BUTTON, MAX_LENGTH_TOWN_NAME_CHARS, this, CS_ALPHANUMERAL, {QueryStringFlag::EnableDefault, QueryStringFlag::LengthIsInChars});
break;
@ -503,14 +367,68 @@ public:
case WID_TV_DELETE: // delete town - only available on Scenario editor
Command<CMD_DELETE_TOWN>::Post(STR_ERROR_TOWN_CAN_T_DELETE, static_cast<TownID>(this->window_number));
break;
case WID_TV_ZONE: {
bool new_show_state = !this->town->show_zone;
TownID index = this->town->index;
new_show_state ? _town_local_authority_kdtree.Insert(index) : _town_local_authority_kdtree.Remove(index);
this->town->show_zone = new_show_state;
this->SetWidgetLoweredState(widget, new_show_state);
MarkWholeScreenDirty();
break;
}
case WID_TV_COMMAND_LIST: {
int y = this->GetRowFromWidget(pt.y, widget, WidgetDimensions::scaled.framerect.top, GetCharacterHeight(FS_NORMAL)) - 1;
auto action = this->enabled_actions.GetNthSetBit(y);
if (!action.has_value()) break;
this->sel_action = *action;
this->SetDirty();
/* When double-clicking, continue */
if (click_count == 1 || !this->available_actions.Test(this->sel_action)) break;
[[fallthrough]];
}
case WID_TV_EXECUTE:
Command<CMD_DO_TOWN_ACTION>::Post(STR_ERROR_CAN_T_DO_THIS, this->town->xy, static_cast<TownID>(this->window_number), this->sel_action);
break;
case WID_TV_PANE_INFO:
TownViewWindow::initial_visible_pane = this->visible_pane = 0;
this->ResizePanes();
break;
case WID_TV_PANE_RATINGS:
TownViewWindow::initial_visible_pane = this->visible_pane = 1;
this->ResizePanes();
break;
case WID_TV_PANE_ACTIONS:
TownViewWindow::initial_visible_pane = this->visible_pane = 2;
this->ResizePanes();
break;
}
}
void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
{
switch (widget) {
case WID_TV_INFO:
size.height = GetDesiredInfoHeight(size.width) + padding.height;
case WID_TV_COMMAND_LIST:
if (this->visible_pane != 2) {
size.height = 0;
} else {
size.height = (to_underlying(TownAction::End) + 1) * GetCharacterHeight(FS_NORMAL) + padding.height;
size.width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width;
for (TownAction i = {}; i != TownAction::End; ++i) {
size.width = std::max(size.width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + to_underlying(i)).width + padding.width);
}
size.width += padding.width;
}
break;
}
}
@ -521,6 +439,7 @@ public:
*/
uint GetDesiredInfoHeight(int width) const
{
width -= WidgetDimensions::scaled.framerect.Horizontal();
uint aimed_height = static_cast<uint>(1 + CargoSpec::town_production_cargoes[TPE_PASSENGERS].size() + CargoSpec::town_production_cargoes[TPE_MAIL].size()) * GetCharacterHeight(FS_NORMAL);
bool first = true;
@ -540,23 +459,76 @@ public:
if (_settings_game.economy.station_noise_level) aimed_height += GetCharacterHeight(FS_NORMAL);
if (!this->town->text.empty()) {
aimed_height += GetStringHeight(this->town->text.GetDecodedString(), width - WidgetDimensions::scaled.framerect.Horizontal());
aimed_height += GetStringHeight(this->town->text.GetDecodedString(), width);
}
return aimed_height;
return aimed_height + WidgetDimensions::scaled.framerect.Vertical();
}
void ResizeWindowAsNeeded()
uint GetDesiredRatingHeight(int) const
{
const NWidgetBase *nwid_info = this->GetWidget<NWidgetBase>(WID_TV_INFO);
uint aimed_height = GetDesiredInfoHeight(nwid_info->current_x);
if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) {
this->ReInit();
int lines = 1;
for (const Company *c : Company::Iterate()) {
if ((this->town->have_ratings.Test(c->index) || this->town->exclusivity == c->index)) {
++lines;
}
}
return this->rating_line_height * std::max(3, lines) + WidgetDimensions::scaled.framerect.Vertical();
}
uint GetDesiredActionInfoHeight(int width) const
{
width -= WidgetDimensions::scaled.framerect.Horizontal();
int height = 0;
for (TownAction i = {}; i != TownAction::End; ++i) {
Money price = _price[PR_TOWN_ACTION] * GetTownActionCost(i) >> 8;
height = std::max(height, GetStringHeight(GetString(this->action_tooltips[to_underlying(i)], price), width));
}
return height + WidgetDimensions::scaled.framerect.Vertical();
}
bool UpdatePaneSizes()
{
bool changed = false;
auto *sel = this->GetWidget<NWidgetStacked>(WID_TV_PANE_SEL);
if (sel != nullptr) {
if (auto *nwid = this->GetWidget<NWidgetCore>(WID_TV_INFO); nwid != nullptr) {
uint y = this->visible_pane == 0 ? GetDesiredInfoHeight(nwid->current_x) : 0;
changed |= nwid->UpdateVerticalSize(y);
}
if (auto *nwid = this->GetWidget<NWidgetCore>(WID_TV_RATING_INFO); nwid != nullptr) {
uint y = this->visible_pane == 1 ? GetDesiredRatingHeight(nwid->current_x) : 0;
changed |= nwid->UpdateVerticalSize(y);
}
if (auto *nwid = this->GetWidget<NWidgetCore>(WID_TV_ACTION_INFO); nwid != nullptr) {
uint y = this->visible_pane == 2 ? GetDesiredActionInfoHeight(nwid->current_x) : 0;
changed |= nwid->UpdateVerticalSize(y);
}
}
return changed;
}
void ResizePanes()
{
this->SetPaneState();
/* We want to resize the window while maintaining the size of the viewport. */
auto *nwid = this->GetWidget<NWidgetViewport>(WID_TV_VIEWPORT);
int old_y = static_cast<int>(nwid->current_y);
this->OnResize();
int new_y = static_cast<int>(nwid->current_y);
if (old_y != new_y) ResizeWindow(this, 0, old_y - new_y, false, false);
}
void OnResize() override
{
if (this->UpdatePaneSizes()) this->ReInit(0, 0);
if (this->viewport != nullptr) {
NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_TV_VIEWPORT);
nvp->UpdateViewportCoordinates(this);
@ -573,6 +545,11 @@ public:
}
}
/** Redraw the whole window on a regular interval. */
const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
this->SetDirty();
}};
/**
* Some data on this window has become invalid.
* @param data Information about the changed data.
@ -581,9 +558,16 @@ public:
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
{
if (!gui_scope) return;
/* Called when setting station noise or required cargoes have changed, in order to resize the window */
this->enabled_actions = GetEnabledActions();
this->available_actions = GetMaskOfTownActions(_local_company, this->town);
if (!this->enabled_actions.Test(this->sel_action)) {
this->sel_action = TownAction::End;
}
this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading
this->ResizeWindowAsNeeded();
this->ResizePanes();
}
void OnQueryTextFinished(std::optional<std::string> str) override
@ -614,10 +598,23 @@ static constexpr NWidgetPart _nested_town_game_view_widgets[] = {
NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetResize(1, 1),
EndContainer(),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
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),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(40, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_PANE_INFO), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_INFO, STR_TOWN_VIEW_INFO_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_PANE_RATINGS), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_RATINGS, STR_TOWN_VIEW_RATINGS_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_PANE_ACTIONS), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_ACTIONS, STR_TOWN_VIEW_ACTIONS_TOOLTIP),
EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_TV_PANE_SEL),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetResize(1, 0), SetFill(1, 1), EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_RATING_INFO), SetResize(1, 0), SetFill(1, 1), EndContainer(),
NWidget(NWID_VERTICAL),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_COMMAND_LIST), SetResize(1, 0), SetFill(1, 1), SetToolTip(STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), EndContainer(),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_ACTION_INFO), SetResize(1, 0), SetFill(1, 0), EndContainer(),
EndContainer(),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXECUTE), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_ZONE), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_LOCAL_AUTHORITY_ZONE, STR_LOCAL_AUTHORITY_ZONE_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
EndContainer(),
};

View File

@ -138,15 +138,58 @@ bool HasBridgeFlatRamp(Slope tileh, Axis axis)
return (tileh != SLOPE_FLAT);
}
static inline std::span<const PalSpriteID> GetBridgeSpriteTable(int index, BridgePieces table)
/**
* Get the sprite table for a rail/road bridge piece.
* @param bridge_type Bridge type.
* @param piece Bridge piece.
* @return Sprite table for the bridge piece.
*/
static std::span<const PalSpriteID> GetBridgeSpriteTable(BridgeType bridge_type, BridgePieces piece)
{
const BridgeSpec *bridge = GetBridgeSpec(index);
assert(table < NUM_BRIDGE_PIECES);
if (table < bridge->sprite_table.size() && !bridge->sprite_table[table].empty()) return bridge->sprite_table[table];
assert(piece < NUM_BRIDGE_PIECES);
return _bridge_sprite_table[index][table];
const BridgeSpec *bridge = GetBridgeSpec(bridge_type);
if (piece < bridge->sprite_table.size() && !bridge->sprite_table[piece].empty()) return bridge->sprite_table[piece];
return _bridge_sprite_table[bridge_type][piece];
}
/**
* Get the sprite table transport type base offset for a rail/road bridge.
* @param transport_type Transport type of bridge.
* @param ramp Tile of bridge ramp.
* @return Offset for transport type.
*/
static uint8_t GetBridgeSpriteTableBaseOffset(TransportType transport_type, TileIndex ramp)
{
switch (transport_type) {
case TRANSPORT_RAIL: return GetRailTypeInfo(GetRailType(ramp))->bridge_offset;
case TRANSPORT_ROAD: return 8;
default: NOT_REACHED();
}
}
/**
* Get bridge sprite table base offset for the ramp part of bridge.
* @param diagdir Direction of ramp.
* @return Offset for direction.
*/
static uint8_t GetBridgeRampDirectionBaseOffset(DiagDirection diagdir)
{
/* Bridge ramps are ordered SW, SE, NE, NW instead of NE, SE, SW, NW. */
static constexpr uint8_t ramp_offsets[DIAGDIR_END] = {2, 1, 0, 3};
return ramp_offsets[diagdir];
}
/**
* Get bridge sprite table base offset for the middle part of bridge.
* @param axis Axis of bridge.
* @return Offset for axis.
*/
static uint8_t GetBridgeMiddleAxisBaseOffset(Axis axis)
{
return axis == AXIS_X ? 0 : 4;
}
/**
* Determines the foundation for the bridge head, and tests if the resulting slope is valid.
@ -1017,10 +1060,10 @@ static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlags flags)
* @param h Bounding box size in Y direction
* @param subsprite Optional subsprite for drawing halfpillars
*/
static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, uint8_t w, uint8_t h, const SubSprite *subsprite)
static inline void DrawPillar(const PalSpriteID &psid, int x, int y, int z, uint8_t w, uint8_t h, const SubSprite *subsprite)
{
static const int PILLAR_Z_OFFSET = TILE_HEIGHT - BRIDGE_Z_START; ///< Start offset of pillar wrt. bridge (downwards)
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, -PILLAR_Z_OFFSET}, {w, h, BB_HEIGHT_UNDER_BRIDGE}, {0, 0, PILLAR_Z_OFFSET}}, IsTransparencySet(TO_BRIDGES), subsprite);
AddSortableSpriteToDraw(psid.sprite, psid.pal, x, y, z, {{0, 0, -PILLAR_Z_OFFSET}, {w, h, BB_HEIGHT_UNDER_BRIDGE}, {0, 0, PILLAR_Z_OFFSET}}, IsTransparencySet(TO_BRIDGES), subsprite);
}
/**
@ -1034,7 +1077,7 @@ static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, uint
* @param h Bounding box size in Y direction
* @return Reached Z at the bottom
*/
static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID *psid, int x, int y, int w, int h)
static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID &psid, int x, int y, int w, int h)
{
int cur_z;
for (cur_z = z_top; cur_z >= z_bottom; cur_z -= TILE_HEIGHT) {
@ -1054,7 +1097,7 @@ static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID *psid, in
* @param y Sprite Y position of front pillar.
* @param z_bridge Absolute height of bridge bottom.
*/
static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge)
static void DrawBridgePillars(const PalSpriteID &psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge)
{
static const int bounding_box_size[2] = {16, 2}; ///< bounding box size of pillars along bridge direction
static const int back_pillar_offset[2] = { 0, 9}; ///< sprite position offset of back facing pillar
@ -1065,7 +1108,7 @@ static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo *ti, Axis
{ { -INF, -INF, 15, INF }, { 16, -INF, INF, INF } }, // Y axis, north and south
};
if (psid->sprite == 0) return;
if (psid.sprite == 0) return;
/* Determine ground height under pillars */
DiagDirection south_dir = AxisToDiagDir(axis);
@ -1404,34 +1447,20 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
DrawBridgeMiddle(ti);
} else { // IsBridge(ti->tile)
const PalSpriteID *psid;
int base_offset;
bool ice = HasTunnelBridgeSnowOrDesert(ti->tile);
if (transport_type == TRANSPORT_RAIL) {
base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset;
assert(base_offset != 8); // This one is used for roads
} else {
base_offset = 8;
}
/* as the lower 3 bits are used for other stuff, make sure they are clear */
assert( (base_offset & 0x07) == 0x00);
DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction)));
/* HACK Wizardry to convert the bridge ramp direction into a sprite offset */
base_offset += (6 - tunnelbridge_direction) % 4;
/* Table number BRIDGE_PIECE_HEAD always refers to the bridge heads for any bridge type */
uint base_offset = GetBridgeRampDirectionBaseOffset(tunnelbridge_direction);
std::span<const PalSpriteID> psid;
if (transport_type != TRANSPORT_WATER) {
if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head
psid = &GetBridgeSpriteTable(GetBridgeType(ti->tile), BRIDGE_PIECE_HEAD)[base_offset];
base_offset += GetBridgeSpriteTableBaseOffset(transport_type, ti->tile);
psid = GetBridgeSpriteTable(GetBridgeType(ti->tile), BRIDGE_PIECE_HEAD);
} else {
psid = _aqueduct_sprites + base_offset;
psid = _aqueduct_sprite_table_heads;
}
psid = psid.subspan(base_offset, 1);
if (!ice) {
if (!HasTunnelBridgeSnowOrDesert(ti->tile)) {
TileIndex next = ti->tile + TileOffsByDiagDir(tunnelbridge_direction);
if (ti->tileh != SLOPE_FLAT && ti->z == 0 && HasTileWaterClass(next) && GetWaterClass(next) == WATER_CLASS_SEA) {
DrawShoreTile(ti->tileh);
@ -1451,7 +1480,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
* it doesn't disappear behind it
*/
/* Bridge heads are drawn solid no matter how invisibility/transparency is set */
AddSortableSpriteToDraw(psid->sprite, psid->pal, *ti, {{}, {TILE_SIZE, TILE_SIZE, static_cast<uint8_t>(ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)}, {}});
AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, *ti, {{}, {TILE_SIZE, TILE_SIZE, static_cast<uint8_t>(ti->tileh == SLOPE_FLAT ? 0 : TILE_HEIGHT)}, {}});
if (transport_type == TRANSPORT_ROAD) {
uint offset = tunnelbridge_direction;
@ -1572,33 +1601,21 @@ void DrawBridgeMiddle(const TileInfo *ti)
TileIndex rampnorth = GetNorthernBridgeEnd(ti->tile);
TileIndex rampsouth = GetSouthernBridgeEnd(ti->tile);
TransportType transport_type = GetTunnelBridgeTransportType(rampsouth);
Axis axis = GetBridgeAxis(ti->tile);
BridgePieces piece = CalcBridgePiece(
GetTunnelBridgeLength(ti->tile, rampnorth) + 1,
GetTunnelBridgeLength(ti->tile, rampsouth) + 1
);
const PalSpriteID *psid;
uint base_offset = GetBridgeMiddleAxisBaseOffset(axis);
std::span<const PalSpriteID> psid;
bool drawfarpillar;
if (transport_type != TRANSPORT_WATER) {
BridgeType type = GetBridgeType(rampsouth);
drawfarpillar = !HasBit(GetBridgeSpec(type)->flags, 0);
uint base_offset;
if (transport_type == TRANSPORT_RAIL) {
base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset;
} else {
base_offset = 8;
}
psid = &GetBridgeSpriteTable(type, piece)[base_offset];
BridgeType bridge_type = GetBridgeType(rampsouth);
drawfarpillar = !HasBit(GetBridgeSpec(bridge_type)->flags, 0);
base_offset += GetBridgeSpriteTableBaseOffset(transport_type, rampsouth);
psid = GetBridgeSpriteTable(bridge_type, CalcBridgePiece(GetTunnelBridgeLength(ti->tile, rampnorth) + 1, GetTunnelBridgeLength(ti->tile, rampsouth) + 1));
} else {
drawfarpillar = true;
psid = _aqueduct_sprites;
psid = _aqueduct_sprite_table_middle;
}
if (axis != AXIS_X) psid += 4;
psid = psid.subspan(base_offset, 3);
int x = ti->x;
int y = ti->y;
@ -1614,14 +1631,12 @@ void DrawBridgeMiddle(const TileInfo *ti)
/* Draw floor and far part of bridge*/
if (!IsInvisibilitySet(TO_BRIDGES)) {
if (axis == AXIS_X) {
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
} else {
AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
AddSortableSpriteToDraw(psid[0].sprite, psid[0].pal, x, y, z, {{0, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {0, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
}
}
psid++;
if (transport_type == TRANSPORT_ROAD) {
/* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */
DrawBridgeRoadBits(rampsouth, x, y, bridge_z, axis ^ 1, false);
@ -1654,10 +1669,10 @@ void DrawBridgeMiddle(const TileInfo *ti)
if (!IsInvisibilitySet(TO_BRIDGES)) {
if (axis == AXIS_X) {
y += 12;
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{0, 3, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, -3, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
if (psid[1].sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid[1].sprite, psid[1].pal, x, y, z, {{0, 3, BRIDGE_Z_START}, {TILE_SIZE, 1, 40}, {0, -3, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
} else {
x += 12;
if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, z, {{3, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {-3, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
if (psid[1].sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid[1].sprite, psid[1].pal, x, y, z, {{3, 0, BRIDGE_Z_START}, {1, TILE_SIZE, 40}, {-3, 0, -BRIDGE_Z_START}}, IsTransparencySet(TO_BRIDGES));
}
}
@ -1667,8 +1682,7 @@ void DrawBridgeMiddle(const TileInfo *ti)
/* Do not draw anything more if bridges are invisible */
if (IsInvisibilitySet(TO_BRIDGES)) return;
psid++;
DrawBridgePillars(psid, ti, axis, drawfarpillar, x, y, z);
DrawBridgePillars(psid[2], ti, axis, drawfarpillar, x, y, z);
}

View File

@ -21,30 +21,27 @@ enum TownDirectoryWidgets : WidgetID {
WID_TD_WORLD_POPULATION, ///< The world's population.
};
/** Widgets of the #TownAuthorityWindow class. */
enum TownAuthorityWidgets : WidgetID {
WID_TA_CAPTION, ///< Caption of window.
WID_TA_ZONE_BUTTON, ///< Turn on/off showing local authority zone.
WID_TA_RATING_INFO, ///< Overview with ratings for each company.
WID_TA_COMMAND_LIST, ///< List of commands for the player.
WID_TA_SCROLLBAR, ///< Scrollbar of the list of commands.
WID_TA_ACTION_INFO, ///< Additional information about the action.
WID_TA_EXECUTE, ///< Do-it button.
};
/** Widgets of the #TownViewWindow class. */
enum TownViewWidgets : WidgetID {
WID_TV_CAPTION, ///< Caption of window.
WID_TV_VIEWPORT, ///< View of the center of the town.
WID_TV_INFO, ///< General information about the town.
WID_TV_CENTER_VIEW, ///< Center the main view on this town.
WID_TV_SHOW_AUTHORITY, ///< Show the town authority window.
WID_TV_CHANGE_NAME, ///< Change the name of this town.
WID_TV_CATCHMENT, ///< Toggle catchment area highlight.
WID_TV_EXPAND, ///< Expand this town (scenario editor only).
WID_TV_EXPAND_BUILDINGS, ///< Expand number of buildings this town (scenario editor only).
WID_TV_EXPAND_ROADS, ///< Expand roads of this town (scenario editor only).
WID_TV_DELETE, ///< Delete this town (scenario editor only).
WID_TV_PANE_SEL,
WID_TV_PANE_INFO,
WID_TV_PANE_RATINGS,
WID_TV_PANE_ACTIONS,
WID_TV_RATING_INFO, ///< Overview with ratings for each company.
WID_TV_COMMAND_LIST, ///< List of commands for the player.
WID_TV_ACTION_INFO, ///< Additional information about the action.
WID_TV_EXECUTE, ///< Do-it button.
WID_TV_ZONE, ///< Turn on/off showing local authority zone.
};
/** Widgets of the #FoundTownWindow class. */

View File

@ -189,12 +189,6 @@ enum WindowClass : uint16_t {
WC_TEXTFILE,
/**
* Town authority; %Window numbers:
* - #TownID = #TownAuthorityWidgets
*/
WC_TOWN_AUTHORITY,
/**
* Vehicle details; %Window numbers:
* - #VehicleID = #VehicleDetailsWidgets