From 59645c67335447e03721a67ebb3de083947dbb81 Mon Sep 17 00:00:00 2001 From: Joel-Milligan <52927756+Joel-Milligan@users.noreply.github.com> Date: Sat, 12 Nov 2022 06:52:38 +0800 Subject: [PATCH] Change: Remove scrollbar from town authority actions panel (#9928) --- src/lang/english.txt | 16 +-- src/script/api/script_town.cpp | 2 +- src/table/settings/economy_settings.ini | 8 +- src/town.h | 24 ++--- src/town_cmd.cpp | 12 +-- src/town_gui.cpp | 132 ++++++++++++++---------- 6 files changed, 109 insertions(+), 85 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index 9ddae0f670..a13bfebe7c 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3482,14 +3482,14 @@ STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Buy exclusive t STR_LOCAL_AUTHORITY_ACTION_BRIBE :Bribe the local authority ###length 8 -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Initiate a small local advertising campaign, to attract more passengers and cargo to your transport services.{}Provides a temporary boost to station rating in a small radius around the town centre.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Initiate a medium local advertising campaign, to attract more passengers and cargo to your transport services.{}Provides a temporary boost to station rating in a medium radius around the town centre.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Initiate a large local advertising campaign, to attract more passengers and cargo to your transport services.{}Provides a temporary boost to station rating in a large radius around the town centre.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Fund the reconstruction of the urban road network.{}Causes considerable disruption to road traffic for up to 6 months.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Build a statue in honour of your company.{}Provides a permanent boost to station rating in this town.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Fund the construction of new buildings in the town.{}Provides a temporary boost to town growth in this town.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Buy 1 year's exclusive transport rights in town.{}Town authority will not allow passengers and cargo to use your competitors' stations.{}Cost: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Bribe the local authority to increase your rating, at the risk of a severe penalty if caught.{}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{PUSH_COLOUR}{YELLOW}Initiate a small local advertising campaign, to attract more passengers and cargo to your transport services.{}Provides a temporary boost to station rating in a small radius around the town centre.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{PUSH_COLOUR}{YELLOW}Initiate a medium local advertising campaign, to attract more passengers and cargo to your transport services.{}Provides a temporary boost to station rating in a medium radius around the town centre.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{PUSH_COLOUR}{YELLOW}Initiate a large local advertising campaign, to attract more passengers and cargo to your transport services.{}Provides a temporary boost to station rating in a large radius around the town centre.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{PUSH_COLOUR}{YELLOW}Fund the reconstruction of the urban road network.{}Causes considerable disruption to road traffic for up to 6 months.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{PUSH_COLOUR}{YELLOW}Build a statue in honour of your company.{}Provides a permanent boost to station rating in this town.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{PUSH_COLOUR}{YELLOW}Fund the construction of new buildings in the town.{}Provides a temporary boost to town growth in this town.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{PUSH_COLOUR}{YELLOW}Buy 1 year's exclusive transport rights in town.{}Town authority will not allow passengers and cargo to use your competitors' stations.{}{POP_COLOUR}Cost: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{PUSH_COLOUR}{YELLOW}Bribe the local authority to increase your rating, at the risk of a severe penalty if caught.{}{POP_COLOUR}Cost: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} Goals diff --git a/src/script/api/script_town.cpp b/src/script/api/script_town.cpp index 78a1734441..afa309c92b 100644 --- a/src/script/api/script_town.cpp +++ b/src/script/api/script_town.cpp @@ -258,7 +258,7 @@ if (ScriptObject::GetCompany() == OWNER_DEITY) return false; if (!IsValidTown(town_id)) return false; - return HasBit(::GetMaskOfTownActions(nullptr, ScriptObject::GetCompany(), ::Town::Get(town_id)), town_action); + return HasBit(::GetMaskOfTownActions(ScriptObject::GetCompany(), ::Town::Get(town_id)), town_action); } /* static */ bool ScriptTown::PerformTownAction(TownID town_id, TownAction town_action) diff --git a/src/table/settings/economy_settings.ini b/src/table/settings/economy_settings.ini index 0101e1bf98..ad2a74319d 100644 --- a/src/table/settings/economy_settings.ini +++ b/src/table/settings/economy_settings.ini @@ -123,7 +123,7 @@ var = economy.bribe def = true str = STR_CONFIG_SETTING_BRIBE strhelp = STR_CONFIG_SETTING_BRIBE_HELPTEXT -post_cb = [](auto) { SetWindowClassesDirty(WC_TOWN_AUTHORITY); } +post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_AUTHORITY); } cat = SC_BASIC [SDT_BOOL] @@ -132,7 +132,7 @@ from = SLV_79 def = true str = STR_CONFIG_SETTING_ALLOW_EXCLUSIVE strhelp = STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT -post_cb = [](auto) { SetWindowClassesDirty(WC_TOWN_AUTHORITY); } +post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_AUTHORITY); } cat = SC_BASIC [SDT_BOOL] @@ -141,7 +141,7 @@ from = SLV_165 def = true str = STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS strhelp = STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT -post_cb = [](auto) { SetWindowClassesDirty(WC_TOWN_AUTHORITY); } +post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_AUTHORITY); } cat = SC_BASIC [SDT_BOOL] @@ -150,7 +150,7 @@ from = SLV_160 def = true str = STR_CONFIG_SETTING_ALLOW_FUND_ROAD strhelp = STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT -post_cb = [](auto) { SetWindowClassesDirty(WC_TOWN_AUTHORITY); } +post_cb = [](auto) { InvalidateWindowClassesData(WC_TOWN_AUTHORITY); } cat = SC_BASIC [SDT_BOOL] diff --git a/src/town.h b/src/town.h index 76b6e9c15c..2dda7cf2e9 100644 --- a/src/town.h +++ b/src/town.h @@ -200,18 +200,6 @@ Town *CalcClosestTownFromTile(TileIndex tile, uint threshold = UINT_MAX); void ResetHouses(); -void ClearTownHouse(Town *t, TileIndex tile); -void UpdateTownMaxPass(Town *t); -void UpdateTownRadius(Town *t); -CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags); -Town *ClosestTownFromTile(TileIndex tile, uint threshold); -void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags); -HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile); -void SetTownRatingTestMode(bool mode); -uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t); -bool GenerateTowns(TownLayout layout); -const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect); - /** Town actions of a company. */ enum TownActions { TACT_NONE = 0x00, ///< Empty action set. @@ -234,6 +222,18 @@ enum TownActions { }; DECLARE_ENUM_AS_BIT_SET(TownActions) +void ClearTownHouse(Town *t, TileIndex tile); +void UpdateTownMaxPass(Town *t); +void UpdateTownRadius(Town *t); +CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags); +Town *ClosestTownFromTile(TileIndex tile, uint threshold); +void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags); +HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile); +void SetTownRatingTestMode(bool mode); +TownActions GetMaskOfTownActions(CompanyID cid, const Town *t); +bool GenerateTowns(TownLayout layout); +const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect); + extern const byte _town_action_costs[TACT_COUNT]; /** diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index a07946029c..680bffda2f 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -3293,21 +3293,19 @@ static TownActionProc * const _town_action_proc[] = { /** * Get a list of available actions to do at a town. - * @param nump if not nullptr add put the number of available actions in it * @param cid the company that is querying the town * @param t the town that is queried * @return bitmasked value of enabled actions */ -uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t) +TownActions GetMaskOfTownActions(CompanyID cid, const Town *t) { - int num = 0; TownActions buttons = TACT_NONE; /* Spectators and unwanted have no options */ if (cid != COMPANY_SPECTATOR && !(_settings_game.economy.bribe && t->unwanted[cid])) { - /* Things worth more than this are not shown */ - Money avail = Company::Get(cid)->money + _price[PR_STATION_VALUE] * 200; + /* Actions worth more than this are not able to be performed */ + Money avail = Company::Get(cid)->money; /* Check the action bits for validity and * if they are valid add them */ @@ -3331,12 +3329,10 @@ uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t) if (avail >= _town_action_costs[i] * _price[PR_TOWN_ACTION] >> 8) { buttons |= cur; - num++; } } } - if (nump != nullptr) *nump = num; return buttons; } @@ -3354,7 +3350,7 @@ CommandCost CmdDoTownAction(DoCommandFlag flags, TownID town_id, uint8 action) Town *t = Town::GetIfValid(town_id); if (t == nullptr || action >= lengthof(_town_action_proc)) return CMD_ERROR; - if (!HasBit(GetMaskOfTownActions(nullptr, _current_company, t), action)) return CMD_ERROR; + if (!HasBit(GetMaskOfTownActions(_current_company, t), action)) return CMD_ERROR; CommandCost cost(EXPENSES_OTHER, _price[PR_TOWN_ACTION] * _town_action_costs[action] >> 8); diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 216de7e79a..95a08a8e13 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -56,10 +56,7 @@ static const NWidgetPart _nested_town_authority_widgets[] = { NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(305, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), SetScrollbar(WID_TA_SCROLLBAR), EndContainer(), - NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TA_SCROLLBAR), - EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(317, 52), SetResize(1, 0), SetDataTip(0x0, 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), SetDataTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP), @@ -72,22 +69,22 @@ struct TownAuthorityWindow : Window { private: Town *town; ///< Town being displayed. int sel_index; ///< Currently selected town action, \c 0 to \c TACT_COUNT-1, \c -1 means no action selected. - Scrollbar *vscroll; uint 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. /** * Get the position of the Nth set bit. * * If there is no Nth bit set return -1 * - * @param bits The value to search in * @param n The Nth set bit from which we want to know the position - * @return The position of the Nth set bit + * @return The position of the Nth set bit, or -1 if no Nth bit set. */ - static int GetNthSetBit(uint32 bits, int n) + int GetNthSetBit(int n) { if (n >= 0) { - for (uint i : SetBitIterator(bits)) { + for (uint i : SetBitIterator(this->enabled_actions)) { n--; if (n < 0) return i; } @@ -95,33 +92,46 @@ private: return -1; } + /** + * Gets all town authority actions enabled in settings. + * + * @return Bitmask of actions enabled in the settings. + */ + static TownActions GetEnabledActions() + { + TownActions enabled = TACT_ALL; + + if (!_settings_game.economy.fund_roads) CLRBITS(enabled, TACT_ROAD_REBUILD); + if (!_settings_game.economy.fund_buildings) CLRBITS(enabled, TACT_FUND_BUILDINGS); + if (!_settings_game.economy.exclusive_rights) CLRBITS(enabled, TACT_BUY_RIGHTS); + if (!_settings_game.economy.bribe) CLRBITS(enabled, TACT_BRIBE); + + return enabled; + } + public: - TownAuthorityWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), sel_index(-1), displayed_actions_on_previous_painting(0) + TownAuthorityWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), sel_index(-1), displayed_actions_on_previous_painting(0), available_actions(TACT_NONE) { this->town = Town::Get(window_number); + this->enabled_actions = GetEnabledActions(); this->InitNested(window_number); - this->vscroll = this->GetScrollbar(WID_TA_SCROLLBAR); - this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / FONT_HEIGHT_NORMAL); } void OnPaint() override { - int numact; - uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); - if (buttons != displayed_actions_on_previous_painting) this->SetDirty(); - displayed_actions_on_previous_painting = buttons; - - this->vscroll->SetCount(numact + 1); - - if (this->sel_index != -1 && !HasBit(buttons, this->sel_index)) { - this->sel_index = -1; - } + 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_index == -1); + this->SetWidgetDisabledState(WID_TA_EXECUTE, (this->sel_index == -1) || !HasBit(this->available_actions, this->sel_index)); this->DrawWidgets(); - if (!this->IsShaded()) this->DrawRatings(); + if (!this->IsShaded()) + { + this->DrawRatings(); + this->DrawActions(); + } } /** Draw the contents of the ratings panel. May request a resize of the window if the contents does not fit. */ @@ -185,6 +195,32 @@ public: } } + /** Draws the contents of the actions panel. May re-initialise window to resize panel, if the list does not fit. */ + void DrawActions() + { + NWidgetBase *nwid = this->GetWidget(WID_TA_COMMAND_LIST); + uint left = nwid->pos_x + WD_FRAMERECT_LEFT; + uint right = nwid->pos_x + nwid->current_x - 1 - WD_FRAMERECT_RIGHT; + uint y = nwid->pos_y + WD_FRAMERECT_TOP; + + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE); + y += FONT_HEIGHT_NORMAL; + + /* Draw list of actions */ + for (int i = 0; i < TACT_COUNT; i++) { + /* Don't show actions if disabled in settings. */ + if (!HasBit(this->enabled_actions, i)) continue; + + /* Set colour of action based on ability to execute and if selected. */ + TextColour action_colour = TC_GREY | TC_NO_SHADE; + if (HasBit(this->available_actions, i)) action_colour = TC_ORANGE; + if (this->sel_index == i) action_colour = TC_WHITE; + + DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, action_colour); + y += FONT_HEIGHT_NORMAL; + } + } + void SetStringParameters(int widget) const override { if (widget == WID_TA_CAPTION) SetDParam(0, this->window_number); @@ -195,33 +231,15 @@ public: switch (widget) { case WID_TA_ACTION_INFO: if (this->sel_index != -1) { - SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[this->sel_index] >> 8); - DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, - STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + this->sel_index); - } - break; - case WID_TA_COMMAND_LIST: { - int numact; - uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); - int y = r.top + WD_FRAMERECT_TOP; - int pos = this->vscroll->GetPosition(); - - if (--pos < 0) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE); - y += FONT_HEIGHT_NORMAL; - } - - for (int i = 0; buttons; i++, buttons >>= 1) { - if (pos <= -5) break; ///< Draw only the 5 fitting lines + Money action_cost = _price[PR_TOWN_ACTION] * _town_action_costs[this->sel_index] >> 8; + bool affordable = action_cost < Company::GetIfValid(_local_company)->money; - if ((buttons & 1) && --pos < 0) { - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, - STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE); - y += FONT_HEIGHT_NORMAL; - } + SetDParam(0, action_cost); + DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, + STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + this->sel_index, + affordable ? TC_YELLOW : TC_RED); } break; - } } } @@ -244,7 +262,7 @@ public: } case WID_TA_COMMAND_LIST: - size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; + size->height = WD_FRAMERECT_TOP + (TACT_COUNT + 1) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width; for (uint i = 0; i < TACT_COUNT; i++ ) { size->width = std::max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width); @@ -275,14 +293,14 @@ public: } case WID_TA_COMMAND_LIST: { - int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, FONT_HEIGHT_NORMAL); - if (!IsInsideMM(y, 0, 5)) return; + int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, FONT_HEIGHT_NORMAL) - 1; - y = GetNthSetBit(GetMaskOfTownActions(nullptr, _local_company, this->town), y + this->vscroll->GetPosition() - 1); + y = GetNthSetBit(y); if (y >= 0) { this->sel_index = y; this->SetDirty(); } + /* When double-clicking, continue */ if (click_count == 1 || y < 0) break; FALLTHROUGH; @@ -298,6 +316,16 @@ public: { this->SetDirty(); } + + void OnInvalidateData(int data = 0, bool gui_scope = true) override + { + if (!gui_scope) return; + + this->enabled_actions = this->GetEnabledActions(); + if (!HasBit(this->enabled_actions, this->sel_index)) { + this->sel_index = -1; + } + } }; static WindowDesc _town_authority_desc(