Update to v4 of house placing patch.
This commit is contained in:
686
src/town_gui.cpp
686
src/town_gui.cpp
@@ -18,6 +18,7 @@
|
||||
#include "company_func.h"
|
||||
#include "company_base.h"
|
||||
#include "company_gui.h"
|
||||
#include "core/random_func.hpp"
|
||||
#include "network/network.h"
|
||||
#include "string_func.h"
|
||||
#include "strings_func.h"
|
||||
@@ -35,16 +36,21 @@
|
||||
#include "newgrf_config.h"
|
||||
#include "newgrf_house.h"
|
||||
#include "date_func.h"
|
||||
#include "core/random_func.hpp"
|
||||
#include "zoom_func.h"
|
||||
|
||||
#include "widgets/town_widget.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
typedef GUIList<const Town*> GUITownList;
|
||||
|
||||
static CommandCost ListTownsToJoinHouseTo(HouseID house, TileIndex tile, TownList *towns);
|
||||
static void ShowSelectTownWindow(const TownList &towns, const CommandContainer &cmd);
|
||||
|
||||
static const NWidgetPart _nested_town_authority_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
|
||||
@@ -1198,11 +1204,15 @@ static WindowDesc _found_town_desc(
|
||||
|
||||
void ShowFoundTownWindow()
|
||||
{
|
||||
if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
|
||||
if (_game_mode != GM_EDITOR) {
|
||||
if (_settings_game.economy.found_town == TF_FORBIDDEN) return;
|
||||
if (!Company::IsValidID(_local_company)) return;
|
||||
}
|
||||
AllocateWindowDescFront<FoundTownWindow>(&_found_town_desc, 0);
|
||||
}
|
||||
|
||||
class GUIHouseList : public SmallVector<HouseID, 32> {
|
||||
/** List of buildable houses and house sets. */
|
||||
class GUIHouseList : protected SmallVector<HouseID, 32> {
|
||||
protected:
|
||||
SmallVector<uint16, 4> house_sets; ///< list of house sets, each item points the first house of the set in the houses array
|
||||
|
||||
@@ -1232,89 +1242,119 @@ public:
|
||||
*this->house_sets.Append() = 0; // terminator
|
||||
}
|
||||
|
||||
inline HouseID GetHouseAtOffset(uint house_set, uint house_offset) const
|
||||
/**
|
||||
* Get house at given offset.
|
||||
* @param house_set House set (or a negative number).
|
||||
* @param house_offset Offset of the house within the set (or a negative number).
|
||||
* @return House at given offset or #INVALID_HOUSE_ID if \c house_set or \c house_offset is negative.
|
||||
*/
|
||||
inline HouseID GetHouseAtOffset(int house_set, int house_offset) const
|
||||
{
|
||||
if (house_set < 0 || house_offset < 0) return INVALID_HOUSE_ID;
|
||||
assert(house_set < (int)this->NumHouseSets());
|
||||
assert(this->house_sets[house_set] + house_offset < (int)this->Length());
|
||||
return *this->Get(this->house_sets[house_set] + house_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of house sets.
|
||||
* @return Number of house sets.
|
||||
*/
|
||||
uint NumHouseSets() const
|
||||
{
|
||||
return this->house_sets.Length() - 1; // last item is a terminator
|
||||
}
|
||||
|
||||
uint NumHousesInHouseSet(uint house_set) const
|
||||
/**
|
||||
* Get number of houses in a given set.
|
||||
* @param house_set House set (or a negative number).
|
||||
* @return Number of houses in the given set or 0 if \c house_set is negative.
|
||||
*/
|
||||
uint NumHousesInHouseSet(int house_set) const
|
||||
{
|
||||
assert(house_set < this->NumHouseSets());
|
||||
assert(house_set < (int)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 != NULL) return GetGRFConfig(gf->grfid)->GetName();
|
||||
|
||||
static char name[DRAW_STRING_BUFFER];
|
||||
GetString(name, STR_BASIC_HOUSE_SET_NAME, lastof(name));
|
||||
return name;
|
||||
return house_set < 0 ? 0 : this->house_sets[house_set + 1] - this->house_sets[house_set];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the sortlist that the rebuild is done
|
||||
* Find the house set of a given house.
|
||||
*
|
||||
* @note This forces a resort
|
||||
* This operation is O(number of house sets).
|
||||
*
|
||||
* @param house The house (or #INVALID_HOUSE_ID).
|
||||
* @return House set of the house or -1 if not found.
|
||||
*/
|
||||
int FindHouseSet(HouseID house) const
|
||||
{
|
||||
if (house != INVALID_HOUSE_ID) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find offset of a given house within a given house set.
|
||||
*
|
||||
* This operation is O(number of houses in the set).
|
||||
*
|
||||
* @param house_set House set to search in (or a negative number).
|
||||
* @param house The house (or #INVALID_HOUSE_ID).
|
||||
* @return Offset of the house within the set or -1 if not found or \c house_set is negative.
|
||||
*/
|
||||
int FindHouseOffset(int house_set, HouseID house) const
|
||||
{
|
||||
assert(house_set < (int)this->NumHouseSets());
|
||||
if (house_set >= 0 && house != INVALID_HOUSE_ID) {
|
||||
const HouseID *begin = this->Begin() + this->house_sets[house_set];
|
||||
const HouseID *end = this->Begin() + this->house_sets[house_set + 1];
|
||||
const HouseID *pos = std::lower_bound(begin, end, house);
|
||||
if (pos != end && *pos == house) return pos - begin;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of a given house set.
|
||||
*
|
||||
* @param house_set The set.
|
||||
* @return The name (appropriate string parameters will be set).
|
||||
*/
|
||||
StringID GetNameOfHouseSet(uint house_set) const
|
||||
{
|
||||
assert(house_set < this->NumHouseSets());
|
||||
const GRFFile *grf = HouseSpec::Get(this->GetHouseAtOffset(house_set, 0))->grf_prop.grffile;
|
||||
if (grf != NULL) {
|
||||
SetDParamStr(0, GetGRFConfig(grf->grfid)->GetName());
|
||||
return STR_JUST_RAW_STRING;
|
||||
} else {
|
||||
SetDParam(0, STR_BASIC_HOUSE_SET_NAME);
|
||||
return STR_JUST_STRING;
|
||||
}
|
||||
}
|
||||
|
||||
/** (Re)build the list. */
|
||||
void Build()
|
||||
{
|
||||
/* collect items */
|
||||
this->Clear();
|
||||
HouseZones zones = CurrentClimateHouseZones();
|
||||
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->Append() = house;
|
||||
if (IsHouseTypeAllowed(house, zones, _game_mode == GM_EDITOR).Succeeded()) *this->Append() = house;
|
||||
}
|
||||
this->Compact();
|
||||
|
||||
/* arrange items */
|
||||
QSortT(this->Begin(), this->Length(), HouseSorter);
|
||||
|
||||
/* list house sets */
|
||||
this->house_sets.Clear();
|
||||
const GRFFile *last_set;
|
||||
const GRFFile *last_set = NULL;
|
||||
for (uint i = 0; i < this->Length(); i++) {
|
||||
const HouseSpec *hs = HouseSpec::Get((*this)[i]);
|
||||
/* add house set */
|
||||
@@ -1328,83 +1368,128 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static HouseID _cur_house = INVALID_HOUSE_ID; ///< house selected in the house picker window
|
||||
static struct {
|
||||
HouseID id;
|
||||
HouseVariant variant;
|
||||
}
|
||||
_cur_house = { INVALID_HOUSE_ID, HOUSE_NO_VARIANT }; ///< house selected in the house picker window
|
||||
|
||||
/** The window used for building houses. */
|
||||
class HousePickerWindow : public PickerWindowBase {
|
||||
class HousePickerWindow : public Window {
|
||||
friend void ShowBuildHousePicker();
|
||||
|
||||
protected:
|
||||
GUIHouseList house_list; ///< list of houses and house sets
|
||||
uint 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
|
||||
GUIHouseList house_list; ///< list of houses and house sets
|
||||
HouseZonesBits tileselect_zone; ///< house zone (closest town) of currently highlighted tile
|
||||
bool tileselect_bad_land; ///< whether currently highlighted tile has wrong landscape for the house (e.g. wrong side of the snowline)
|
||||
|
||||
void RestoreSelectedHouseIndex()
|
||||
/**
|
||||
* Get the height of a single line in the list of house sets.
|
||||
* @return the height
|
||||
*/
|
||||
inline uint GetLineHeight() const
|
||||
{
|
||||
this->house_set = 0;
|
||||
this->house_offset = 0;
|
||||
return FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
|
||||
}
|
||||
|
||||
if (this->house_list.Length() == 0) { // no houses at all?
|
||||
_cur_house = INVALID_HOUSE_ID;
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Test whether this window is currently being a callback window for ongoing tile selection.
|
||||
* @return result of the test
|
||||
* @see SetObjectToPlace
|
||||
*/
|
||||
inline bool IsObjectToPlaceSet() const
|
||||
{
|
||||
return _thd.window_class == WC_BUILD_HOUSE;
|
||||
}
|
||||
|
||||
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);
|
||||
/**
|
||||
* Test whether a given house is currently disabled (greyed out houses).
|
||||
* @return result of the test
|
||||
*/
|
||||
inline bool IsHouseDisabled(HouseID house) const
|
||||
{
|
||||
if (_game_mode == GM_EDITOR) return false;
|
||||
const HouseSpec *hs = HouseSpec::Get(house);
|
||||
return _cur_year < hs->min_year || _cur_year > hs->max_year;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get currently selected house set.
|
||||
* @return index of the house set
|
||||
*/
|
||||
int GetCurrentHouseSet() const
|
||||
{
|
||||
return this->house_list.FindHouseSet(_cur_house.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select another house.
|
||||
* @param new_house_set index of the house set
|
||||
* @param new_house_offset offset of the house
|
||||
* @param new_house_set index of the house set, -1 to auto-select
|
||||
* @param new_house_offset offset of the house, -1 to auto-select
|
||||
* @param new_house_variant variant of the house, -1 to auto-select
|
||||
* @param clicked whether to make the house button "clicked" and activate house placement (>0 yes, 0 no, -1 auto)
|
||||
*/
|
||||
void SelectOtherHouse(uint new_house_set, uint new_house_offset)
|
||||
void SelectOtherHouse(int new_house_set, int new_house_offset, int new_house_variant, int clicked)
|
||||
{
|
||||
assert(new_house_set < this->house_list.NumHouseSets());
|
||||
assert(new_house_offset < this->house_list.NumHousesInHouseSet(new_house_set));
|
||||
if (this->house_list.NumHouseSets() == 0) { // special handling needed
|
||||
_cur_house.id = INVALID_HOUSE_ID;
|
||||
_cur_house.variant = HOUSE_NO_VARIANT;
|
||||
if (this->IsObjectToPlaceSet()) ResetObjectToPlace();
|
||||
return;
|
||||
}
|
||||
|
||||
_cur_house = this->house_list.GetHouseAtOffset(new_house_set, new_house_offset);
|
||||
this->house_set = new_house_set;
|
||||
this->house_offset = new_house_offset;
|
||||
/* auto-select */
|
||||
if (new_house_set < 0) new_house_set = max(0, this->GetCurrentHouseSet());
|
||||
if (new_house_offset < 0) new_house_offset = max(0, this->house_list.FindHouseOffset(new_house_set, _cur_house.id));
|
||||
if (clicked < 0) clicked = this->IsObjectToPlaceSet() ? 1 : 0;
|
||||
|
||||
HouseID new_house_id = this->house_list.GetHouseAtOffset(new_house_set, new_house_offset);
|
||||
|
||||
const HouseSpec *hs = HouseSpec::Get(new_house_id);
|
||||
if (hs->num_variants == 0) {
|
||||
new_house_variant = HOUSE_NO_VARIANT;
|
||||
} else {
|
||||
if (new_house_variant < 0 && new_house_id == _cur_house.id) new_house_variant = _cur_house.variant;
|
||||
if (!IsInsideBS(new_house_variant, HOUSE_FIRST_VARIANT, hs->num_variants)) new_house_variant = HOUSE_FIRST_VARIANT;
|
||||
}
|
||||
|
||||
_cur_house.id = new_house_id;
|
||||
_cur_house.variant = new_house_variant;
|
||||
|
||||
bool disabled = this->IsHouseDisabled(_cur_house.id);
|
||||
|
||||
if (clicked > 0 ? disabled : this->IsObjectToPlaceSet()) {
|
||||
ResetObjectToPlace(); // warning, this may cause recursion through OnPlaceObjectAbort
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
matrix->SetCount(this->house_list.NumHousesInHouseSet(new_house_set));
|
||||
matrix->SetClicked(clicked > 0 ? new_house_offset : -1);
|
||||
|
||||
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++;
|
||||
this->GetWidget<NWidgetStacked>(WID_HP_PREV_VARIANT_SEL)->SetDisplayedPlane(hs->num_variants > 1 ? 0 : SZSP_NONE);
|
||||
this->GetWidget<NWidgetStacked>(WID_HP_NEXT_VARIANT_SEL)->SetDisplayedPlane(hs->num_variants > 1 ? 0 : SZSP_NONE);
|
||||
this->SetWidgetDisabledState(WID_HP_PREV_VARIANT, _cur_house.variant <= HOUSE_FIRST_VARIANT);
|
||||
this->SetWidgetDisabledState(WID_HP_NEXT_VARIANT, _cur_house.variant >= HOUSE_FIRST_VARIANT + hs->num_variants - 1);
|
||||
|
||||
this->SetDirty();
|
||||
|
||||
if (clicked > 0 && !disabled) {
|
||||
if (!this->IsObjectToPlaceSet()) SetObjectToPlaceWnd(SPR_CURSOR_TOWN, PAL_NONE, HT_RECT, this);
|
||||
SetTileSelectSize(
|
||||
hs->building_flags & BUILDING_2_TILES_X ? 2 : 1,
|
||||
hs->building_flags & BUILDING_2_TILES_Y ? 2 : 1);
|
||||
}
|
||||
SetTileSelectSize(w, h);
|
||||
}
|
||||
|
||||
public:
|
||||
HousePickerWindow(WindowDesc *desc, Window *w) : PickerWindowBase(desc, w)
|
||||
HousePickerWindow(WindowDesc *desc, WindowNumber number) : Window(desc), tileselect_zone(HZB_END), tileselect_bad_land(false)
|
||||
{
|
||||
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(0);
|
||||
|
||||
if (_cur_house != INVALID_HOUSE_ID) matrix->SetClicked(this->house_offset); // set clicked item again to make it visible
|
||||
this->FinishInitNested(number);
|
||||
}
|
||||
|
||||
~HousePickerWindow()
|
||||
@@ -1415,28 +1500,20 @@ public:
|
||||
virtual void OnInit()
|
||||
{
|
||||
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 != NULL) ?
|
||||
STR_HOUSE_BUILD_CUSTOM_CAPTION : STR_HOUSE_BUILD_CAPTION;
|
||||
/* restore last house */
|
||||
this->SelectOtherHouse(-1, -1, -1, -1);
|
||||
|
||||
/* hide widgets if we have no houses to show */
|
||||
this->SetShaded(this->house_list.Length() == 0);
|
||||
this->SetShaded(this->house_list.NumHouseSets() == 0);
|
||||
|
||||
if (this->house_list.Length() != 0) {
|
||||
if (this->house_list.NumHouseSets() != 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1444,48 +1521,53 @@ public:
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_HP_CAPTION:
|
||||
if (this->house_list.NumHouseSets() == 1) SetDParamStr(0, this->house_list.GetNameOfHouseSet(0));
|
||||
if (this->house_list.NumHouseSets() == 1 && _loaded_newgrf_features.has_newhouses) {
|
||||
StringID str = this->house_list.GetNameOfHouseSet(0);
|
||||
InjectDParam(1);
|
||||
SetDParam(0, str);
|
||||
} else {
|
||||
SetDParam(0, STR_JUST_STRING);
|
||||
SetDParam(1, STR_HOUSE_BUILD_CAPTION_DEFAULT_TEXT);
|
||||
}
|
||||
break;
|
||||
|
||||
case WID_HP_HOUSE_NAME:
|
||||
SetDParam(0, GetHouseName(_cur_house));
|
||||
SetDParam(0, GetHouseName(_cur_house.id, INVALID_TILE, _cur_house.variant));
|
||||
break;
|
||||
|
||||
case WID_HP_HISTORICAL_BUILDING:
|
||||
SetDParam(0, HouseSpec::Get(_cur_house)->extra_flags & BUILDING_IS_HISTORICAL ? STR_HOUSE_BUILD_HISTORICAL_BUILDING : STR_EMPTY);
|
||||
SetDParam(0, HouseSpec::Get(_cur_house.id)->extra_flags & BUILDING_IS_HISTORICAL ? STR_HOUSE_BUILD_HISTORICAL_BUILDING : STR_EMPTY);
|
||||
break;
|
||||
|
||||
case WID_HP_HOUSE_POPULATION:
|
||||
SetDParam(0, HouseSpec::Get(_cur_house)->population);
|
||||
SetDParam(0, HouseSpec::Get(_cur_house.id)->population);
|
||||
break;
|
||||
|
||||
case WID_HP_HOUSE_ZONES: {
|
||||
HouseZones zones = (HouseZones)(HouseSpec::Get(_cur_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: 1(center)/2/3/4/5(edge) */
|
||||
HouseZones zones = (HouseZones)(HouseSpec::Get(_cur_house.id)->building_availability & HZ_ZONALL);
|
||||
for (HouseZonesBits i = HZB_BEGIN; i < HZB_END; i++) {
|
||||
StringID str = STR_HOUSE_BUILD_HOUSE_ZONE_GOOD;
|
||||
str += !HasBit(zones, i) ? 1 : 0; // bad : good
|
||||
str += (this->tileselect_zone == i) ? 2 : 0; // highlighted : not highlighted
|
||||
SetDParam(2 * i, str);
|
||||
SetDParam(2 * i + 1, i + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_HP_HOUSE_LANDSCAPE: {
|
||||
StringID info = STR_HOUSE_BUILD_LANDSCAPE_ABOVE_OR_BELOW_SNOWLINE;
|
||||
switch (HouseSpec::Get(_cur_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;
|
||||
case WID_HP_HOUSE_LANDSCAPE:
|
||||
switch (HouseSpec::Get(_cur_house.id)->building_availability & (HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW)) {
|
||||
case HZ_SUBARTC_ABOVE: SetDParam(0, this->tileselect_bad_land ? STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE_BAD : STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE_GOOD); break;
|
||||
case HZ_SUBARTC_BELOW: SetDParam(0, this->tileselect_bad_land ? STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE_BAD : STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE_GOOD); break;
|
||||
default: SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ABOVE_OR_BELOW_SNOWLINE); break;
|
||||
}
|
||||
SetDParam(0, info);
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_HP_HOUSE_YEARS: {
|
||||
const HouseSpec *hs = HouseSpec::Get(_cur_house);
|
||||
SetDParam(0, hs->min_year <= _cur_year ? STR_HOUSE_BUILD_YEARS_GOOD_YEAR : STR_HOUSE_BUILD_YEARS_BAD_YEAR);
|
||||
const HouseSpec *hs = HouseSpec::Get(_cur_house.id);
|
||||
SetDParam(0, hs->min_year <= _cur_year ? STR_HOUSE_BUILD_YEAR_GOOD : STR_HOUSE_BUILD_YEAR_BAD);
|
||||
SetDParam(1, hs->min_year);
|
||||
SetDParam(2, hs->max_year >= _cur_year ? STR_HOUSE_BUILD_YEARS_GOOD_YEAR : STR_HOUSE_BUILD_YEARS_BAD_YEAR);
|
||||
SetDParam(2, hs->max_year >= _cur_year ? STR_HOUSE_BUILD_YEAR_GOOD : STR_HOUSE_BUILD_YEAR_BAD);
|
||||
SetDParam(3, hs->max_year);
|
||||
break;
|
||||
}
|
||||
@@ -1495,7 +1577,7 @@ public:
|
||||
char *str = buff;
|
||||
CargoArray cargo;
|
||||
uint32 dummy = 0;
|
||||
AddAcceptedHouseCargo(_cur_house, INVALID_TILE, cargo, &dummy);
|
||||
AddAcceptedHouseCargo(_cur_house.id, INVALID_TILE, cargo, &dummy, _cur_house.variant);
|
||||
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 */
|
||||
@@ -1511,7 +1593,7 @@ public:
|
||||
|
||||
case WID_HP_HOUSE_SUPPLY: {
|
||||
CargoArray cargo;
|
||||
AddProducedHouseCargo(_cur_house, INVALID_TILE, cargo);
|
||||
AddProducedHouseCargo(_cur_house.id, INVALID_TILE, cargo, _cur_house.variant);
|
||||
uint32 cargo_mask = 0;
|
||||
for (uint i = 0; i < NUM_CARGO; i++) if (cargo[i] != 0) SetBit(cargo_mask, i);
|
||||
SetDParam(0, cargo_mask);
|
||||
@@ -1531,11 +1613,15 @@ public:
|
||||
max_w = max(max_w, GetStringBoundingBox(this->house_list.GetNameOfHouseSet(i)).width);
|
||||
}
|
||||
size->width = max(size->width, max_w + padding.width);
|
||||
this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
|
||||
size->height = this->house_list.NumHouseSets() * this->line_height;
|
||||
size->height = this->house_list.NumHouseSets() * this->GetLineHeight();
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_HP_HOUSE_PREVIEW:
|
||||
size->width = max(size->width, ScaleGUITrad(4 * TILE_PIXELS) + padding.width);
|
||||
size->height = max(size->height, ScaleGUITrad(140) + padding.height); // this is slightly less then MAX_BUILDING_PIXELS, buildings will be clipped if necessary
|
||||
break;
|
||||
|
||||
case WID_HP_HOUSE_NAME:
|
||||
size->width = 120; // we do not want this window to get too wide, better clip
|
||||
break;
|
||||
@@ -1546,25 +1632,20 @@ public:
|
||||
|
||||
case WID_HP_HOUSE_POPULATION:
|
||||
SetDParam(0, 0);
|
||||
/* max popultion is 255 - 3 digits */
|
||||
size->width = max(size->width, GetStringBoundingBox(STR_HOUSE_BUILD_HOUSE_POPULATION).width + 3 * GetDigitWidth() + padding.width);
|
||||
SetDParamMaxValue(0, UINT8_MAX);
|
||||
size->width = max(size->width, GetStringBoundingBox(STR_HOUSE_BUILD_HOUSE_POPULATION).width + 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 = 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);
|
||||
SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE_GOOD);
|
||||
dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE));
|
||||
SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE);
|
||||
SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE_BAD);
|
||||
dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE));
|
||||
SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE_GOOD);
|
||||
dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE));
|
||||
SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE_BAD);
|
||||
dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE));
|
||||
dim.width += padding.width;
|
||||
dim.height += padding.height;
|
||||
@@ -1573,12 +1654,17 @@ public:
|
||||
}
|
||||
|
||||
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
|
||||
SetDParamMaxValue(1, MAX_YEAR);
|
||||
SetDParamMaxValue(3, MAX_YEAR);
|
||||
Dimension dim = { 0, 0 };
|
||||
for (uint good_bad_from = 0; good_bad_from < 2; good_bad_from++) {
|
||||
for (uint good_bad_to = 0; good_bad_to < 2; good_bad_to++) {
|
||||
SetDParam(0, STR_HOUSE_BUILD_YEAR_GOOD + good_bad_from);
|
||||
SetDParam(2, STR_HOUSE_BUILD_YEAR_GOOD + good_bad_to);
|
||||
dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_YEARS));
|
||||
}
|
||||
}
|
||||
dim.width += padding.width;
|
||||
dim.height += padding.height;
|
||||
*size = maxdim(*size, dim);
|
||||
break;
|
||||
@@ -1588,6 +1674,11 @@ public:
|
||||
resize->height = 1; // don't snap to rows of this matrix
|
||||
break;
|
||||
|
||||
case WID_HP_HOUSE_SELECT:
|
||||
size->width = ScaleGUITrad(2 * TILE_PIXELS) + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT;
|
||||
size->height = ScaleGUITrad(58) + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM;
|
||||
break;
|
||||
|
||||
/* these texts can be long, better clip */
|
||||
case WID_HP_HOUSE_ACCEPTANCE:
|
||||
case WID_HP_HOUSE_SUPPLY:
|
||||
@@ -1603,29 +1694,31 @@ public:
|
||||
switch (GB(widget, 0, 16)) {
|
||||
case WID_HP_HOUSE_SETS: {
|
||||
int y = r.top + WD_MATRIX_TOP;
|
||||
int sel = this->GetCurrentHouseSet();
|
||||
for (uint i = 0; i < this->house_list.NumHouseSets(); i++) {
|
||||
SetDParamStr(0, this->house_list.GetNameOfHouseSet(i));
|
||||
DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y, STR_JUST_RAW_STRING, i == this->house_set ? TC_WHITE : TC_BLACK);
|
||||
y += this->line_height;
|
||||
DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y, this->house_list.GetNameOfHouseSet(i), (int)i == sel ? TC_WHITE : TC_BLACK);
|
||||
y += this->GetLineHeight();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_HP_HOUSE_PREVIEW:
|
||||
DrawHouseImage(_cur_house, r.left, r.top, r.right, r.bottom);
|
||||
DrawHouseImage(_cur_house.id, r.left, r.top, r.right, r.bottom, HIT_GUI_HOUSE_PREVIEW, _cur_house.variant);
|
||||
break;
|
||||
|
||||
case WID_HP_HOUSE_SELECT: {
|
||||
HouseID house = this->house_list.GetHouseAtOffset(this->house_set, GB(widget, 16, 16));
|
||||
int lowered = (house == _cur_house) ? 1 : 0;
|
||||
HouseID house = this->house_list.GetHouseAtOffset(this->GetCurrentHouseSet(), GB(widget, 16, 16));
|
||||
int lowered = (house == _cur_house.id) ? 1 : 0;
|
||||
DrawHouseImage(house,
|
||||
r.left + WD_MATRIX_LEFT + lowered, r.top + WD_MATRIX_TOP + lowered,
|
||||
r.right - WD_MATRIX_RIGHT + lowered, r.bottom - WD_MATRIX_BOTTOM + lowered);
|
||||
const HouseSpec *hs = HouseSpec::Get(house);
|
||||
/* disabled? */
|
||||
if (_cur_year < hs->min_year || _cur_year > hs->max_year) {
|
||||
GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER);
|
||||
}
|
||||
r.left + WD_IMGBTN_LEFT + lowered, r.top + WD_IMGBTN_TOP + lowered,
|
||||
r.right - WD_IMGBTN_RIGHT + lowered, r.bottom - WD_IMGBTN_BOTTOM + lowered,
|
||||
HIT_GUI_HOUSE_LIST);
|
||||
/* grey out outdated houses */
|
||||
if (!this->IsHouseDisabled(house)) break;
|
||||
GfxFillRect(
|
||||
r.left + WD_BEVEL_LEFT, r.top + WD_BEVEL_TOP,
|
||||
r.right - WD_BEVEL_LEFT, r.bottom - WD_BEVEL_BOTTOM,
|
||||
PC_BLACK, FILLRECT_CHECKER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1635,14 +1728,103 @@ public:
|
||||
{
|
||||
switch (GB(widget, 0, 16)) {
|
||||
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);
|
||||
uint index = (uint)(pt.y - this->GetWidget<NWidgetBase>(widget)->pos_y) / this->GetLineHeight();
|
||||
if (index < this->house_list.NumHouseSets()) {
|
||||
this->SelectOtherHouse(index, -1, -1, -1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_HP_HOUSE_SELECT:
|
||||
this->SelectOtherHouse(this->house_set, GB(widget, 16, 16));
|
||||
case WID_HP_PREV_VARIANT:
|
||||
this->SelectOtherHouse(-1, -1, _cur_house.variant - 1, -1);
|
||||
break;
|
||||
|
||||
case WID_HP_NEXT_VARIANT:
|
||||
this->SelectOtherHouse(-1, -1, _cur_house.variant + 1, -1);
|
||||
break;
|
||||
|
||||
case WID_HP_HOUSE_SELECT:
|
||||
this->SelectOtherHouse(-1, GB(widget, 16, 16), -1, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnPlaceObject(Point pt, TileIndex tile)
|
||||
{
|
||||
DeleteWindowById(WC_SELECT_TOWN, 0);
|
||||
|
||||
TownList towns;
|
||||
CommandCost ret = ListTownsToJoinHouseTo(_cur_house.id, tile, &towns);
|
||||
if (ret.Failed()) {
|
||||
ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HOUSE_HERE, ret.GetErrorMessage(), WL_INFO);
|
||||
return;
|
||||
}
|
||||
|
||||
CommandContainer cmd = {
|
||||
tile,
|
||||
_cur_house.id, // p1 - house type and town index (town not yet set)
|
||||
InteractiveRandomRange(1 << 8), // p2 - 8 random bits for the house
|
||||
CMD_BUILD_HOUSE | CMD_MSG(STR_ERROR_CAN_T_BUILD_HOUSE_HERE),
|
||||
CcFoundTown,
|
||||
""
|
||||
};
|
||||
|
||||
/* Place the house right away if CTRL is not pressed. */
|
||||
if (!_ctrl_pressed) {
|
||||
SB(cmd.p1, 16, 16, towns[0]);
|
||||
DoCommandP(&cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the place is buildable. */
|
||||
ret = CheckFlatLandHouse(_cur_house.id, tile);
|
||||
if (ret.Failed()) {
|
||||
ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HOUSE_HERE, ret.GetErrorMessage(), WL_INFO);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Show the joiner window. */
|
||||
if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
|
||||
ShowSelectTownWindow(towns, cmd);
|
||||
}
|
||||
|
||||
virtual void OnPlaceObjectAbort()
|
||||
{
|
||||
this->SelectOtherHouse(-1, -1, -1, 0);
|
||||
this->tileselect_zone = HZB_END;
|
||||
this->tileselect_bad_land = false;
|
||||
}
|
||||
|
||||
virtual void OnTick()
|
||||
{
|
||||
if (this->IsObjectToPlaceSet() && (_thd.dirty & 4)) {
|
||||
_thd.dirty &= ~4;
|
||||
|
||||
HouseZonesBits prev_zone = this->tileselect_zone;
|
||||
bool prev_land = this->tileselect_bad_land;
|
||||
|
||||
this->tileselect_zone = HZB_END;
|
||||
this->tileselect_bad_land = false;
|
||||
if (_thd.drawstyle == HT_RECT) {
|
||||
TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
|
||||
if (tile < MapSize()) {
|
||||
/* find best town zone */
|
||||
const Town *t;
|
||||
FOR_ALL_TOWNS(t) {
|
||||
if (CheckHouseDistanceFromTown(t, tile, false).Failed()) continue;
|
||||
HouseZonesBits zone = GetTownRadiusGroup(t, tile);
|
||||
if (!IsInsideMM(this->tileselect_zone, zone, HZB_END)) this->tileselect_zone = zone;
|
||||
}
|
||||
/* check the snowline */
|
||||
if (_settings_game.game_creation.landscape == LT_ARCTIC) {
|
||||
HouseZones zone = HouseSpec::Get(_cur_house.id)->building_availability & (HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW);
|
||||
this->tileselect_bad_land = HasExactlyOneBit(zone) && ((GetTileMaxZ(tile) > HighestSnowLine()) != (zone == HZ_SUBARTC_ABOVE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prev_zone != this->tileselect_zone) this->SetWidgetDirty(WID_HP_HOUSE_ZONES);
|
||||
if (prev_land != this->tileselect_bad_land) this->SetWidgetDirty(WID_HP_HOUSE_LANDSCAPE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1667,9 +1849,30 @@ static const NWidgetPart _nested_house_picker_widgets[] = {
|
||||
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),
|
||||
/* HOUSE PICTURE AND PREV/NEXT BUTTONS */
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 1),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
|
||||
NWidget(NWID_SELECTION, COLOUR_DARK_GREEN, WID_HP_PREV_VARIANT_SEL),
|
||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_HP_PREV_VARIANT), SetDataTip(SPR_ARROW_LEFT, STR_NULL),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_PREVIEW), SetFill(0, 1), SetResize(0, 1), SetPadding(0, 8, 0, 8),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 1),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_SELECTION, COLOUR_DARK_GREEN, WID_HP_NEXT_VARIANT_SEL),
|
||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_HP_NEXT_VARIANT), SetDataTip(SPR_ARROW_RIGHT, STR_NULL),
|
||||
EndContainer(),
|
||||
NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
/* HOUSE LABEL */
|
||||
NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_HP_HOUSE_NAME), SetDataTip(STR_HOUSE_BUILD_HOUSE_NAME, STR_NULL), SetMinimalSize(120, 0), SetPadding(5, 0, 0, 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),
|
||||
@@ -1680,8 +1883,8 @@ static const NWidgetPart _nested_house_picker_widgets[] = {
|
||||
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),
|
||||
NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_HP_HOUSE_SELECT_MATRIX), SetPIP(0, 2, 0), SetPadding(5, 2, 2, 4), SetScrollbar(WID_HP_HOUSE_SELECT_SCROLL),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_HP_HOUSE_SELECT),
|
||||
SetDataTip(0x0, STR_HOUSE_BUILD_SELECT_HOUSE_TOOLTIP), SetScrollbar(WID_HP_HOUSE_SELECT_SCROLL),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
@@ -1713,11 +1916,12 @@ static WindowDesc _house_picker_desc(
|
||||
|
||||
/**
|
||||
* Show our house picker.
|
||||
* @param parent The toolbar window we're associated with.
|
||||
*/
|
||||
void ShowBuildHousePicker(Window *parent)
|
||||
void ShowBuildHousePicker()
|
||||
{
|
||||
new HousePickerWindow(&_house_picker_desc, parent);
|
||||
if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
|
||||
HousePickerWindow *w = AllocateWindowDescFront<HousePickerWindow>(&_house_picker_desc, 0, true);
|
||||
if (w != NULL) w->SelectOtherHouse(-1, -1, -1, 1); // push the button
|
||||
}
|
||||
|
||||
|
||||
@@ -1737,6 +1941,21 @@ struct SelectTownWindow : Window {
|
||||
this->FinishInitNested();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list i-th item string. Appropriate string parameters will be set.
|
||||
* @param i Index of the item.
|
||||
* @return The string.
|
||||
*/
|
||||
StringID GetTownString(uint i) const
|
||||
{
|
||||
SetDParam(0, this->towns[i]);
|
||||
if (CheckHouseDistanceFromTown(Town::Get(this->towns[i]), this->cmd.tile, false).Failed()) {
|
||||
return STR_SELECT_TOWN_LIST_TOWN_OUTSIDE;
|
||||
}
|
||||
SetDParam(1, GetTownRadiusGroup(Town::Get(this->towns[i]), this->cmd.tile) + 1);
|
||||
return STR_SELECT_TOWN_LIST_TOWN_ZONE;
|
||||
}
|
||||
|
||||
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
|
||||
{
|
||||
if (widget != WID_ST_PANEL) return;
|
||||
@@ -1744,8 +1963,7 @@ struct SelectTownWindow : Window {
|
||||
/* Determine the widest string */
|
||||
Dimension d = { 0, 0 };
|
||||
for (uint i = 0; i < this->towns.Length(); i++) {
|
||||
SetDParam(0, this->towns[i]);
|
||||
d = maxdim(d, GetStringBoundingBox(STR_SELECT_TOWN_LIST_ITEM));
|
||||
d = maxdim(d, GetStringBoundingBox(this->GetTownString(i)));
|
||||
}
|
||||
|
||||
resize->height = d.height;
|
||||
@@ -1762,8 +1980,7 @@ struct SelectTownWindow : Window {
|
||||
uint y = r.top + WD_FRAMERECT_TOP;
|
||||
uint end = min(this->vscroll->GetCount(), this->vscroll->GetPosition() + this->vscroll->GetCapacity());
|
||||
for (uint i = this->vscroll->GetPosition(); i < end; i++) {
|
||||
SetDParam(0, this->towns[i]);
|
||||
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SELECT_TOWN_LIST_ITEM);
|
||||
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, this->GetTownString(i));
|
||||
y += this->resize.step_height;
|
||||
}
|
||||
}
|
||||
@@ -1817,60 +2034,53 @@ static void ShowSelectTownWindow(const TownList &towns, const CommandContainer &
|
||||
new SelectTownWindow(&_select_town_desc, towns, cmd);
|
||||
}
|
||||
|
||||
/** Helper class for sorting a list of towns to join house to. */
|
||||
struct TownsToJoinHouseToListSorter {
|
||||
TileIndex tile; // Tile where the house is about to be placed.
|
||||
|
||||
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;
|
||||
bool operator () (const TownID &a, const TownID &b) const
|
||||
{
|
||||
uint dist_a, dist_b, inner_a, inner_b, outer_a, outer_b;
|
||||
HouseZonesBits zone_a = TryGetTownRadiusGroup(Town::Get(a), this->tile, &dist_a, &inner_a, &outer_a);
|
||||
HouseZonesBits zone_b = TryGetTownRadiusGroup(Town::Get(b), this->tile, &dist_b, &inner_b, &outer_b);
|
||||
|
||||
if (zone_a != zone_b) return zone_a != HZB_END && (zone_b == HZB_END || zone_a > zone_b);
|
||||
|
||||
if (zone_a == HZB_END) return dist_a - inner_a < dist_b - inner_b;
|
||||
|
||||
return (uint64)(dist_a - inner_a) * (uint64)(outer_b - inner_b) <
|
||||
(uint64)(dist_b - inner_b) * (uint64)(outer_a - inner_a);
|
||||
}
|
||||
};
|
||||
|
||||
DeleteWindowById(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;
|
||||
/**
|
||||
* Make a list of towns for which a house can be joined to.
|
||||
*
|
||||
* @param house Type of the house to join.
|
||||
* @param tile Tile where the house is about to be placed.
|
||||
* @param [out] towns Container where sorted towns will be stored.
|
||||
* @return Success or an error.
|
||||
*/
|
||||
static CommandCost ListTownsToJoinHouseTo(HouseID house, TileIndex tile, TownList *towns)
|
||||
{
|
||||
const bool deity = (_game_mode == GM_EDITOR);
|
||||
StringID error = STR_ERROR_MUST_FOUND_TOWN_FIRST;
|
||||
const Town *t;
|
||||
FOR_ALL_TOWNS(t) {
|
||||
HouseZonesBits town_zone = TryGetTownRadiusGroup(t, tile);
|
||||
if (HasBit(house_zones, town_zone)) {
|
||||
/* 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;
|
||||
best_zone = town_zone;
|
||||
towns.Clear();
|
||||
}
|
||||
*towns.Append() = t->index;
|
||||
CommandCost ret = CheckHouseDistanceFromTown(t, tile, deity);
|
||||
if (ret.Failed()) {
|
||||
if (error == STR_ERROR_MUST_FOUND_TOWN_FIRST) error = ret.GetErrorMessage();
|
||||
continue;
|
||||
}
|
||||
if (!deity && !HasBit(HouseSpec::Get(house)->building_availability, GetTownRadiusGroup(t, tile))) {
|
||||
error = STR_ERROR_BUILDING_NOT_ALLOWED_IN_THIS_TOWN_ZONE;
|
||||
continue;
|
||||
}
|
||||
*(towns->Append()) = t->index;
|
||||
}
|
||||
|
||||
if (towns.Length() == 0) {
|
||||
ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HOUSE_HERE, STR_ERROR_BUILDING_NOT_ALLOWED_IN_THIS_TOWN_ZONE, WL_INFO);
|
||||
return;
|
||||
}
|
||||
|
||||
CommandContainer cmd = {
|
||||
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),
|
||||
CcPlaySound1E,
|
||||
""
|
||||
};
|
||||
|
||||
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) DeleteWindowById(WC_BUILD_HOUSE, 0);
|
||||
ShowSelectTownWindow(towns, cmd);
|
||||
}
|
||||
if (towns->Length() == 0) return CommandCost(error);
|
||||
TownsToJoinHouseToListSorter compare = { tile };
|
||||
std::sort(towns->Begin(), towns->End(), compare);
|
||||
return CommandCost();
|
||||
}
|
||||
|
Reference in New Issue
Block a user