Remove old house placer window, functionality and settings

This commit is contained in:
Jonathan G Rennison 2024-09-02 18:28:38 +01:00
parent db4b489fff
commit fe84080c46
16 changed files with 17 additions and 1133 deletions

View File

@ -523,7 +523,6 @@ add_files(
town.h
town_cmd.cpp
town_gui.cpp
town_gui.h
town_kdtree.h
town_map.h
town_type.h

View File

@ -65,7 +65,6 @@ CommandProc CmdTerraformLand;
CommandProc CmdBuildObject;
CommandProc CmdPurchaseLandArea;
CommandProc CmdBuildObjectArea;
CommandProc CmdBuildHouse;
CommandProc CmdSellLandArea;
CommandProc CmdBuildTunnel;
@ -345,7 +344,6 @@ static const Command _command_proc_table[] = {
DEF_CMD(CmdBuildObject, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_OBJECT
DEF_CMD(CmdPurchaseLandArea, CMD_NO_WATER | CMD_AUTO | CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_PURCHASE_LAND_AREA
DEF_CMD(CmdBuildObjectArea, CMD_NO_WATER | CMD_AUTO | CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_OBJECT_AREA
DEF_CMD(CmdBuildHouse, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_HOUSE
DEF_CMD(CmdBuildTunnel, CMD_DEITY | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_TUNNEL
DEF_CMD(CmdRemoveFromRailStation, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_FROM_RAIL_STATION
DEF_CMD(CmdConvertRail, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CONVERT_RAIL

View File

@ -287,7 +287,6 @@ enum Commands {
CMD_BUILD_OBJECT, ///< build an object
CMD_PURCHASE_LAND_AREA, ///< purchase an area of landscape
CMD_BUILD_OBJECT_AREA, ///< build an area of objects
CMD_BUILD_HOUSE, ///< build a house
CMD_BUILD_TUNNEL, ///< build a tunnel
CMD_REMOVE_FROM_RAIL_STATION, ///< remove a (rectangle of) tiles from a rail station

View File

@ -147,8 +147,5 @@ inline HouseID GetTranslatedHouseID(HouseID hid)
void ShowBuildHousePicker(struct Window *);
StringID GetHouseName(HouseID house, TileIndex tile = INVALID_TILE);
void DrawHouseImage(HouseID house_id, int left, int top, int right, int bottom);
void AddProducedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &produced);
void AddAcceptedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &acceptance, CargoTypes *always_accepted = nullptr);
#endif /* HOUSE_H */

View File

@ -104,8 +104,6 @@ STR_SORT_BY_VEHICLES_CALLING :Number of vehic
STR_SORT_BY_CARGO_CAPACITY_VS_RUNNING_COST :Cargo capacity/Running cost
STR_SORT_BY_VEHICLE_COUNT :Vehicle count
STR_SCENEDIT_TOOLBAR_PLACE_HOUSE :{BLACK}Place house
STR_SETTINGS_MENU_ZONING :Zoning
STR_SETTINGS_MENU_MONEY_TEXT_EFFECTS :Income/cost texts displayed
@ -711,7 +709,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST_PER_CARGO_OVERRIDE :{ORANGE}Cargo d
STR_CONFIG_SETTING_VIEWPORT_MAP_OPTIONS :{ORANGE}Map mode
STR_CONFIG_SETTING_VEHICLE_ROUTE_OVERLAY :{ORANGE}Vehicle route overlay
STR_CONFIG_SETTING_SHARING :{ORANGE}Infrastructure sharing
STR_CONFIG_SETTING_SCENARIO_EDITOR :{ORANGE}Scenario Editor
STR_CONFIG_SETTING_REROUTE_RV_ON_LAYOUT_CHANGE :Re-route road vehicles when road layout changes: {STRING2}
STR_CONFIG_SETTING_REROUTE_RV_ON_LAYOUT_CHANGE_HELPTEXT :Whether to re-route all road vehicles on the map when the road layout is changed.{}This can improve road vehicle responsiveness to a changing road layout at the expense of performance.{}Note that if this is set to "Yes", town growth can trigger re-routing of road vehicles which may cause slow-downs on large maps.
@ -796,20 +793,6 @@ STR_CONFIG_SETTING_COPY_CLONE_ADD_TO_GROUP_HELPTEXT :Set whether clo
STR_CONFIG_SETTING_REMAIN_IF_NEXT_ORDER_SAME_STATION :Remain in station if next order is for same station: {STRING2}
STR_CONFIG_SETTING_REMAIN_IF_NEXT_ORDER_SAME_STATION_HELPTEXT :If a vehicle's next order is for the same station it would be about to leave, start loading/unloading again instead of leaving.
STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS :Allow multiple churches/stadiums: {STRING2}
STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS_HELPTEXT :Allow manually adding churches and stadiums when there is already one present in the town.
STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_DATES :Ignore house year restrictions: {STRING2}
STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_DATES_HELPTEXT :Allow manually adding houses which are not available for the current date.
STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES :Ignore house zone restrictions: {STRING2}
STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES_HELPTEXT :Allow manually adding houses which are not suitable for the target town zone.
STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_GRF :Ignore house GRF restrictions: {STRING2}
STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_GRF_HELPTEXT :Allow manually adding houses even if this is not permitted by the house GRF.
STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES_OFF :Off
STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES_WITHIN_TOWN :Within town
STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES_ANYWHERE :Anywhere
STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS :When auto-fill dragging, continue past stations/waypoints: {STRING2}
STR_CONFIG_SETTING_DRAG_SIGNALS_SKIP_STATIONS_HELPTEXT :Select the behaviour of signal placement when Ctrl+dragging signals. If disabled, signal placement stops when reaching a station/waypoint tile. If enabled, signal placement continues on the far side of rail stations/waypoints
@ -1255,36 +1238,6 @@ STR_WATERWAYS_TOOLBAR_CREATE_RIVER_IN_GAME_TOOLTIP :{BLACK}Place ri
STR_LANDSCAPING_TOOLTIP_RULER_TOOL :{BLACK}Use a virtual ruler to measure distance and height
#House construction window (for SE only)
STR_HOUSE_BUILD_CAPTION :{WHITE}House Selection
STR_HOUSE_BUILD_CUSTOM_CAPTION :{WHITE}{RAW_STRING}
STR_HOUSE_BUILD_HOUSESET_LIST_TOOLTIP :{BLACK}Select set of houses
STR_HOUSE_BUILD_SELECT_HOUSE_TOOLTIP :{BLACK}Select house to build
STR_HOUSE_BUILD_HOUSE_NAME :{GOLD}{STRING1}
STR_HOUSE_BUILD_HISTORICAL_BUILDING :{GOLD}(historical building)
STR_HOUSE_BUILD_HOUSE_POPULATION :{BLACK}Population: {GOLD}{NUM}
STR_HOUSE_BUILD_HOUSE_ZONES :{BLACK}House zones: {STRING1} {STRING1} {STRING1} {STRING1} {STRING1}
STR_HOUSE_BUILD_HOUSE_ZONE_DISABLED :{GRAY}{NUM}
STR_HOUSE_BUILD_HOUSE_ZONE_ENABLED :{GOLD}{NUM}
STR_HOUSE_BUILD_LANDSCAPE :{BLACK}Landscape: {STRING}
STR_HOUSE_BUILD_LANDSCAPE_ABOVE_OR_BELOW_SNOWLINE :{GOLD}above or below snowline
STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE :{GOLD}only above snowline
STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE :{GOLD}only below snowline
STR_HOUSE_BUILD_YEARS :{BLACK}Years: {STRING1}{GOLD} - {STRING1}
STR_HOUSE_BUILD_YEARS_BAD_YEAR :{RED}{NUM}
STR_HOUSE_BUILD_YEARS_GOOD_YEAR :{GOLD}{NUM}
STR_HOUSE_BUILD_SUPPLIED_CARGO :{BLACK}Supplies: {GOLD}{CARGO_LIST}
STR_HOUSE_BUILD_ACCEPTED_CARGO :{BLACK}Accepts: {GOLD}{RAW_STRING}
STR_HOUSE_BUILD_CARGO_FIRST :{STRING2}
STR_HOUSE_BUILD_CARGO_SEPARATED :, {STRING2}
STR_HOUSE_BUILD_CARGO_VALUE_JUST_NAME :{1:STRING}
STR_HOUSE_BUILD_CARGO_VALUE_EIGHTS :({COMMA}/8 {STRING})
STR_BASIC_HOUSE_SET_NAME :Basic houses
#Town select window (for SE only)
STR_SELECT_TOWN_CAPTION :{WHITE}Select town
STR_SELECT_TOWN_LIST_ITEM :{BLACK}{TOWN}
STR_TREES_REMOVE_TREES_BUTTON :{BLACK}Remove all Trees
STR_TREES_REMOVE_TREES_TOOLTIP :{BLACK}Remove all Trees over landscape
@ -1956,7 +1909,6 @@ STR_GAME_SAVELOAD_ERROR_HELI_OILRIG_BUG :Savegame has a
STR_QUERY_CLEAR_AREA_CAPTION :{WHITE}Clear area
STR_CLEAR_AREA_CONFIRMATION_TEXT :{YELLOW}You are about to destroy an important structure. Are you sure?
STR_ERROR_CAN_T_BUILD_HOUSE_HERE :{WHITE}Can't build house here...
STR_ERROR_BUILDING_NOT_ALLOWED_IN_THIS_TOWN_ZONE :{WHITE}... not allowed in this town zone.
STR_ERROR_BUILDING_NOT_ALLOWED_ABOVE_SNOW_LINE :{WHITE}... not allowed above the snow line.
STR_ERROR_BUILDING_NOT_ALLOWED_BELOW_SNOW_LINE :{WHITE}... not allowed below the snow line.
@ -1965,8 +1917,6 @@ STR_ERROR_TOO_MANY_HOUSE_TYPES :{WHITE}... too
STR_ERROR_BUILDING_IS_TOO_OLD :{WHITE}... building is too old.
STR_ERROR_BUILDING_IS_TOO_MODERN :{WHITE}... building is too modern.
STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN :{WHITE}... only one building of this type is allowed in a town.
STR_ERROR_NO_MORE_BUILDINGS_ALLOWED_PER_TOWN :{WHITE}... too many buildings of this type in the town.
STR_ERROR_BUILDING_NOT_ALLOWED :{WHITE}... the building is not allowed.
STR_ERROR_TOO_MANY_DOCKS :{WHITE}Too many docks
STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT :{WHITE}Can't build road waypoint here...
STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT :{WHITE}Can't remove road waypoint here...

View File

@ -131,35 +131,6 @@ uint32_t HouseResolverObject::GetDebugID() const
return HouseSpec::Get(this->house_scope.house_id)->grf_prop.local_id;
}
/**
* Construct a resolver for a fake house.
* @param house_id House to query.
* @param callback Callback ID.
* @param param1 First parameter (var 10) of the callback.
* @param param2 Second parameter (var 18) of the callback.
* @param not_yet_constructed House is still under construction.
* @param initial_random_bits Random bits during construction checks.
* @param watched_cargo_triggers Cargo types that triggered the watched cargo callback.
*/
FakeHouseResolverObject::FakeHouseResolverObject(HouseID house_id,
CallbackID callback, uint32_t param1, uint32_t param2)
: ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2),
house_scope(*this, house_id),
town_scope(*this) // Don't access StorePSA if house is not yet constructed.
{
this->root_spritegroup = HouseSpec::Get(house_id)->grf_prop.spritegroup[0];
}
GrfSpecFeature FakeHouseResolverObject::GetFeature() const
{
return GSF_HOUSES;
}
uint32_t FakeHouseResolverObject::GetDebugID() const
{
return HouseSpec::Get(this->house_scope.house_id)->grf_prop.local_id;
}
void ResetHouseClassIDs()
{
_class_mapping.clear();
@ -637,14 +608,9 @@ uint32_t HouseScopeResolver::OtherHouseIDVariable(uint32_t parameter, F func) co
uint16_t GetHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, HouseID house_id, Town *town, TileIndex tile,
bool not_yet_constructed, uint8_t initial_random_bits, CargoTypes watched_cargo_triggers, int view)
{
if (tile != INVALID_TILE) {
HouseResolverObject object(house_id, tile, town, callback, param1, param2,
not_yet_constructed, initial_random_bits, watched_cargo_triggers, view);
return object.ResolveCallback();
} else {
FakeHouseResolverObject object(house_id, callback, param1, param2);
return object.ResolveCallback();
}
HouseResolverObject object(house_id, tile, town, callback, param1, param2,
not_yet_constructed, initial_random_bits, watched_cargo_triggers, view);
return object.ResolveCallback();
}
/**
@ -705,26 +671,6 @@ static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *grou
DrawNewGRFTileSeq(ti, dts, TO_HOUSES, stage, palette);
}
static void DrawTileLayoutInGUI(int x, int y, const TileLayoutSpriteGroup *group, HouseID house_id, bool ground)
{
uint8_t stage = TOWN_HOUSE_COMPLETED;
const DrawTileSprites *dts = group->ProcessRegisters(&stage);
PaletteID palette = GetHouseColour(house_id);
if (ground) {
PalSpriteID image = dts->ground;
if (HasBit(image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) image.sprite += stage;
if (HasBit(image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) image.pal += stage;
if (GB(image.sprite, 0, SPRITE_WIDTH) != 0) {
DrawSprite(image.sprite, GroundSpritePaletteTransform(image.sprite, image.pal, palette), x, y);
}
} else {
DrawNewGRFTileSeqInGUI(x, y, dts, stage, palette);
}
}
void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
{
const HouseSpec *hs = HouseSpec::Get(house_id);
@ -751,15 +697,6 @@ void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
}
}
void DrawNewHouseTileInGUI(int x, int y, HouseID house_id, bool ground)
{
FakeHouseResolverObject object(house_id);
const SpriteGroup *group = object.Resolve();
if (group != nullptr && group->type == SGT_TILELAYOUT) {
DrawTileLayoutInGUI(x, y, (const TileLayoutSpriteGroup*)group, house_id, ground);
}
}
/* Simple wrapper for GetHouseCallback to keep the animation unified. */
uint16_t GetSimpleHouseCallback(CallbackID callback, uint32_t param1, uint32_t param2, const HouseSpec *spec, Town *town, TileIndex tile, CargoTypes extra_data)
{

View File

@ -97,27 +97,6 @@ struct HouseResolverObject : public ResolverObject {
uint32_t GetDebugID() const override;
};
/** Resolver object to be used for fake houses (feature 07 spritegroups). */
struct FakeHouseResolverObject : public ResolverObject {
FakeHouseScopeResolver house_scope;
FakeTownScopeResolver town_scope;
FakeHouseResolverObject(HouseID house_id,
CallbackID callback = CBID_NO_CALLBACK, uint32_t param1 = 0, uint32_t param2 = 0);
ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, VarSpriteGroupScopeOffset relative = 0) override
{
switch (scope) {
case VSG_SCOPE_SELF: return &this->house_scope;
case VSG_SCOPE_PARENT: return &this->town_scope;
default: return ResolverObject::GetScope(scope, relative);
}
}
GrfSpecFeature GetFeature() const override;
uint32_t GetDebugID() const override;
};
/**
* Makes class IDs unique to each GRF file.
* Houses can be assigned class IDs which are only comparable within the GRF

View File

@ -2748,17 +2748,6 @@ static SettingsContainer &GetSettingsTree()
ai->Add(new SettingEntry("difficulty.override_town_settings_in_multiplayer"));
}
SettingsPage *scenario = main->Add(new SettingsPage(STR_CONFIG_SETTING_SCENARIO_EDITOR));
scenario->hide_callback = []() -> bool {
return _game_mode == GM_NORMAL;
};
{
scenario->Add(new SettingEntry("scenario.multiple_buildings"));
scenario->Add(new SettingEntry("scenario.house_ignore_dates"));
scenario->Add(new SettingEntry("scenario.house_ignore_zones"));
scenario->Add(new SettingEntry("scenario.house_ignore_grf"));
}
SettingsPage *network = main->Add(new SettingsPage(STR_CONFIG_SETTING_NETWORK));
{
network->Add(new SettingEntry("network.use_relay_service"));

View File

@ -843,15 +843,6 @@ struct DebugSettings {
uint32_t chicken_bits; ///< chicken bits
uint32_t newgrf_optimiser_flags; ///< NewGRF optimiser flags
};
/** Scenario editor settings. */
struct ScenarioSettings {
bool multiple_buildings; ///< allow manually adding more than one church/stadium
bool house_ignore_dates; ///< allow manually adding houses regardless of date restrictions
uint8_t house_ignore_zones; ///< allow manually adding houses regardless of zone restrictions
bool house_ignore_grf; ///< allow manually adding houses regardless of GRF restrictions
};
/** Settings related to currency/unit systems. */
struct ClientLocaleSettings {
bool sync_locale_network_server; ///< sync locale settings with network server
@ -893,7 +884,6 @@ struct ClientSettings {
SoundSettings sound; ///< sound effect settings
MusicSettings music; ///< settings related to music/sound
NewsSettings news_display; ///< news display settings.
ScenarioSettings scenario; ///< scenario editor settings
};
/** The current settings for this game. */

View File

@ -40,36 +40,3 @@ startup = false
extver = SlXvFeatureTest()
patxname = nullptr
[SDTC_BOOL]
var = scenario.multiple_buildings
flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_PATCH
def = false
str = STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS
strhelp = STR_CONFIG_SETTING_SCENARIO_MULTIPLE_BUILDINGS_HELPTEXT
[SDTC_BOOL]
var = scenario.house_ignore_dates
flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_PATCH
def = false
str = STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_DATES
strhelp = STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_DATES_HELPTEXT
[SDTC_VAR]
var = scenario.house_ignore_zones
type = SLE_UINT8
flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_GUI_DROPDOWN | SF_PATCH
def = 0
min = 0
max = 2
interval = 1
str = STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES
strhelp = STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES_HELPTEXT
strval = STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_ZONES_OFF
[SDTC_BOOL]
var = scenario.house_ignore_grf
flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_PATCH
def = false
str = STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_GRF
strhelp = STR_CONFIG_SETTING_SCENARIO_HOUSE_IGNORE_GRF_HELPTEXT

View File

@ -34,7 +34,6 @@
#include "engine_override.h"
#include "terraform_gui.h"
#include "cheat_func.h"
#include "town_gui.h"
#include "zoom_func.h"
#include "widgets/terraform_widget.h"
@ -545,9 +544,6 @@ static constexpr NWidgetPart _nested_scen_edit_land_gen_widgets[] = {
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_ETT_PLACE_OBJECT), SetMinimalSize(23, 22),
SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT),
NWidget(NWID_SPACER), SetFill(1, 0),
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_HOUSE), SetMinimalSize(23, 22),
SetFill(0, 1), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_PLACE_HOUSE),
NWidget(NWID_SPACER), SetFill(1, 0),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(NWID_SPACER), SetFill(1, 0),
@ -693,10 +689,6 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
ShowBuildObjectPicker();
break;
case WID_ETT_PLACE_HOUSE: // Place house button
ShowBuildHousePicker();
break;
case WID_ETT_INCREASE_SIZE:
case WID_ETT_DECREASE_SIZE: { // Increase/Decrease terraform size
int size = (widget == WID_ETT_INCREASE_SIZE) ? 1 : -1;
@ -843,7 +835,6 @@ static Hotkey terraform_editor_hotkeys[] = {
Hotkey('R', "rocky", WID_ETT_PLACE_ROCKS),
Hotkey('T', "desert", WID_ETT_PLACE_DESERT),
Hotkey('O', "object", WID_ETT_PLACE_OBJECT),
Hotkey('H', "house", WID_ETT_PLACE_HOUSE),
};
HotkeyList ScenarioEditorLandscapeGenerationWindow::hotkeys("terraform_editor", terraform_editor_hotkeys, TerraformToolbarEditorGlobalHotkeys);

View File

@ -283,11 +283,6 @@ static void TownDrawHouseLift(const TileInfo *ti)
AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile));
}
static void DrawHouseLiftInGUI(int x, int y)
{
DrawSprite(SPR_LIFT, PAL_NONE, x - 18, y + 7);
}
typedef void TownDrawTileProc(const TileInfo *ti);
static TownDrawTileProc * const _town_draw_tile_procs[1] = {
TownDrawHouseLift
@ -356,81 +351,6 @@ static void DrawTile_Town(TileInfo *ti, DrawTileProcParams params)
}
}
static void DrawOldHouseTileInGUI(int x, int y, HouseID house_id, bool ground)
{
/* Retrieve pointer to the draw town tile struct */
const DrawBuildingsTileStruct *dcts = &_town_draw_tile_data[house_id << 4 | TOWN_HOUSE_COMPLETED];
if (ground) {
/* Draw the ground sprite */
DrawSprite(dcts->ground.sprite, dcts->ground.pal, x, y);
} else {
/* Add a house on top of the ground? */
if (dcts->building.sprite != 0) {
DrawSprite(dcts->building.sprite, dcts->building.pal, x + dcts->subtile_x, y + dcts->subtile_y);
}
/* Draw the lift */
if (dcts->draw_proc == 1) DrawHouseLiftInGUI(x, y);
}
}
/**
* Draw image of a house. Image will be centered between the \c left and the \c right and verticaly aligned to the \c bottom.
*
* @param house_id house type
* @param left left bound of the drawing area
* @param top top bound of the drawing area
* @param right right bound of the drawing area
* @param bottom bottom bound of the drawing area
*/
void DrawHouseImage(HouseID house_id, int left, int top, int right, int bottom)
{
DrawPixelInfo tmp_dpi;
if (!FillDrawPixelInfo(&tmp_dpi, left, top, right - left + 1, bottom - top + 1)) return;
AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
const HouseSpec *hs = HouseSpec::Get(house_id);
/* sprites are relative to the topmost pixel of the ground tile */
uint x = (right - left + 1) / 2;
uint y = bottom - top + 1 - ScaleSpriteTrad(TILE_PIXELS);
if (hs->building_flags & TILE_SIZE_1x2) x -= ScaleSpriteTrad(TILE_PIXELS / 2);
if (hs->building_flags & TILE_SIZE_2x1) x += ScaleSpriteTrad(TILE_PIXELS / 2);
if (hs->building_flags & BUILDING_HAS_2_TILES) y -= ScaleSpriteTrad(TILE_PIXELS / 2);
if (hs->building_flags & BUILDING_HAS_4_TILES) y -= ScaleSpriteTrad(TILE_PIXELS / 2);
bool new_house = false;
if (house_id >= NEW_HOUSE_OFFSET) {
/* Houses don't necessarily need new graphics. If they don't have a
* spritegroup associated with them, then the sprite for the substitute
* house id is drawn instead. */
if (hs->grf_prop.spritegroup[0] != nullptr) {
new_house = true;
} else {
house_id = hs->grf_prop.subst_id;
}
}
uint num_row = (hs->building_flags & BUILDING_2_TILES_X) ? 2 : 1;
uint num_col = (hs->building_flags & BUILDING_2_TILES_Y) ? 2 : 1;
for (bool ground : { true, false }) {
HouseID hid = house_id;
for (uint row = 0; row < num_row; row++) {
for (uint col = 0; col < num_col; col++) {
Point offset = RemapCoords(row * TILE_SIZE, col * TILE_SIZE, 0); // offset for current tile
offset.x = UnScaleByZoom(offset.x, ZOOM_LVL_GUI);
offset.y = UnScaleByZoom(offset.y, ZOOM_LVL_GUI);
if (new_house) {
DrawNewHouseTileInGUI(x + offset.x, y + offset.y, hid, ground);
} else {
DrawOldHouseTileInGUI(x + offset.x, y + offset.y, hid, ground);
}
hid++;
}
}
}
}
static int GetSlopePixelZ_Town(TileIndex tile, uint x, uint y, bool ground_vehicle)
{
return GetTileMaxPixelZ(tile);
@ -878,7 +798,7 @@ static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags)
return cost;
}
void AddProducedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &produced)
static void AddProducedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &produced)
{
const HouseSpec *hs = HouseSpec::Get(house_id);
@ -920,7 +840,7 @@ static inline void AddAcceptedCargoSetMask(CargoID cargo, uint amount, CargoArra
SetBit(*always_accepted, cargo);
}
void AddAcceptedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &acceptance, CargoTypes *always_accepted)
static void AddAcceptedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &acceptance, CargoTypes *always_accepted)
{
const HouseSpec *hs = HouseSpec::Get(house_id);
Town *t = (tile == INVALID_TILE) ? nullptr : Town::GetByTile(tile);
@ -2885,7 +2805,7 @@ static inline CommandCost CanBuildHouseHere(const TileArea &ta, TownID town, int
* @param zone return error if houses are forbidden in this house zone
* @return success if house is avaliable, error message otherwise
*/
static inline CommandCost IsHouseTypeAllowed(HouseID house, bool above_snowline, HouseZonesBits zone, bool manual)
static inline CommandCost IsHouseTypeAllowed(HouseID house, bool above_snowline, HouseZonesBits zone)
{
const HouseSpec *hs = HouseSpec::Get(house);
/* Disallow disabled and replaced houses. */
@ -2900,8 +2820,6 @@ static inline CommandCost IsHouseTypeAllowed(HouseID house, bool above_snowline,
if (!(hs->building_availability & HZ_SUBARTC_BELOW)) return_cmd_error(STR_ERROR_BUILDING_NOT_ALLOWED_BELOW_SNOW_LINE);
}
if (manual && _settings_client.scenario.house_ignore_zones) return CommandCost();
/* Check if the house zone is allowed for this type of houses. */
if (!HasBit(hs->building_availability & HZ_ZONALL, zone)) {
return_cmd_error(STR_ERROR_BUILDING_NOT_ALLOWED_IN_THIS_TOWN_ZONE);
@ -3016,7 +2934,7 @@ static TileIndex FindPlaceForTownHouseAroundTile(TileIndex tile, Town *t, HouseI
* @param t the town
* @return success if house can be built, error message otherwise
*/
static CommandCost CheckCanBuildHouse(HouseID house, const Town *t, bool manual)
static CommandCost CheckCanBuildHouse(HouseID house, const Town *t)
{
const HouseSpec *hs = HouseSpec::Get(house);
@ -3024,17 +2942,14 @@ static CommandCost CheckCanBuildHouse(HouseID house, const Town *t, bool manual)
return CMD_ERROR;
}
if (!manual || !_settings_client.scenario.house_ignore_dates) {
if (CalTime::CurYear() > hs->max_year) return_cmd_error(STR_ERROR_BUILDING_IS_TOO_OLD);
if (CalTime::CurYear() < hs->min_year) return_cmd_error(STR_ERROR_BUILDING_IS_TOO_MODERN);
}
if (CalTime::CurYear() > hs->max_year) return_cmd_error(STR_ERROR_BUILDING_IS_TOO_OLD);
if (CalTime::CurYear() < hs->min_year) return_cmd_error(STR_ERROR_BUILDING_IS_TOO_MODERN);
/* Special houses that there can be only one of. */
bool multiple_buildings = (manual && _settings_client.scenario.multiple_buildings);
if (hs->building_flags & BUILDING_IS_CHURCH) {
if (t->church_count >= (multiple_buildings ? UINT16_MAX : 1)) return_cmd_error(multiple_buildings ? STR_ERROR_NO_MORE_BUILDINGS_ALLOWED_PER_TOWN : STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN);
if (t->church_count >= 1) return_cmd_error(STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN);
} else if (hs->building_flags & BUILDING_IS_STADIUM) {
if (t->stadium_count >= (multiple_buildings ? UINT16_MAX : 1)) return_cmd_error(multiple_buildings ? STR_ERROR_NO_MORE_BUILDINGS_ALLOWED_PER_TOWN : STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN);
if (t->stadium_count >= 1) return_cmd_error(STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN);
}
return CommandCost();
@ -3081,58 +2996,6 @@ static void BuildTownHouse(Town *t, TileIndex tile, const HouseSpec *hs, HouseID
UpdateTownGrowthRate(t);
}
/**
* Place a custom house
* @param tile tile where the house will be located
* @param flags flags for the command
* @param p1 \n
* bits 0..15 - the HouseID of the house \n
* bits 16..31 - the TownID of the town \n
* @param p2 \n
* bits 0..7 - random bits \n
* @param text unused
* @return the cost of this operation or an error
*/
CommandCost CmdBuildHouse(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint32_t p2, const char *text)
{
if (_game_mode != GM_EDITOR && // in scenario editor anyone can build a house
_current_company != OWNER_TOWN && // towns naturally can build houses
_current_company != OWNER_DEITY) { // GameScript can place a house too
return CMD_ERROR;
}
HouseID house = GB(p1, 0, 16);
Town *t = Town::Get(GB(p1, 16, 16));
if (t == nullptr) return CMD_ERROR;
uint8_t random_bits = GB(p2, 0, 8);
int max_z = GetTileMaxZ(tile);
bool above_snowline = (_settings_game.game_creation.landscape == LT_ARCTIC) && (max_z > HighestSnowLine());
bool manual = (_game_mode == GM_EDITOR);
CommandCost ret = IsHouseTypeAllowed(house, above_snowline, TryGetTownRadiusGroup(t, tile), manual);
if (ret.Succeeded()) ret = IsAnotherHouseTypeAllowedInTown(t, house);
if (ret.Succeeded()) ret = CheckCanBuildHouse(house, t, manual);
if (ret.Succeeded()) {
/* While placing a house manually, try only at exact position and ignore the layout */
const HouseSpec *hs = HouseSpec::Get(house);
uint w = hs->building_flags & BUILDING_2_TILES_X ? 2 : 1;
uint h = hs->building_flags & BUILDING_2_TILES_Y ? 2 : 1;
bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0;
ret = CanBuildHouseHere(TileArea(tile, w, h), t->index, max_z, noslope);
}
if (ret.Failed()) return ret;
if (!manual || !_settings_client.scenario.house_ignore_grf) {
/* Check if GRF allows this house */
if (!HouseAllowsConstruction(house, tile, t, random_bits)) return_cmd_error(STR_ERROR_BUILDING_NOT_ALLOWED);
}
if (flags & DC_EXEC) BuildTownHouse(t, tile, HouseSpec::Get(house), house, random_bits);
return CommandCost();
}
/**
* Tries to build a house at this tile.
* @param t The town the house will belong to.
@ -3160,7 +3023,7 @@ static bool TryBuildTownHouse(Town *t, TileIndex tile)
/* Generate a list of all possible houses that can be built. */
for (const auto &hs : HouseSpec::Specs()) {
if (IsHouseTypeAllowed(hs.Index(), above_snowline, zone, false).Failed()) continue;
if (IsHouseTypeAllowed(hs.Index(), above_snowline, zone).Failed()) continue;
if (IsAnotherHouseTypeAllowedInTown(t, hs.Index()).Failed()) continue;
uint cur_prob = hs.probability;
@ -3192,7 +3055,7 @@ static bool TryBuildTownHouse(Town *t, TileIndex tile)
probs[i] = probs.back();
probs.pop_back();
CommandCost ret = CheckCanBuildHouse(house, t, false);
CommandCost ret = CheckCanBuildHouse(house, t);
if (ret.Failed()) continue;
tile = FindPlaceForTownHouseAroundTile(tile, t, house);
@ -3229,7 +3092,10 @@ CommandCost CmdPlaceHouse(DoCommandFlag flags, TileIndex tile, HouseID house)
uint w = (hs->building_flags & BUILDING_2_TILES_X) ? 2 : 1;
uint h = (hs->building_flags & BUILDING_2_TILES_Y) ? 2 : 1;
CommandCost cost = CanBuildHouseHere(TileArea(tile, w, h), t->index, max_z, noslope);
CommandCost cost = IsAnotherHouseTypeAllowedInTown(t, house);
if (!cost.Succeeded()) return cost;
cost = CanBuildHouseHere(TileArea(tile, w, h), t->index, max_z, noslope);
if (!cost.Succeeded()) return cost;
if (flags & DC_EXEC) {

View File

@ -54,8 +54,6 @@ TownKdtree _town_local_authority_kdtree(&Kdtree_TownXYFunc);
typedef GUIList<const Town*, const bool &> GUITownList;
static void PlaceProc_House(TileIndex tile);
static constexpr NWidgetPart _nested_town_authority_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
@ -1514,738 +1512,6 @@ void ShowFoundTownWindow()
AllocateWindowDescFront<FoundTownWindow>(&_found_town_desc, 0);
}
class GUIHouseList : public std::vector<HouseID> {
protected:
std::vector<uint16_t> house_sets; ///< list of house sets, each item points the first house of the set in the houses array
static bool HouseSorter(const HouseID &a, const HouseID &b)
{
const HouseSpec *a_hs = HouseSpec::Get(a);
const GRFFile *a_set = a_hs->grf_prop.grffile;
const HouseSpec *b_hs = HouseSpec::Get(b);
const GRFFile *b_set = b_hs->grf_prop.grffile;
int ret = (a_set != nullptr) - (b_set != nullptr);
if (ret == 0) {
if (a_set != nullptr) {
static_assert(sizeof(a_set->grfid) <= sizeof(int));
ret = a_set->grfid - b_set->grfid;
if (ret == 0) ret = a_hs->grf_prop.local_id - b_hs->grf_prop.local_id;
} else {
ret = a - b;
}
}
return ret < 0;
}
public:
GUIHouseList()
{
this->house_sets.push_back(0); // terminator
}
inline HouseID GetHouseAtOffset(uint house_set, uint house_offset) const
{
return (*this)[this->house_sets[house_set] + house_offset];
}
uint NumHouseSets() const
{
return (uint)this->house_sets.size() - 1; // last item is a terminator
}
uint NumHousesInHouseSet(uint house_set) const
{
assert(house_set < this->NumHouseSets());
/* There is a terminator on the list of house sets. It's equal to the number
* of all houses. We can safely use "house_set + 1" even for the last
* house set. */
return this->house_sets[house_set + 1] - this->house_sets[house_set];
}
int FindHouseSet(HouseID house) const
{
const GRFFile *house_set = HouseSpec::Get(house)->grf_prop.grffile;
for (uint i = 0; i < this->NumHouseSets(); i++) {
if (HouseSpec::Get(this->GetHouseAtOffset(i, 0))->grf_prop.grffile == house_set) return i;
}
return -1;
}
int FindHouseOffset(uint house_set, HouseID house) const
{
assert(house_set < this->NumHouseSets());
uint count = this->NumHousesInHouseSet(house_set);
for (uint i = 0; i < count; i++) {
if (this->GetHouseAtOffset(house_set, i) == house) return i;
}
return -1;
}
const char *GetNameOfHouseSet(uint house_set) const
{
assert(house_set < this->NumHouseSets());
const GRFFile *gf = HouseSpec::Get(this->GetHouseAtOffset(house_set, 0))->grf_prop.grffile;
if (gf != nullptr) return GetGRFConfig(gf->grfid)->GetName();
return GetStringPtr(STR_BASIC_HOUSE_SET_NAME);
}
/**
* Notify the sortlist that the rebuild is done
*
* @note This forces a resort
*/
void Build()
{
/* collect items */
this->clear();
for (HouseID house = 0; house < NUM_HOUSES; house++) {
const HouseSpec *hs = HouseSpec::Get(house);
/* is the house enabled? */
if (!hs->enabled) continue;
/* is the house overriden? */
if (hs->grf_prop.override != INVALID_HOUSE_ID) continue;
/* is the house allownd in current landscape? */
HouseZones landscapes = (HouseZones)(HZ_TEMP << _settings_game.game_creation.landscape);
if (_settings_game.game_creation.landscape == LT_ARCTIC) landscapes |= HZ_SUBARTC_ABOVE;
if (!(hs->building_availability & landscapes)) continue;
/* is the house allowed at any of house zones at all? */
if (!(hs->building_availability & HZ_ZONALL)) continue;
/* is there any year in which the house is allowed? */
if (hs->min_year > hs->max_year) continue;
/* add the house */
this->push_back(house);
}
/* arrange items */
std::sort(this->begin(), this->end(), HouseSorter);
/* list house sets */
this->house_sets.clear();
const GRFFile *last_set = nullptr;
for (uint i = 0; i < this->size(); i++) {
const HouseSpec *hs = HouseSpec::Get((*this)[i]);
/* add house set */
if (this->house_sets.size() == 0 || last_set != hs->grf_prop.grffile) {
last_set = hs->grf_prop.grffile;
this->house_sets.push_back(i);
}
}
/* put a terminator on the list to make counting easier */
this->house_sets.push_back((uint16_t)this->size());
}
};
static HouseID _cur_house = INVALID_HOUSE_ID; ///< house selected in the house picker window
/** The window used for building houses. */
class HousePickerWindow : public Window {
protected:
GUIHouseList house_list; ///< list of houses and house sets
int house_offset; ///< index of selected house
uint house_set; ///< index of selected house set
uint line_height; ///< height of a single line in the list of house sets
HouseID display_house; ///< house ID of currently displayed house
void RestoreSelectedHouseIndex()
{
this->house_set = 0;
this->house_offset = 0;
if (this->house_list.size() == 0) { // no houses at all?
_cur_house = INVALID_HOUSE_ID;
this->display_house = _cur_house;
return;
}
if (_cur_house != INVALID_HOUSE_ID) {
int house_set = this->house_list.FindHouseSet(_cur_house);
if (house_set >= 0) {
this->house_set = house_set;
int house_offset = this->house_list.FindHouseOffset(house_set, _cur_house);
if (house_offset >= 0) {
this->house_offset = house_offset;
return;
}
}
}
_cur_house = this->house_list.GetHouseAtOffset(this->house_set, this->house_offset);
this->display_house = _cur_house;
}
void SelectHouseIntl(uint new_house_set, int new_house_offset)
{
SetObjectToPlaceWnd(SPR_CURSOR_TOWN, PAL_NONE, HT_RECT, this);
this->house_set = new_house_set;
this->house_offset = new_house_offset;
_cur_house = this->house_list.GetHouseAtOffset(new_house_set, new_house_offset);
this->display_house = _cur_house;
}
/**
* Select another house.
* @param new_house_set index of the house set
* @param new_house_offset offset of the house
*/
void SelectOtherHouse(uint new_house_set, int new_house_offset)
{
assert(new_house_set < this->house_list.NumHouseSets());
assert(new_house_offset < (int) this->house_list.NumHousesInHouseSet(new_house_set));
assert(new_house_offset >= 0);
SelectHouseIntl(new_house_set, new_house_offset);
NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_HP_HOUSE_SELECT_MATRIX);
matrix->SetCount(this->house_list.NumHousesInHouseSet(this->house_set));
matrix->SetClicked(this->house_offset);
this->UpdateSelectSize();
this->SetDirty();
}
void UpdateSelectSize()
{
uint w = 1, h = 1;
if (_cur_house != INVALID_HOUSE_ID) {
const HouseSpec *hs = HouseSpec::Get(_cur_house);
if (hs->building_flags & BUILDING_2_TILES_X) w++;
if (hs->building_flags & BUILDING_2_TILES_Y) h++;
}
SetTileSelectSize(w, h);
}
public:
HousePickerWindow(WindowDesc *desc, WindowNumber number) : Window(desc)
{
this->CreateNestedTree();
/* there is no shade box but we will shade the window if there is no house to show */
this->shade_select = this->GetWidget<NWidgetStacked>(WID_HP_MAIN_PANEL_SEL);
NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_HP_HOUSE_SELECT_MATRIX);
matrix->SetScrollbar(this->GetScrollbar(WID_HP_HOUSE_SELECT_SCROLL));
this->FinishInitNested(number);
if (_cur_house != INVALID_HOUSE_ID) matrix->SetClicked(this->house_offset); // set clicked item again to make it visible
}
virtual void OnInit() override
{
this->house_list.Build();
this->RestoreSelectedHouseIndex();
this->UpdateSelectSize();
/* if we have exactly one set of houses and it's not the default one then display it's name in the title bar */
this->GetWidget<NWidgetCore>(WID_HP_CAPTION)->widget_data =
(this->house_list.NumHouseSets() == 1 && HouseSpec::Get(this->house_list[0])->grf_prop.grffile != nullptr) ?
STR_HOUSE_BUILD_CUSTOM_CAPTION : STR_HOUSE_BUILD_CAPTION;
/* hide widgets if we have no houses to show */
this->SetShaded(this->house_list.size() == 0);
if (this->house_list.size() != 0) {
/* show the list of house sets if we have at least 2 items to show */
this->GetWidget<NWidgetStacked>(WID_HP_HOUSE_SETS_SEL)->SetDisplayedPlane(this->house_list.NumHouseSets() > 1 ? 0 : SZSP_NONE);
/* set number of items in the list of house sets */
this->GetWidget<NWidgetCore>(WID_HP_HOUSE_SETS)->widget_data = (this->house_list.NumHouseSets() << MAT_ROW_START) | (1 << MAT_COL_START);
/* show the landscape info only in arctic climate (above/below snowline) */
this->GetWidget<NWidgetStacked>(WID_HP_HOUSE_LANDSCAPE_SEL)->SetDisplayedPlane(_settings_game.game_creation.landscape == LT_ARCTIC ? 0 : SZSP_NONE);
/* update the matrix of houses */
NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_HP_HOUSE_SELECT_MATRIX);
matrix->SetCount(this->house_list.NumHousesInHouseSet(this->house_set));
matrix->SetClicked(this->house_offset);
SelectHouseIntl(this->house_set, this->house_offset);
} else {
ResetObjectToPlace();
}
}
virtual void SetStringParameters(WidgetID widget) const override
{
if (widget == WID_HP_CAPTION) {
if (this->house_list.NumHouseSets() == 1) SetDParamStr(0, this->house_list.GetNameOfHouseSet(0));
} else if (this->display_house == INVALID_HOUSE_ID) {
switch (widget) {
case WID_HP_CAPTION:
break;
case WID_HP_HOUSE_ZONES:
for (int i = 0; i < HZB_END; i++) {
SetDParam(2 * i, STR_HOUSE_BUILD_HOUSE_ZONE_DISABLED);
SetDParam(2 * i + 1, 4 - i);
}
break;
case WID_HP_HOUSE_YEARS:
SetDParam(0, STR_HOUSE_BUILD_YEARS_BAD_YEAR);
SetDParam(1, 0);
SetDParam(2, STR_HOUSE_BUILD_YEARS_BAD_YEAR);
SetDParam(3, 0);
break;
case WID_HP_HOUSE_ACCEPTANCE:
SetDParamStr(0, "");
break;
case WID_HP_HOUSE_SUPPLY:
SetDParam(0, 0);
break;
default:
SetDParam(0, STR_EMPTY);
break;
}
} else {
switch (widget) {
case WID_HP_HOUSE_NAME:
SetDParam(0, GetHouseName(this->display_house));
break;
case WID_HP_HISTORICAL_BUILDING:
SetDParam(0, HouseSpec::Get(this->display_house)->extra_flags & BUILDING_IS_HISTORICAL ? STR_HOUSE_BUILD_HISTORICAL_BUILDING : STR_EMPTY);
break;
case WID_HP_HOUSE_POPULATION:
SetDParam(0, HouseSpec::Get(this->display_house)->population);
break;
case WID_HP_HOUSE_ZONES: {
HouseZones zones = (HouseZones)(HouseSpec::Get(this->display_house)->building_availability & HZ_ZONALL);
for (int i = 0; i < HZB_END; i++) {
/* colour: gold(enabled)/grey(disabled) */
SetDParam(2 * i, HasBit(zones, HZB_END - i - 1) ? STR_HOUSE_BUILD_HOUSE_ZONE_ENABLED : STR_HOUSE_BUILD_HOUSE_ZONE_DISABLED);
/* digit: 4(center)/3/1/1/0(edge) */
SetDParam(2 * i + 1, 4 - i);
}
break;
}
case WID_HP_HOUSE_LANDSCAPE: {
StringID info = STR_HOUSE_BUILD_LANDSCAPE_ABOVE_OR_BELOW_SNOWLINE;
switch (HouseSpec::Get(this->display_house)->building_availability & (HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW)) {
case HZ_SUBARTC_ABOVE: info = STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE; break;
case HZ_SUBARTC_BELOW: info = STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE; break;
default: break;
}
SetDParam(0, info);
break;
}
case WID_HP_HOUSE_YEARS: {
const HouseSpec *hs = HouseSpec::Get(this->display_house);
SetDParam(0, hs->min_year <= CalTime::CurYear() ? STR_HOUSE_BUILD_YEARS_GOOD_YEAR : STR_HOUSE_BUILD_YEARS_BAD_YEAR);
SetDParam(1, hs->min_year);
SetDParam(2, hs->max_year >= CalTime::CurYear() ? STR_HOUSE_BUILD_YEARS_GOOD_YEAR : STR_HOUSE_BUILD_YEARS_BAD_YEAR);
SetDParam(3, hs->max_year);
break;
}
case WID_HP_HOUSE_ACCEPTANCE: {
std::string buff;
CargoArray cargo{};
CargoTypes dummy = 0;
AddAcceptedHouseCargo(this->display_house, INVALID_TILE, cargo, &dummy);
for (uint i = 0; i < NUM_CARGO; i++) {
if (cargo[i] == 0) continue;
/* If the accepted value is less than 8, show it in 1/8:ths */
SetDParam(0, cargo[i] < 8 ? STR_HOUSE_BUILD_CARGO_VALUE_EIGHTS : STR_HOUSE_BUILD_CARGO_VALUE_JUST_NAME);
SetDParam(1, cargo[i]);
SetDParam(2, CargoSpec::Get(i)->name);
GetString(StringBuilder(buff), buff.empty() ? STR_HOUSE_BUILD_CARGO_FIRST : STR_HOUSE_BUILD_CARGO_SEPARATED);
}
if (buff.empty()) GetString(StringBuilder(buff), STR_JUST_NOTHING);
SetDParamStr(0, std::move(buff));
break;
}
case WID_HP_HOUSE_SUPPLY: {
CargoArray cargo{};
AddProducedHouseCargo(this->display_house, INVALID_TILE, cargo);
uint32_t cargo_mask = 0;
for (uint i = 0; i < NUM_CARGO; i++) if (cargo[i] != 0) SetBit(cargo_mask, i);
SetDParam(0, cargo_mask);
break;
}
default: break;
}
}
}
virtual void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
{
switch (widget) {
case WID_HP_HOUSE_SETS: {
uint max_w = 0;
for (uint i = 0; i < this->house_list.NumHouseSets(); i++) {
max_w = std::max(max_w, GetStringBoundingBox(this->house_list.GetNameOfHouseSet(i)).width);
}
size.width = std::max(size.width, max_w + padding.width);
this->line_height = GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.matrix.Vertical();
size.height = this->house_list.NumHouseSets() * this->line_height;
break;
}
case WID_HP_HOUSE_NAME:
size.width = 120; // we do not want this window to get too wide, better clip
break;
case WID_HP_HISTORICAL_BUILDING:
size.width = std::max(size.width, GetStringBoundingBox(STR_HOUSE_BUILD_HISTORICAL_BUILDING).width + padding.width);
break;
case WID_HP_HOUSE_POPULATION:
SetDParam(0, 0);
/* max popultion is 255 - 3 digits */
size.width = std::max(size.width, GetStringBoundingBox(STR_HOUSE_BUILD_HOUSE_POPULATION).width + 3 * GetDigitWidth() + padding.width);
break;
case WID_HP_HOUSE_ZONES: {
for (int i = 0; i < HZB_END; i++) {
SetDParam(2 * i, STR_HOUSE_BUILD_HOUSE_ZONE_ENABLED); // colour
SetDParam(2 * i + 1, i + 1); // digit: 1(center)/2/3/4/5(edge)
}
size.width = std::max(size.width, GetStringBoundingBox(STR_HOUSE_BUILD_HOUSE_ZONES).width + padding.width);
break;
}
case WID_HP_HOUSE_LANDSCAPE: {
SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ABOVE_OR_BELOW_SNOWLINE);
Dimension dim = GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE);
SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE);
dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE));
SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE);
dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE));
dim.width += padding.width;
dim.height += padding.height;
size = maxdim(size, dim);
break;
}
case WID_HP_HOUSE_YEARS: {
SetDParam(0, STR_HOUSE_BUILD_YEARS_GOOD_YEAR);
SetDParam(1, 0);
SetDParam(2, STR_HOUSE_BUILD_YEARS_GOOD_YEAR);
SetDParam(3, 0);
Dimension dim = GetStringBoundingBox(STR_HOUSE_BUILD_YEARS);
dim.width += 14 * GetDigitWidth() + padding.width; // space for about 16 digits (14 + two zeros) should be enough, don't make the window too wide
dim.height += padding.height;
size = maxdim(size, dim);
break;
}
case WID_HP_HOUSE_SELECT_MATRIX:
resize.height = 1; // don't snap to rows of this matrix
break;
/* these texts can be long, better clip */
case WID_HP_HOUSE_ACCEPTANCE:
case WID_HP_HOUSE_SUPPLY:
size.width = 0;
break;
default: break;
}
}
virtual void DrawWidget(const Rect &r, WidgetID widget) const override
{
switch (widget) {
case WID_HP_HOUSE_SETS: {
int y = r.top + WidgetDimensions::scaled.matrix.top;
for (uint i = 0; i < this->house_list.NumHouseSets(); i++) {
SetDParamStr(0, this->house_list.GetNameOfHouseSet(i));
DrawString(r.left + WidgetDimensions::scaled.matrix.left, r.right - WidgetDimensions::scaled.matrix.right, y, STR_JUST_RAW_STRING, i == this->house_set ? TC_WHITE : TC_BLACK);
y += this->line_height;
}
break;
}
case WID_HP_HOUSE_PREVIEW:
if (this->display_house != INVALID_HOUSE_ID) {
DrawHouseImage(this->display_house, r.left, r.top, r.right, r.bottom);
}
break;
case WID_HP_HOUSE_SELECT: {
HouseID house = this->house_list.GetHouseAtOffset(this->house_set, this->GetWidget<NWidgetBase>(widget)->GetParentWidget<NWidgetMatrix>()->GetCurrentElement());
int lowered = (house == _cur_house) ? 1 : 0;
DrawHouseImage(house,
r.left + WidgetDimensions::scaled.matrix.left + lowered, r.top + WidgetDimensions::scaled.matrix.top + lowered,
r.right - WidgetDimensions::scaled.matrix.right + lowered, r.bottom - WidgetDimensions::scaled.matrix.bottom + lowered);
const HouseSpec *hs = HouseSpec::Get(house);
/* disabled? */
if (CalTime::CurYear() < hs->min_year || CalTime::CurYear() > hs->max_year) {
GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER);
}
break;
}
}
}
virtual void OnClick(Point pt, WidgetID widget, int click_count) override
{
switch (widget) {
case WID_HP_HOUSE_SETS: {
uint index = (uint)(pt.y - this->GetWidget<NWidgetBase>(widget)->pos_y) / this->line_height;
if (index < this->house_list.NumHouseSets() && index != this->house_set) this->SelectOtherHouse(index, 0);
break;
}
case WID_HP_HOUSE_SELECT:
this->SelectOtherHouse(this->house_set, this->GetWidget<NWidgetBase>(widget)->GetParentWidget<NWidgetMatrix>()->GetCurrentElement());
break;
}
}
virtual void OnPlaceObject(Point pt, TileIndex tile) override
{
PlaceProc_House(tile);
}
virtual void OnPlaceObjectAbort() override
{
this->house_offset = -1;
_cur_house = INVALID_HOUSE_ID;
NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_HP_HOUSE_SELECT_MATRIX);
matrix->SetClicked(-1);
this->UpdateSelectSize();
this->SetDirty();
}
};
static const NWidgetPart _nested_house_picker_widgets[] = {
/* TOP */
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_HP_CAPTION), SetDataTip(STR_HOUSE_BUILD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
EndContainer(),
NWidget(NWID_SELECTION, COLOUR_DARK_GREEN, WID_HP_MAIN_PANEL_SEL),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_HP_HOUSE_SELECT_SCROLL),
/* MIDDLE */
NWidget(NWID_HORIZONTAL), SetPIP(5, 0, 0),
/* LEFT */
NWidget(NWID_VERTICAL), SetPIP(5, 2, 2),
/* LIST OF HOUSE SETS */
NWidget(NWID_SELECTION, COLOUR_DARK_GREEN, WID_HP_HOUSE_SETS_SEL),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_MATRIX, COLOUR_GREY, WID_HP_HOUSE_SETS), SetMinimalSize(0, 60), SetFill(1, 0), SetResize(0, 0),
SetMatrixDataTip(1, 1, STR_HOUSE_BUILD_HOUSESET_LIST_TOOLTIP),
EndContainer(),
EndContainer(),
/* HOUSE PICTURE AND LABEL */
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_PREVIEW), SetFill(1, 1), SetResize(0, 1), SetMinimalSize(2 * TILE_PIXELS, 142),
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_HP_HOUSE_NAME), SetDataTip(STR_HOUSE_BUILD_HOUSE_NAME, STR_NULL), SetMinimalSize(120, 0),
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_HP_HISTORICAL_BUILDING), SetDataTip(STR_JUST_STRING, STR_NULL),
/* HOUSE INFOS (SHORT TEXTS) */
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_POPULATION), SetDataTip(STR_HOUSE_BUILD_HOUSE_POPULATION, STR_NULL), SetPadding(5, 0, 0, 0),
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_ZONES), SetDataTip(STR_HOUSE_BUILD_HOUSE_ZONES, STR_NULL),
NWidget(NWID_SELECTION, COLOUR_DARK_GREEN, WID_HP_HOUSE_LANDSCAPE_SEL),
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_LANDSCAPE), SetDataTip(STR_HOUSE_BUILD_LANDSCAPE, STR_NULL),
EndContainer(),
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_YEARS), SetDataTip(STR_HOUSE_BUILD_YEARS, STR_NULL),
EndContainer(),
/* RIGHT: MATRIX OF HOUSES */
NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_HP_HOUSE_SELECT_MATRIX), SetPIP(0, 2, 0), SetPadding(2, 2, 2, 2), SetScrollbar(WID_HP_HOUSE_SELECT_SCROLL),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_HP_HOUSE_SELECT), SetMinimalSize(64, 64), SetFill(0, 0), SetResize(0, 0),
SetDataTip(0x0, STR_HOUSE_BUILD_SELECT_HOUSE_TOOLTIP), SetScrollbar(WID_HP_HOUSE_SELECT_SCROLL),
EndContainer(),
EndContainer(),
NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_HP_HOUSE_SELECT_SCROLL),
EndContainer(),
/* BOTTOM */
NWidget(NWID_HORIZONTAL), SetPIP(5, 2, 0),
/* HOUSE INFOS (LONG TEXTS) */
NWidget(NWID_VERTICAL), SetPIP(0, 2, 5),
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_ACCEPTANCE), SetDataTip(STR_HOUSE_BUILD_ACCEPTED_CARGO, STR_NULL), SetFill(1, 0), SetResize(1, 0),
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_SUPPLY), SetDataTip(STR_HOUSE_BUILD_SUPPLIED_CARGO, STR_NULL), SetFill(1, 0), SetResize(1, 0),
EndContainer(),
/* RESIZE BOX */
NWidget(NWID_VERTICAL),
NWidget(NWID_SPACER), SetFill(0, 1),
NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
EndContainer(),
EndContainer(),
EndContainer(),
EndContainer(),
};
static WindowDesc _house_picker_desc(__FILE__, __LINE__,
WDP_AUTO, "build_house", 0, 0,
WC_BUILD_HOUSE, WC_BUILD_TOOLBAR,
WDF_CONSTRUCTION,
std::begin(_nested_house_picker_widgets), std::end(_nested_house_picker_widgets)
);
/**
* Show our house picker.
* @param parent The toolbar window we're associated with.
*/
void ShowBuildHousePicker()
{
AllocateWindowDescFront<HousePickerWindow>(&_house_picker_desc, 0);
}
/**
* Window for selecting towns to build a house in.
*/
struct SelectTownWindow : Window {
TownList towns; ///< list of towns
CommandContainer cmd; ///< command to build the house (CMD_BUILD_HOUSE)
Scrollbar *vscroll; ///< scrollbar for the town list
SelectTownWindow(WindowDesc *desc, TownList towns, const CommandContainer &cmd) : Window(desc), towns(std::move(towns)), cmd(cmd)
{
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_ST_SCROLLBAR);
this->vscroll->SetCount((uint)this->towns.size());
this->FinishInitNested();
}
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
{
if (widget != WID_ST_PANEL) return;
/* Determine the widest string */
Dimension d = { 0, 0 };
for (uint i = 0; i < this->towns.size(); i++) {
SetDParam(0, this->towns[i]);
d = maxdim(d, GetStringBoundingBox(STR_SELECT_TOWN_LIST_ITEM));
}
resize.height = d.height;
d.height *= 5;
d.width += WidgetDimensions::scaled.framerect.Horizontal();
d.height += WidgetDimensions::scaled.framerect.Vertical();
size = d;
}
void DrawWidget(const Rect &r, WidgetID widget) const override
{
if (widget != WID_ST_PANEL) return;
Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
uint y = ir.top;
uint end = std::min<uint>(this->vscroll->GetCount(), this->vscroll->GetPosition() + this->vscroll->GetCapacity());
for (uint i = this->vscroll->GetPosition(); i < end; i++) {
SetDParam(0, this->towns[i]);
DrawString(ir.left, ir.right, y, STR_SELECT_TOWN_LIST_ITEM);
y += this->resize.step_height;
}
}
void OnClick(Point pt, WidgetID widget, int click_count) override
{
if (widget != WID_ST_PANEL) return;
uint pos = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ST_PANEL, WidgetDimensions::scaled.framerect.top);
if (pos >= this->towns.size()) return;
/* Place a house */
SB(this->cmd.p1, 16, 16, this->towns[pos]);
DoCommandP(&this->cmd);
/* Close the window */
this->Close();
}
void OnResize() override
{
this->vscroll->SetCapacityFromWidget(this, WID_ST_PANEL, WidgetDimensions::scaled.framerect.Vertical());
}
};
static const NWidgetPart _nested_select_town_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ST_CAPTION), SetDataTip(STR_SELECT_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_ST_PANEL), SetResize(1, 0), SetScrollbar(WID_ST_SCROLLBAR), EndContainer(),
NWidget(NWID_VERTICAL),
NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_ST_SCROLLBAR),
NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
EndContainer(),
EndContainer(),
};
static WindowDesc _select_town_desc(__FILE__, __LINE__,
WDP_AUTO, "select_town", 100, 0,
WC_SELECT_TOWN, WC_NONE,
WDF_CONSTRUCTION,
std::begin(_nested_select_town_widgets), std::end(_nested_select_town_widgets)
);
static void ShowSelectTownWindow(TownList towns, const CommandContainer &cmd)
{
CloseWindowByClass(WC_SELECT_TOWN);
new SelectTownWindow(&_select_town_desc, std::move(towns), cmd);
}
static void PlaceProc_House(TileIndex tile)
{
if (_town_pool.items == 0) {
ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HOUSE_HERE, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO);
return;
}
CloseWindowById(WC_SELECT_TOWN, 0);
if (_cur_house == INVALID_HOUSE_ID) return;
/* build a list of towns to join to */
TownList towns;
HouseZones house_zones = HouseSpec::Get(_cur_house)->building_availability & HZ_ZONALL;
uint best_dist = UINT_MAX;
int best_zone = (int)HZB_BEGIN - 1;
for (const Town *t : Town::Iterate()) {
HouseZonesBits town_zone = TryGetTownRadiusGroup(t, tile);
if (HasBit(house_zones, town_zone) || (_settings_client.scenario.house_ignore_zones == 1 && town_zone != HZB_END) || _settings_client.scenario.house_ignore_zones == 2) {
/* If CTRL is NOT pressed keep only single town on the list, the best one.
* Otherwise add all towns to the list so they can be shown to the player. */
if (!_ctrl_pressed) {
if ((int)town_zone < best_zone) continue;
uint dist = DistanceSquare(tile, t->xy);
if (dist >= best_dist) continue;
best_dist = dist;
if (town_zone != HZB_END) best_zone = town_zone;
towns.clear();
}
towns.push_back(t->index);
}
}
if (towns.size() == 0) {
ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HOUSE_HERE, STR_ERROR_BUILDING_NOT_ALLOWED_IN_THIS_TOWN_ZONE, WL_INFO);
return;
}
if (towns.size() > 16 && _settings_client.scenario.house_ignore_zones == 2) {
std::sort(towns.begin(), towns.end(), [&](const TownID a, const TownID b) {
return DistanceSquare(tile, Town::Get(a)->xy) < DistanceSquare(tile, Town::Get(b)->xy);
});
towns.resize(16);
}
CommandContainer cmd = NewCommandContainerBasic(
tile,
_cur_house, // p1 - house type and town index (town not yet set)
InteractiveRandom(), // p2 - random bits for the house
CMD_BUILD_HOUSE | CMD_MSG(STR_ERROR_CAN_T_BUILD_HOUSE_HERE),
CcPlaySound_CONSTRUCTION_RAIL
);
if (!_ctrl_pressed) {
SB(cmd.p1, 16, 16, towns[0]); // set the town, it's alone on the list
DoCommandP(&cmd);
} else {
if (!_settings_client.gui.persistent_buildingtools) CloseWindowById(WC_BUILD_HOUSE, 0);
ShowSelectTownWindow(std::move(towns), cmd);
}
}
void InitializeTownGui()
{
_town_local_authority_kdtree.Clear();

View File

@ -1,15 +0,0 @@
/*
* This file is part of OpenTTD.
* 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.
* 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.
* 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/>.
*/
/** @file town_gui.h Types and functions related to the town GUI. */
#ifndef TOWN_GUI_H
#define TOWN_GUI_H
void ShowBuildHousePicker();
#endif /* TOWN_GUI_H */

View File

@ -41,7 +41,6 @@ enum EditorTerraformToolbarWidgets : WidgetID {
WID_ETT_PLACE_ROCKS, ///< Place rocks button.
WID_ETT_PLACE_DESERT, ///< Place desert button (in tropical climate).
WID_ETT_PLACE_OBJECT, ///< Place transmitter button.
WID_ETT_PLACE_HOUSE, ///< Place house button.
WID_ETT_BUTTONS_END, ///< End of pushable buttons.
WID_ETT_INCREASE_SIZE = WID_ETT_BUTTONS_END, ///< Upwards arrow button to increase terraforming size.
WID_ETT_DECREASE_SIZE, ///< Downwards arrow button to decrease terraforming size.

View File

@ -66,32 +66,4 @@ enum TownFoundingWidgets : WidgetID {
WID_TF_LAYOUT_RANDOM, ///< Selection for a randomly chosen town layout.
};
/** Widgets of the #HousePickerWindow class. */
enum HousePickerWidgets : WidgetID {
WID_HP_CAPTION,
WID_HP_MAIN_PANEL_SEL, ///< Selection widget to show/hide the main panel.
WID_HP_HOUSE_SETS_SEL, ///< Selection widget to show/hide the list of house sets.
WID_HP_HOUSE_SETS, ///< List of available house sets.
WID_HP_HOUSE_SELECT_MATRIX, ///< Matrix with houses to select.
WID_HP_HOUSE_SELECT_SCROLL, ///< Scrollbar associated with the house matrix.
WID_HP_HOUSE_SELECT, ///< Panels with house images in the house matrix.
WID_HP_HOUSE_PREVIEW, ///< House preview panel.
WID_HP_HOUSE_NAME, ///< House name display.
WID_HP_HISTORICAL_BUILDING, ///< "Historical building" label.
WID_HP_HOUSE_POPULATION, ///< House population display.
WID_HP_HOUSE_ZONES, ///< House zones display.
WID_HP_HOUSE_LANDSCAPE, ///< Information about house availability against the landscape.
WID_HP_HOUSE_LANDSCAPE_SEL, ///< Selection widget to show/hide the landscape info.
WID_HP_HOUSE_YEARS, ///< Years display.
WID_HP_HOUSE_ACCEPTANCE, ///< Cargo accepted.
WID_HP_HOUSE_SUPPLY, ///< Cargo supplied.
};
/** Widgets of the #SelectTownWindow class. */
enum SelectTownWidgets : WidgetID {
WID_ST_CAPTION, ///< Caption of the window.
WID_ST_PANEL, ///< Main panel.
WID_ST_SCROLLBAR, ///< Scrollbar of the panel.
};
#endif /* WIDGETS_TOWN_WIDGET_H */