mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-09 19:10:38 +00:00
Feature: Allow manually placing town buildings in scenario editor.
House picker is accessed from the Landscaping toolbar as there is no town toolbar. Once placed these houses behave like any other and can be removed by players and towns. Uses the unified picker system, so also supports used/saved favourites. As town building don't have class labels, town zones are use to imitate them.
This commit is contained in:
parent
874cfe000b
commit
ed67aedabf
@ -136,4 +136,6 @@ inline HouseID GetTranslatedHouseID(HouseID hid)
|
||||
return hs->grf_prop.override == INVALID_HOUSE_ID ? hid : hs->grf_prop.override;
|
||||
}
|
||||
|
||||
void ShowBuildHousePicker(struct Window *);
|
||||
|
||||
#endif /* HOUSE_H */
|
||||
|
@ -437,6 +437,9 @@ STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Abandon scenari
|
||||
STR_SCENEDIT_FILE_MENU_SEPARATOR :
|
||||
STR_SCENEDIT_FILE_MENU_QUIT :Exit
|
||||
|
||||
STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generate towns
|
||||
STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Place houses
|
||||
|
||||
# Settings menu
|
||||
###length 16
|
||||
STR_SETTINGS_MENU_GAME_OPTIONS :Game options
|
||||
@ -2814,6 +2817,16 @@ STR_PICKER_ROADSTOP_TRUCK_CLASS_TOOLTIP :Select a lorry
|
||||
STR_PICKER_ROADSTOP_TRUCK_TYPE_TOOLTIP :Select a lorry station type to build. Ctrl+Click to add or remove in saved items
|
||||
STR_PICKER_OBJECT_CLASS_TOOLTIP :Select an object class to display
|
||||
STR_PICKER_OBJECT_TYPE_TOOLTIP :Select an object type to build. Ctrl+Click to add or remove in saved items. Ctrl+Click+Drag to select the area diagonally. Also press Shift to show cost estimate only
|
||||
STR_PICKER_HOUSE_CLASS_TOOLTIP :Select a town zone to display
|
||||
STR_PICKER_HOUSE_TYPE_TOOLTIP :Select a house type to build. Ctrl+Click to add or remove in saved items
|
||||
|
||||
STR_HOUSE_PICKER_CAPTION :House Selection
|
||||
|
||||
STR_HOUSE_PICKER_CLASS_ZONE1 :Edge
|
||||
STR_HOUSE_PICKER_CLASS_ZONE2 :Outskirts
|
||||
STR_HOUSE_PICKER_CLASS_ZONE3 :Outer Suburbs
|
||||
STR_HOUSE_PICKER_CLASS_ZONE4 :Inner Suburbs
|
||||
STR_HOUSE_PICKER_CLASS_ZONE5 :Town centre
|
||||
|
||||
STR_STATION_CLASS_DFLT :Default
|
||||
STR_STATION_CLASS_DFLT_STATION :Default station
|
||||
@ -5001,6 +5014,7 @@ STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... ther
|
||||
STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Road works in progress
|
||||
STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Can't delete this town...{}A station or depot is referring to the town or a town owned tile can't be removed
|
||||
STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... there is no suitable place for a statue in the centre of this town
|
||||
STR_ERROR_CAN_T_BUILD_HOUSE :{WHITE}Can't build house...
|
||||
|
||||
# Industry related errors
|
||||
STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... too many industries
|
||||
|
@ -172,6 +172,15 @@ void InitializeBuildingCounts()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get read-only span of total HouseID building counts.
|
||||
* @return span of HouseID building counts.
|
||||
*/
|
||||
std::span<const uint> GetBuildingHouseIDCounts()
|
||||
{
|
||||
return _building_counts.id_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* IncreaseBuildingCount()
|
||||
* Increase the count of a building when it has been added by a town.
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "clear_map.h"
|
||||
#include "company_func.h"
|
||||
#include "company_base.h"
|
||||
#include "house.h"
|
||||
#include "gui.h"
|
||||
#include "window_gui.h"
|
||||
#include "window_func.h"
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "dropdown_type.h"
|
||||
#include "dropdown_func.h"
|
||||
#include "dropdown_common_type.h"
|
||||
#include "house.h"
|
||||
#include "vehicle_gui.h"
|
||||
#include "rail_gui.h"
|
||||
#include "road.h"
|
||||
@ -1211,12 +1212,18 @@ static CallBackFunction ToolbarScenGenLand(Window *w)
|
||||
return CBF_NONE;
|
||||
}
|
||||
|
||||
|
||||
static CallBackFunction ToolbarScenGenTown(Window *w)
|
||||
static CallBackFunction ToolbarScenGenTownClick(Window *w)
|
||||
{
|
||||
w->HandleButtonClick(WID_TE_TOWN_GENERATE);
|
||||
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
|
||||
ShowFoundTownWindow();
|
||||
PopupMainToolbarMenu(w, WID_TE_TOWN_GENERATE, {STR_SCENEDIT_TOWN_MENU_BUILD_TOWN, STR_SCENEDIT_TOWN_MENU_PACE_HOUSE});
|
||||
return CBF_NONE;
|
||||
}
|
||||
|
||||
static CallBackFunction ToolbarScenGenTown(int index)
|
||||
{
|
||||
switch (index) {
|
||||
case 0: ShowFoundTownWindow(); break;
|
||||
case 1: ShowBuildHousePicker(nullptr); break;
|
||||
}
|
||||
return CBF_NONE;
|
||||
}
|
||||
|
||||
@ -2223,7 +2230,7 @@ static MenuClickedProc * const _scen_toolbar_dropdown_procs[] = {
|
||||
nullptr, // 9
|
||||
nullptr, // 10
|
||||
nullptr, // 11
|
||||
nullptr, // 12
|
||||
ToolbarScenGenTown, // 12
|
||||
nullptr, // 13
|
||||
ToolbarScenBuildRoad, // 14
|
||||
ToolbarScenBuildTram, // 15
|
||||
@ -2249,7 +2256,7 @@ static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
|
||||
ToolbarZoomInClick,
|
||||
ToolbarZoomOutClick,
|
||||
ToolbarScenGenLand,
|
||||
ToolbarScenGenTown,
|
||||
ToolbarScenGenTownClick,
|
||||
ToolbarScenGenIndustry,
|
||||
ToolbarScenBuildRoadClick,
|
||||
ToolbarScenBuildTramClick,
|
||||
@ -2376,7 +2383,7 @@ struct ScenarioEditorToolbarWindow : Window {
|
||||
case MTEHK_SETTINGS: ShowGameOptions(); break;
|
||||
case MTEHK_SAVEGAME: MenuClickSaveLoad(); break;
|
||||
case MTEHK_GENLAND: ToolbarScenGenLand(this); break;
|
||||
case MTEHK_GENTOWN: ToolbarScenGenTown(this); break;
|
||||
case MTEHK_GENTOWN: ToolbarScenGenTownClick(this); break;
|
||||
case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break;
|
||||
case MTEHK_BUILD_ROAD: ToolbarScenBuildRoadClick(this); break;
|
||||
case MTEHK_BUILD_TRAM: ToolbarScenBuildTramClick(this); break;
|
||||
|
@ -320,5 +320,6 @@ inline uint16_t TownTicksToGameTicks(uint16_t ticks)
|
||||
|
||||
RoadType GetTownRoadType();
|
||||
bool CheckTownRoadTypes();
|
||||
std::span<const DrawBuildingsTileStruct> GetTownDrawTileData();
|
||||
|
||||
#endif /* TOWN_H */
|
||||
|
@ -4066,3 +4066,8 @@ extern const TileTypeProcs _tile_type_town_procs = {
|
||||
GetFoundation_Town, // get_foundation_proc
|
||||
TerraformTile_Town, // terraform_tile_proc
|
||||
};
|
||||
|
||||
std::span<const DrawBuildingsTileStruct> GetTownDrawTileData()
|
||||
{
|
||||
return _town_draw_tile_data;
|
||||
}
|
||||
|
321
src/town_gui.cpp
321
src/town_gui.cpp
@ -12,6 +12,9 @@
|
||||
#include "viewport_func.h"
|
||||
#include "error.h"
|
||||
#include "gui.h"
|
||||
#include "house.h"
|
||||
#include "newgrf_house.h"
|
||||
#include "picker_gui.h"
|
||||
#include "command_func.h"
|
||||
#include "company_func.h"
|
||||
#include "company_base.h"
|
||||
@ -1304,3 +1307,321 @@ void InitializeTownGui()
|
||||
{
|
||||
_town_local_authority_kdtree.Clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw representation of a house tile for GUI purposes.
|
||||
* @param x Position x of image.
|
||||
* @param y Position y of image.
|
||||
* @param spec House spec to draw.
|
||||
* @param house_id House ID to draw.
|
||||
* @param view The house's 'view'.
|
||||
*/
|
||||
void DrawNewHouseTileInGUI(int x, int y, const HouseSpec *spec, HouseID house_id, int view)
|
||||
{
|
||||
HouseResolverObject object(house_id, INVALID_TILE, nullptr, CBID_NO_CALLBACK, 0, 0, true, view);
|
||||
const SpriteGroup *group = object.Resolve();
|
||||
if (group == nullptr || group->type != SGT_TILELAYOUT) return;
|
||||
|
||||
uint8_t stage = TOWN_HOUSE_COMPLETED;
|
||||
const DrawTileSprites *dts = reinterpret_cast<const TileLayoutSpriteGroup *>(group)->ProcessRegisters(&stage);
|
||||
|
||||
PaletteID palette = GENERAL_SPRITE_COLOUR(spec->random_colour[0]);
|
||||
if (HasBit(spec->callback_mask, CBM_HOUSE_COLOUR)) {
|
||||
uint16_t callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, nullptr, INVALID_TILE, true, view);
|
||||
if (callback != CALLBACK_FAILED) {
|
||||
/* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
|
||||
palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
|
||||
}
|
||||
}
|
||||
|
||||
SpriteID image = dts->ground.sprite;
|
||||
PaletteID pal = dts->ground.pal;
|
||||
|
||||
if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage;
|
||||
if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage;
|
||||
|
||||
if (GB(image, 0, SPRITE_WIDTH) != 0) {
|
||||
DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
|
||||
}
|
||||
|
||||
DrawNewGRFTileSeqInGUI(x, y, dts, stage, palette);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a house that does not exist.
|
||||
* @param x Position x of image.
|
||||
* @param y Position y of image.
|
||||
* @param house_id House ID to draw.
|
||||
* @param view The house's 'view'.
|
||||
*/
|
||||
void DrawHouseInGUI(int x, int y, HouseID house_id, int view)
|
||||
{
|
||||
auto draw = [](int x, int y, HouseID house_id, int view) {
|
||||
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. */
|
||||
const HouseSpec *spec = HouseSpec::Get(house_id);
|
||||
if (spec->grf_prop.spritegroup[0] != nullptr) {
|
||||
DrawNewHouseTileInGUI(x, y, spec, house_id, view);
|
||||
return;
|
||||
} else {
|
||||
house_id = HouseSpec::Get(house_id)->grf_prop.subst_id;
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieve data from the draw town tile struct */
|
||||
const DrawBuildingsTileStruct &dcts = GetTownDrawTileData()[house_id << 4 | view << 2 | TOWN_HOUSE_COMPLETED];
|
||||
DrawSprite(dcts.ground.sprite, dcts.ground.pal, x, y);
|
||||
|
||||
/* Add a house on top of the ground? */
|
||||
if (dcts.building.sprite != 0) {
|
||||
Point pt = RemapCoords(dcts.subtile_x, dcts.subtile_y, 0);
|
||||
DrawSprite(dcts.building.sprite, dcts.building.pal, x + UnScaleGUI(pt.x), y + UnScaleGUI(pt.y));
|
||||
}
|
||||
};
|
||||
|
||||
/* Houses can have 1x1, 1x2, 2x1 and 2x2 layouts which are individual HouseIDs. For the GUI we need
|
||||
* draw all of the tiles with appropriate positions. */
|
||||
int x_delta = ScaleGUITrad(TILE_PIXELS);
|
||||
int y_delta = ScaleGUITrad(TILE_PIXELS / 2);
|
||||
|
||||
const HouseSpec *hs = HouseSpec::Get(house_id);
|
||||
if (hs->building_flags & TILE_SIZE_2x2) {
|
||||
draw(x, y - y_delta - y_delta, house_id, view); // North corner.
|
||||
draw(x + x_delta, y - y_delta, house_id + 1, view); // West corner.
|
||||
draw(x - x_delta, y - y_delta, house_id + 2, view); // East corner.
|
||||
draw(x, y, house_id + 3, view); // South corner.
|
||||
} else if (hs->building_flags & TILE_SIZE_2x1) {
|
||||
draw(x + x_delta / 2, y - y_delta, house_id, view); // North east tile.
|
||||
draw(x - x_delta / 2, y, house_id + 1, view); // South west tile.
|
||||
} else if (hs->building_flags & TILE_SIZE_1x2) {
|
||||
draw(x - x_delta / 2, y - y_delta, house_id, view); // North west tile.
|
||||
draw(x + x_delta / 2, y, house_id + 1, view); // South east tile.
|
||||
} else {
|
||||
draw(x, y, house_id, view);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class HousePickerCallbacks : public PickerCallbacks {
|
||||
public:
|
||||
HousePickerCallbacks() : PickerCallbacks("fav_houses") {}
|
||||
|
||||
/**
|
||||
* Set climate mask for filtering buildings from current landscape.
|
||||
*/
|
||||
void SetClimateMask()
|
||||
{
|
||||
switch (_settings_game.game_creation.landscape) {
|
||||
case LT_TEMPERATE: climate_mask = HZ_TEMP; break;
|
||||
case LT_ARCTIC: climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break;
|
||||
case LT_TROPIC: climate_mask = HZ_SUBTROPIC; break;
|
||||
case LT_TOYLAND: climate_mask = HZ_TOYLND; break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
HouseZones climate_mask;
|
||||
|
||||
static inline int sel_class; ///< Currently selected 'class'.
|
||||
static inline int sel_type; ///< Currently selected HouseID.
|
||||
static inline int sel_view; ///< Currently selected 'view'. This is not controllable as its based on random data.
|
||||
|
||||
/* Houses do not have classes like NewGRFClass. We'll make up fake classes based on town zone
|
||||
* availability instead. */
|
||||
static inline const std::array<StringID, HZB_END> zone_names = {
|
||||
STR_HOUSE_PICKER_CLASS_ZONE1,
|
||||
STR_HOUSE_PICKER_CLASS_ZONE2,
|
||||
STR_HOUSE_PICKER_CLASS_ZONE3,
|
||||
STR_HOUSE_PICKER_CLASS_ZONE4,
|
||||
STR_HOUSE_PICKER_CLASS_ZONE5,
|
||||
};
|
||||
|
||||
StringID GetClassTooltip() const override { return STR_PICKER_HOUSE_CLASS_TOOLTIP; }
|
||||
StringID GetTypeTooltip() const override { return STR_PICKER_HOUSE_TYPE_TOOLTIP; }
|
||||
bool IsActive() const override { return true; }
|
||||
|
||||
bool HasClassChoice() const override { return true; }
|
||||
int GetClassCount() const override { return static_cast<int>(zone_names.size()); }
|
||||
|
||||
void Close([[maybe_unused]] int data) override { ResetObjectToPlace(); }
|
||||
|
||||
int GetSelectedClass() const override { return HousePickerCallbacks::sel_class; }
|
||||
void SetSelectedClass(int cls_id) const override { HousePickerCallbacks::sel_class = cls_id; }
|
||||
|
||||
StringID GetClassName(int id) const override
|
||||
{
|
||||
if (id < GetClassCount()) return zone_names[id];
|
||||
return INVALID_STRING_ID;
|
||||
}
|
||||
|
||||
int GetTypeCount(int cls_id) const override
|
||||
{
|
||||
if (cls_id < GetClassCount()) return static_cast<int>(HouseSpec::Specs().size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
PickerItem GetPickerItem(int cls_id, int id) const override
|
||||
{
|
||||
const auto *spec = HouseSpec::Get(id);
|
||||
if (spec->grf_prop.grffile == nullptr) return {0, spec->Index(), cls_id, id};
|
||||
return {spec->grf_prop.grffile->grfid, spec->grf_prop.local_id, cls_id, id};
|
||||
}
|
||||
|
||||
int GetSelectedType() const override { return sel_type; }
|
||||
void SetSelectedType(int id) const override { sel_type = id; }
|
||||
|
||||
StringID GetTypeName(int cls_id, int id) const override
|
||||
{
|
||||
const HouseSpec *spec = HouseSpec::Get(id);
|
||||
if (spec == nullptr) return INVALID_STRING_ID;
|
||||
if (!spec->enabled) return INVALID_STRING_ID;
|
||||
if ((spec->building_availability & climate_mask) == 0) return INVALID_STRING_ID;
|
||||
if (!HasBit(spec->building_availability, cls_id)) return INVALID_STRING_ID;
|
||||
for (int i = 0; i < cls_id; i++) {
|
||||
/* Don't include if it's already included in an earlier zone. */
|
||||
if (HasBit(spec->building_availability, i)) return INVALID_STRING_ID;
|
||||
}
|
||||
|
||||
return spec->building_name;
|
||||
}
|
||||
|
||||
bool IsTypeAvailable(int, int id) const override
|
||||
{
|
||||
const HouseSpec *hs = HouseSpec::Get(id);
|
||||
if (!hs->enabled) return false;
|
||||
if (TimerGameCalendar::year < hs->min_year || TimerGameCalendar::year > hs->max_year) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrawType(int x, int y, int, int id) const override
|
||||
{
|
||||
DrawHouseInGUI(x, y, id, HousePickerCallbacks::sel_view);
|
||||
}
|
||||
|
||||
void FillUsedItems(std::set<PickerItem> &items) override
|
||||
{
|
||||
auto id_count = GetBuildingHouseIDCounts();
|
||||
for (auto it = id_count.begin(); it != id_count.end(); ++it) {
|
||||
if (*it == 0) continue;
|
||||
HouseID house = static_cast<HouseID>(std::distance(id_count.begin(), it));
|
||||
const HouseSpec *hs = HouseSpec::Get(house);
|
||||
int class_index = FindFirstBit(hs->building_availability & HZ_ZONALL);
|
||||
items.insert({0, house, class_index, house});
|
||||
}
|
||||
}
|
||||
|
||||
std::set<PickerItem> UpdateSavedItems(const std::set<PickerItem> &src) override
|
||||
{
|
||||
if (src.empty()) return src;
|
||||
|
||||
const auto specs = HouseSpec::Specs();
|
||||
std::set<PickerItem> dst;
|
||||
for (const auto &item : src) {
|
||||
if (item.grfid == 0) {
|
||||
dst.insert(item);
|
||||
} else {
|
||||
/* Search for spec by grfid and local index. */
|
||||
auto it = std::find_if(specs.begin(), specs.end(), [&item](const HouseSpec &spec) { return spec.grf_prop.grffile != nullptr && spec.grf_prop.grffile->grfid == item.grfid && spec.grf_prop.local_id == item.local_id; });
|
||||
if (it == specs.end()) {
|
||||
/* Not preset, hide from UI. */
|
||||
dst.insert({item.grfid, item.local_id, -1, -1});
|
||||
} else {
|
||||
int class_index = FindFirstBit(it->building_availability & HZ_ZONALL);
|
||||
dst.insert( {item.grfid, item.local_id, class_index, it->Index()});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
static HousePickerCallbacks instance;
|
||||
};
|
||||
/* static */ HousePickerCallbacks HousePickerCallbacks::instance;
|
||||
|
||||
struct BuildHouseWindow : public PickerWindow {
|
||||
BuildHouseWindow(WindowDesc *desc, Window *parent) : PickerWindow(desc, parent, 0, HousePickerCallbacks::instance)
|
||||
{
|
||||
HousePickerCallbacks::instance.SetClimateMask();
|
||||
this->ConstructWindow();
|
||||
this->InvalidateData();
|
||||
}
|
||||
|
||||
void UpdateSelectSize(const HouseSpec *spec)
|
||||
{
|
||||
if (spec == nullptr) {
|
||||
SetTileSelectSize(1, 1);
|
||||
ResetObjectToPlace();
|
||||
} else {
|
||||
SetObjectToPlaceWnd(SPR_CURSOR_TOWN, PAL_NONE, HT_RECT | HT_DIAGONAL, this);
|
||||
if (spec->building_flags & TILE_SIZE_2x2) {
|
||||
SetTileSelectSize(2, 2);
|
||||
} else if (spec->building_flags & TILE_SIZE_2x1) {
|
||||
SetTileSelectSize(2, 1);
|
||||
} else if (spec->building_flags & TILE_SIZE_1x2) {
|
||||
SetTileSelectSize(1, 2);
|
||||
} else if (spec->building_flags & TILE_SIZE_1x1) {
|
||||
SetTileSelectSize(1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnInvalidateData(int data = 0, bool gui_scope = true) override
|
||||
{
|
||||
this->PickerWindow::OnInvalidateData(data, gui_scope);
|
||||
if (!gui_scope) return;
|
||||
|
||||
if ((data & PickerWindow::PFI_POSITION) != 0) {
|
||||
const HouseSpec *spec = HouseSpec::Get(HousePickerCallbacks::sel_type);
|
||||
UpdateSelectSize(spec);
|
||||
}
|
||||
}
|
||||
|
||||
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
|
||||
{
|
||||
const HouseSpec *spec = HouseSpec::Get(HousePickerCallbacks::sel_type);
|
||||
Command<CMD_PLACE_HOUSE>::Post(STR_ERROR_CAN_T_BUILD_HOUSE, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index());
|
||||
}
|
||||
|
||||
IntervalTimer<TimerWindow> view_refresh_interval = {std::chrono::milliseconds(2500), [this](auto) {
|
||||
/* There are four different 'views' that are random based on house tile position. As this is not
|
||||
* user-controllable, instead we automatically cycle through them. */
|
||||
HousePickerCallbacks::sel_view = (HousePickerCallbacks::sel_view + 1) % 4;
|
||||
this->SetDirty();
|
||||
}};
|
||||
|
||||
static inline HotkeyList hotkeys{"buildhouse", {
|
||||
Hotkey('F', "focus_filter_box", PCWHK_FOCUS_FILTER_BOX),
|
||||
}};
|
||||
};
|
||||
|
||||
/** Nested widget definition for the build NewGRF rail waypoint window */
|
||||
static constexpr NWidgetPart _nested_build_house_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_HOUSE_PICKER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidgetFunction(MakePickerClassWidgets),
|
||||
NWidgetFunction(MakePickerTypeWidgets),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
static WindowDesc _build_house_desc(
|
||||
WDP_AUTO, "build_house", 0, 0,
|
||||
WC_BUILD_HOUSE, WC_BUILD_TOOLBAR,
|
||||
WDF_CONSTRUCTION,
|
||||
std::begin(_nested_build_house_widgets), std::end(_nested_build_house_widgets),
|
||||
&BuildHouseWindow::hotkeys
|
||||
);
|
||||
|
||||
void ShowBuildHousePicker(Window *parent)
|
||||
{
|
||||
if (BringWindowToFrontById(WC_BUILD_HOUSE, 0)) return;
|
||||
new BuildHouseWindow(&_build_house_desc, parent);
|
||||
}
|
||||
|
@ -375,6 +375,12 @@ enum WindowClass {
|
||||
*/
|
||||
WC_BUILD_OBJECT,
|
||||
|
||||
/**
|
||||
* Build house; %Window numbers:
|
||||
* - 0 = #BuildHouseWidgets
|
||||
*/
|
||||
WC_BUILD_HOUSE,
|
||||
|
||||
/**
|
||||
* Build vehicle; %Window numbers:
|
||||
* - #VehicleType = #BuildVehicleWidgets
|
||||
|
Loading…
Reference in New Issue
Block a user