diff --git a/source.list b/source.list
index df35cdd26e..c9834dcf31 100644
--- a/source.list
+++ b/source.list
@@ -367,6 +367,7 @@ tilematrix_type.hpp
timetable.h
toolbar_gui.h
town.h
+town_gui.h
town_type.h
townname_func.h
townname_type.h
diff --git a/src/core/math_func.hpp b/src/core/math_func.hpp
index 2538d48ea7..df9142462b 100644
--- a/src/core/math_func.hpp
+++ b/src/core/math_func.hpp
@@ -346,33 +346,6 @@ static inline int RoundDivSU(int a, uint b)
}
}
-/**
- * Test if sqrt(a) <= sqrt(b) + sqrt(c)
- *
- * This function can tell you what's the relation between some of your values
- * even thought you know only squares of them. Useful when comparing euclidean
- * distances, it's easier to calculate them squared (#DistanceSquare) e.g.
- * having a squared town radius R and squared distance D, to tell if the distance
- * is further then N tiles beyond the town you may check if !SqrtCmp(D, R, N * N).
- *
- * @param a first value squared
- * @param b second value squared
- * @param c third value squared
- * @return sqrt(a) <= sqrt(b) + sqrt(c)
- *
- * @pre 4 * b * c <= UINT32_MAX
- */
-inline bool SqrtCmp(uint32 a, uint32 b, uint32 c)
-{
- assert(c == 0 || b <= UINT32_MAX / 4 / c);
-
- /* we can square the inequality twice to get rid of square roots
- * but some edge case must be checked first */
- if (a <= b + c) return true;
- uint32 d = a - (b + c);
- return d <= UINT16_MAX && d * d <= 4 * b * c;
-}
-
uint32 IntSqrt(uint32 num);
#endif /* MATH_FUNC_HPP */
diff --git a/src/economy_type.h b/src/economy_type.h
index 30d3cbff5f..7e7a572413 100644
--- a/src/economy_type.h
+++ b/src/economy_type.h
@@ -137,7 +137,6 @@ enum Price {
PR_INFRASTRUCTURE_WATER,
PR_INFRASTRUCTURE_STATION,
PR_INFRASTRUCTURE_AIRPORT,
- PR_BUILD_HOUSE,
PR_END,
INVALID_PRICE = 0xFF
diff --git a/src/gui.h b/src/gui.h
index 93fba824b2..39f1ea661e 100644
--- a/src/gui.h
+++ b/src/gui.h
@@ -65,7 +65,6 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
void ShowBuildIndustryWindow();
void ShowFoundTownWindow();
-void ShowBuildHousePicker();
void ShowMusicWindow();
#endif /* GUI_H */
diff --git a/src/house.h b/src/house.h
index 2679f303c3..17aee20c7f 100644
--- a/src/house.h
+++ b/src/house.h
@@ -31,9 +31,6 @@ static const HouseID NEW_HOUSE_OFFSET = 110; ///< Offset for new houses.
static const HouseID NUM_HOUSES = 512; ///< Total number of houses.
static const HouseID INVALID_HOUSE_ID = 0xFFFF;
-static const HouseVariant HOUSE_NO_VARIANT = 0; ///< No particular house variant.
-static const HouseVariant HOUSE_FIRST_VARIANT = 1; ///< First possible house variant.
-
/**
* There can only be as many classes as there are new houses, plus one for
* NO_CLASS, as the original houses don't have classes.
@@ -89,13 +86,11 @@ enum HouseZones { ///< Bit Value Meaning
DECLARE_ENUM_AS_BIT_SET(HouseZones)
enum HouseExtraFlags {
- NO_EXTRA_FLAG = 0,
- BUILDING_IS_HISTORICAL = 1U << 0, ///< this house will only appear during town generation in random games, thus the historical
- BUILDING_IS_PROTECTED = 1U << 1, ///< towns and AI will not remove this house, while human players will be able to
- SYNCHRONISED_CALLBACK_1B = 1U << 2, ///< synchronized callback 1B will be performed, on multi tile houses
- CALLBACK_1A_RANDOM_BITS = 1U << 3, ///< callback 1A needs random bits
- DISALLOW_BUILDING_BY_COMPANIES = 1U << 4, ///< disallow placing manually by companies (excludes scenario editor, game scripts)
- DISALLOW_BUILDING_MANUALLY = 1U << 5, ///< disallow placing manually
+ NO_EXTRA_FLAG = 0,
+ BUILDING_IS_HISTORICAL = 1U << 0, ///< this house will only appear during town generation in random games, thus the historical
+ BUILDING_IS_PROTECTED = 1U << 1, ///< towns and AI will not remove this house, while human players will be able to
+ SYNCHRONISED_CALLBACK_1B = 1U << 2, ///< synchronized callback 1B will be performed, on multi tile houses
+ CALLBACK_1A_RANDOM_BITS = 1U << 3, ///< callback 1A needs random bits
};
DECLARE_ENUM_AS_BIT_SET(HouseExtraFlags)
@@ -106,7 +101,6 @@ struct HouseSpec {
Year max_year; ///< last year it can be built
byte population; ///< population (Zero on other tiles in multi tile house.)
byte removal_cost; ///< cost multiplier for removing it
- uint16 construction_cost; ///< cost multiplier for building it
StringID building_name; ///< building name
uint16 remove_rating_decrease; ///< rating decrease if removed
byte mail_generation; ///< mail generation multiplier (tile based, as the acceptances below)
@@ -120,7 +114,6 @@ struct HouseSpec {
GRFFileProps grf_prop; ///< Properties related the the grf file
uint16 callback_mask; ///< Bitmask of house callbacks that have to be called
byte random_colour[4]; ///< 4 "random" colours
- byte num_variants; ///< total number of house variants, 0 - variants disabled
byte probability; ///< Relative probability of appearing (16 is the standard value)
HouseExtraFlags extra_flags; ///< some more flags
HouseClassID class_id; ///< defines the class this house has (not grf file based)
@@ -129,7 +122,6 @@ struct HouseSpec {
byte minimum_life; ///< The minimum number of years this house will survive before the town rebuilds it
uint32 watched_cargoes; ///< Cargo types watched for acceptance.
- Money GetConstructionCost() const;
Money GetRemovalCost() const;
static inline HouseSpec *Get(size_t house_id)
@@ -151,16 +143,9 @@ static inline HouseID GetTranslatedHouseID(HouseID hid)
return hs->grf_prop.override == INVALID_HOUSE_ID ? hid : hs->grf_prop.override;
}
-StringID GetHouseName(HouseID house_id, TileIndex tile, HouseVariant variant = HOUSE_NO_VARIANT);
-void DrawHouseImage(HouseID house_id, int left, int top, int right, int bottom, HouseImageType image_type, HouseVariant variant = HOUSE_NO_VARIANT);
-void AddProducedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &produced, HouseVariant variant = HOUSE_NO_VARIANT);
-void AddAcceptedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &acceptance, uint32 *always_accepted, HouseVariant variant = HOUSE_NO_VARIANT);
-HouseZones CurrentClimateHouseZones(int altitude = -1);
-
-CommandCost CheckHouseDistanceFromTown(const Town *t, TileIndex tile, bool allow_outside);
-CommandCost IsHouseTypeAllowed(HouseID house, HouseZones availability, bool allow_historical);
-CommandCost CheckFlatLandHouse(HouseID house, TileIndex tile);
-
-uint16 DefaultHouseCostBaseMultiplier(uint16 callback_mask, byte population, byte mail_generation, byte cargo_acceptance1, byte cargo_acceptance2, byte cargo_acceptance3, CargoID accepts_cargo1, CargoID accepts_cargo2, CargoID accepts_cargo3);
+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, uint32 *always_accepted = NULL);
#endif /* HOUSE_H */
diff --git a/src/house_type.h b/src/house_type.h
index 20326b4b86..9c9c41702c 100644
--- a/src/house_type.h
+++ b/src/house_type.h
@@ -14,15 +14,7 @@
typedef uint16 HouseID; ///< OpenTTD ID of house types.
typedef uint16 HouseClassID; ///< Classes of houses.
-typedef byte HouseVariant; ///< House variant.
struct HouseSpec;
-/** Visualization contexts of town houses. */
-enum HouseImageType {
- HIT_HOUSE_TILE = 0, ///< Real house that exists on the game map (certain house tile).
- HIT_GUI_HOUSE_PREVIEW = 1, ///< GUI preview of a house.
- HIT_GUI_HOUSE_LIST = 2, ///< Same as #HIT_GUI_HOUSE_PREVIEW but the house is being drawn in the GUI list of houses, not in the full house preview.
-};
-
#endif /* HOUSE_TYPE_H */
diff --git a/src/lang/english.txt b/src/lang/english.txt
index 2a0192a516..13a30831c8 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -359,6 +359,7 @@ STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Road con
STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant trees. Shift toggles building/showing cost estimate
STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Place sign
STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Place object. Shift toggles building/showing cost estimate
+STR_SCENEDIT_TOOLBAR_PLACE_HOUSE :{BLACK}Place house
############ range for SE file menu starts
STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Save scenario
@@ -404,7 +405,6 @@ STR_MAP_MENU_SIGN_LIST :Sign list
############ range for town menu starts
STR_TOWN_MENU_TOWN_DIRECTORY :Town directory
STR_TOWN_MENU_FOUND_TOWN :Found town
-STR_TOWN_MENU_FUND_HOUSE :Fund new house
############ range ends here
############ range for subsidies menu starts
@@ -1235,8 +1235,6 @@ STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Allow funding b
STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Allow companies to give money to towns for funding new houses
STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Allow funding local road reconstruction: {STRING2}
STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Allow companies to give money to towns for road re-construction to sabotage road-based services in the town
-STR_CONFIG_SETTING_ALLOW_PLACING_HOUSES :Allow placing houses in-game: {STRING2}
-STR_CONFIG_SETTING_ALLOW_PLACING_HOUSES_HELPTEXT :Allow placing houses manually also during gameplay, not just in scenario editor
STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Allow sending money to other companies: {STRING2}
STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Allow transfer of money between companies in multiplayer mode
STR_CONFIG_SETTING_FREIGHT_TRAINS :Weight multiplier for freight to simulate heavy trains: {STRING2}
@@ -2489,33 +2487,24 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Size: {G
STR_OBJECT_CLASS_LTHS :Lighthouses
STR_OBJECT_CLASS_TRNS :Transmitters
-#Town select window
-STR_SELECT_TOWN_CAPTION :{WHITE}Select town
-STR_SELECT_TOWN_LIST_TOWN_ZONE :{WHITE}{TOWN}{BLACK} (zone {NUM})
-STR_SELECT_TOWN_LIST_TOWN_OUTSIDE :{WHITE}{TOWN}{BLACK} (outside)
-
-# House construction window
-STR_HOUSE_BUILD_CAPTION :{WHITE}{STRING1}
-STR_HOUSE_BUILD_CAPTION_DEFAULT_TEXT :House Selection
+#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_GOOD :{GOLD}{NUM}
-STR_HOUSE_BUILD_HOUSE_ZONE_BAD :{GRAY}{NUM}
-STR_HOUSE_BUILD_HOUSE_ZONE_GOOD_HIGHLIGHTED :{WHITE}{NUM}
-STR_HOUSE_BUILD_HOUSE_ZONE_BAD_HIGHLIGHTED :{RED}{NUM}
+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_GOOD :{GOLD}only above snowline
-STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE_BAD :{RED}only above snowline
-STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE_GOOD :{GOLD}only below snowline
-STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE_BAD :{RED}only 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_YEAR_GOOD :{GOLD}{NUM}
-STR_HOUSE_BUILD_YEAR_BAD :{RED}{NUM}
+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}
@@ -2524,6 +2513,10 @@ 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}
+
# Tree planting window (last two for SE only)
STR_PLANT_TREE_CAPTION :{WHITE}Trees
STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type
@@ -4214,9 +4207,14 @@ STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Road wor
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_BUILDING_NOT_ALLOWED_IN_THIS_TOWN_ZONE :{WHITE}... not allowed in this town zone.
-STR_ERROR_ONLY_ONE_CHURCH_PER_TOWN :{WHITE}... only one church per town is allowed.
-STR_ERROR_ONLY_ONE_STADIUM_PER_TOWN :{WHITE}... only one stadium per town is allowed.
-STR_ERROR_TOO_FAR_FROM_TOWN :{WHITE}... too far from town.
+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.
+STR_ERROR_TOO_MANY_HOUSE_SETS :{WHITE}... too many house sets in the town
+STR_ERROR_TOO_MANY_HOUSE_TYPES :{WHITE}... too many house types in the town
+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_BUILDING_NOT_ALLOWED :{WHITE}... the building is not allowed.
# Industry related errors
STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... too many industries
diff --git a/src/misc.cpp b/src/misc.cpp
index 1702b6cd40..d9d506993f 100644
--- a/src/misc.cpp
+++ b/src/misc.cpp
@@ -92,7 +92,6 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
InitializeTrees();
InitializeIndustries();
InitializeObjects();
- InitializeHouses();
InitializeBuildingCounts();
InitializeNPF();
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index bb16df4ab4..b9c1bf89e3 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -2353,7 +2353,6 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt
housespec->grf_prop.local_id = hid + i;
housespec->grf_prop.subst_id = subs_id;
housespec->grf_prop.grffile = _cur.grffile;
- housespec->construction_cost = 0xFFFF;
housespec->random_colour[0] = 0x04; // those 4 random colours are the base colour
housespec->random_colour[1] = 0x08; // for all new houses
housespec->random_colour[2] = 0x0C; // they stand for red, blue, orange and green
@@ -2520,14 +2519,6 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt
housespec->max_year = buf->ReadWord();
break;
- case 0x23: // Build cost multiplier
- housespec->construction_cost = buf->ReadDWord();
- break;
-
- case 0x24:
- housespec->num_variants = buf->ReadByte();
- break;
-
default:
ret = CIR_UNKNOWN;
break;
@@ -8592,13 +8583,6 @@ static void FinaliseHouseArray()
* building_flags to zero here to make sure any house following
* this one in the pool is properly handled as 1x1 house. */
hs->building_flags = TILE_NO_FLAG;
- } else if (hs->enabled && (hs->building_flags && BUILDING_HAS_1_TILE)) {
- if (hs->construction_cost == 0xFFFF) {
- hs->construction_cost = DefaultHouseCostBaseMultiplier(
- hs->callback_mask, hs->population, hs->mail_generation,
- hs->cargo_acceptance[0], hs->cargo_acceptance[1], hs->cargo_acceptance[2],
- hs->accepts_cargo[0], hs->accepts_cargo[1], hs->accepts_cargo[2]);
- }
}
}
diff --git a/src/newgrf_callbacks.h b/src/newgrf_callbacks.h
index 549dcb4f31..2c30241f07 100644
--- a/src/newgrf_callbacks.h
+++ b/src/newgrf_callbacks.h
@@ -281,9 +281,6 @@ enum CallbackID {
/** Called to spawn visual effects for vehicles. */
CBID_VEHICLE_SPAWN_VISUAL_EFFECT = 0x160, // 15 bit callback
-
- /** Called to set house variant through animation control. */
- CBID_HOUSE_SETUP_VARIANT = 0x161, // 15 bit callback
};
/**
@@ -329,7 +326,6 @@ enum HouseCallbackMask {
CBM_HOUSE_DENY_DESTRUCTION = 10, ///< conditional protection
CBM_HOUSE_DRAW_FOUNDATIONS = 11, ///< decides if default foundations need to be drawn
CBM_HOUSE_AUTOSLOPE = 12, ///< decides allowance of autosloping
- CBM_HOUSE_SETUP_VARIANT = 13, ///< set house variant through animation control
};
/**
diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp
index 8f0ec3e455..2d7c666607 100644
--- a/src/newgrf_house.cpp
+++ b/src/newgrf_house.cpp
@@ -17,7 +17,6 @@
#include "newgrf_text.h"
#include "newgrf_town.h"
#include "newgrf_sound.h"
-#include "command_func.h"
#include "company_func.h"
#include "company_base.h"
#include "town.h"
@@ -26,9 +25,6 @@
#include "newgrf_cargo.h"
#include "station_base.h"
-#include
-#include
-
#include "safeguards.h"
#include "table/strings.h"
@@ -38,56 +34,17 @@ static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX];
HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, NUM_HOUSES, INVALID_HOUSE_ID);
-/** How a house is being placed. */
-enum TownExpansionBits {
- TEB_NONE = 0, ///< House is already placed or it's a GUI house, not placing currently.
- TEB_CREATING_TOWN = 1 << 0, ///< House is being placed while a town is being created.
- TEB_EXPANDING_TOWN = 1 << 1, ///< House is being placed while a town is expanding.
- TEB_PLACING_MANUALLY = 1 << 2, ///< House is being placed manually.
-};
-
-static std::vector _gui_house_cache;
-
-void InitializeHouses()
-{
- _gui_house_cache.clear();
-}
-
-/**
- * Get animation frame for a GUI house.
- * @param house House to query.
- * @param variant House variant to get the frame for.
- * @param image_type House image type.
- * @return Animation frame to be used when drawing the house.
- */
-static byte CacheGetGUIHouseAnimFrame(HouseID house, HouseVariant variant, HouseImageType image_type)
-{
- if (image_type == HIT_HOUSE_TILE) return 0;
-
- if (!HasBit(HouseSpec::Get(house)->callback_mask, CBM_HOUSE_SETUP_VARIANT)) return 0;
-
- uint32 key = house << 23 | variant << 15 | image_type << 13;
- std::vector::iterator pos = std::lower_bound(_gui_house_cache.begin(), _gui_house_cache.end(), key);
- if (pos != _gui_house_cache.end() && ((*pos) & ~0xFF) == key) return (byte)*pos;
-
- uint16 callback_result = GetHouseCallback(CBID_HOUSE_SETUP_VARIANT, 0, variant, house, NULL, INVALID_TILE, image_type, variant);
- byte frame = (callback_result < 0xFD) ? callback_result : 0;
- _gui_house_cache.insert(pos, key | frame);
- return frame;
-}
-
/**
* Constructor of a house scope resolver.
* @param ro Surrounding resolver.
* @param house_id House type being queried.
* @param tile %Tile containing the house.
* @param town %Town containing the house.
- * @param placing Whether the houe is being placed currently (house construction check or house variant setup).
* @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.
*/
-HouseScopeResolver::HouseScopeResolver(ResolverObject &ro, HouseID house_id, TileIndex tile, Town *town, bool placing,
+HouseScopeResolver::HouseScopeResolver(ResolverObject &ro, HouseID house_id, TileIndex tile, Town *town,
bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers)
: ScopeResolver(ro)
{
@@ -111,14 +68,14 @@ static const GRFFile *GetHouseSpecGrf(HouseID house_id)
}
/**
- * Construct a resolver for a house tile.
+ * Construct a resolver for a house.
* @param house_id House to query.
- * @param tile %Tile containing the house. #INVALID_TILE to query a GUI house rather then a certain house tile.
- * @param town %Town containing the house. \c NULL if querying a GUI house.
+ * @param tile %Tile containing the house. INVALID_TILE to query a house type rather then a certian house tile.
+ * @param town %Town containing the house.
* @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 (do not use for GUI houses).
+ * @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.
*/
@@ -127,35 +84,17 @@ HouseResolverObject::HouseResolverObject(HouseID house_id, TileIndex tile, Town
bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers)
: ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2)
{
- assert(not_yet_constructed ? IsValidTile(tile) : IsTileType(tile, MP_HOUSE));
+ assert((tile != INVALID_TILE) == (town != NULL));
+ assert(tile == INVALID_TILE || (not_yet_constructed ? IsValidTile(tile) : GetHouseType(tile) == house_id && Town::GetByTile(tile) == town));
- this->house_scope = new HouseScopeResolver(*this, house_id, tile, town, not_yet_constructed || callback == CBID_HOUSE_SETUP_VARIANT, not_yet_constructed, initial_random_bits, watched_cargo_triggers);
- this->town_scope = new TownScopeResolver(*this, town, not_yet_constructed); // Don't access StorePSA if house is not yet constructed.
- this->root_spritegroup = HouseSpec::Get(house_id)->grf_prop.spritegroup[0];
-}
+ this->house_scope = (tile != INVALID_TILE) ?
+ (ScopeResolver*)new HouseScopeResolver(*this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers) :
+ (ScopeResolver*)new FakeHouseScopeResolver(*this, house_id);
-/**
- * Construct a resolver for a GUI house.
- * @param house_id House to query.
- * @param variant House variant.
- * @param image_type House context.
- * @param callback Callback ID.
- * @param param1 First parameter (var 10) of the callback.
- * @param param2 Second parameter (var 18) of the callback.
- */
-HouseResolverObject::HouseResolverObject(HouseID house_id, HouseVariant variant, HouseImageType image_type,
- CallbackID callback, uint32 param1, uint32 param2)
- : ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2)
-{
- assert(image_type != HIT_HOUSE_TILE);
+ this->town_scope = (town != NULL) ?
+ (ScopeResolver*)new TownScopeResolver(*this, town, not_yet_constructed) : // Don't access StorePSA if house is not yet constructed.
+ (ScopeResolver*)new FakeTownScopeResolver(*this);
- byte anim_frame = 0;
- if (callback != CBID_HOUSE_SETUP_VARIANT) { // prevent endless recursion from CacheGetGUIHouseAnimFrame
- anim_frame = CacheGetGUIHouseAnimFrame(house_id, variant, image_type);
- }
-
- this->house_scope = new FakeHouseScopeResolver(*this, house_id, image_type, anim_frame);
- this->town_scope = new FakeTownScopeResolver(*this);
this->root_spritegroup = HouseSpec::Get(house_id)->grf_prop.spritegroup[0];
}
@@ -391,26 +330,6 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI
return 0;
}
-static uint32 GetHouseIDClassInfo(HouseID house, bool is_own_house)
-{
- const HouseSpec *hs = HouseSpec::Get(house);
- /* Information about the grf local classid if the house has a class */
- uint houseclass = 0;
- if (hs->class_id != HOUSE_NO_CLASS) {
- houseclass = (is_own_house ? 1 : 2) << 8;
- houseclass |= _class_mapping[hs->class_id].class_id;
- }
- /* old house type or grf-local houseid */
- uint local_houseid = 0;
- if (house < NEW_HOUSE_OFFSET) {
- local_houseid = house;
- } else {
- local_houseid = (is_own_house ? 1 : 2) << 8;
- local_houseid |= hs->grf_prop.local_id;
- }
- return houseclass << 16 | local_houseid;
-}
-
/**
* @note Used by the resolver to get values for feature 07 deterministic spritegroups.
*/
@@ -432,12 +351,8 @@ static uint32 GetHouseIDClassInfo(HouseID house, bool is_own_house)
/* Number of this type of building on the map. */
case 0x44: return GetNumHouses(this->house_id, this->town);
- /* Whether the town is being created or just expanded and whether the house is being placed manually. */
- case 0x45:
- if (!this->placing) return TEB_NONE;
- if (_current_company != OWNER_TOWN) return TEB_PLACING_MANUALLY;
- if (_generating_world) return TEB_CREATING_TOWN;
- return TEB_EXPANDING_TOWN;
+ /* Whether the town is being created or just expanded. */
+ case 0x45: return _generating_world ? 1 : 0;
/* Current animation frame. */
case 0x46: return IsTileType(this->tile, MP_HOUSE) ? GetAnimationFrame(this->tile) : 0;
@@ -502,8 +417,22 @@ static uint32 GetHouseIDClassInfo(HouseID house, bool is_own_house)
case 0x66: {
TileIndex testtile = GetNearbyTile(parameter, this->tile);
if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
- HouseID test_id = GetHouseType(testtile);
- return GetHouseIDClassInfo(test_id, GetHouseSpecGrf(test_id) == this->ro.grffile);
+ HouseSpec *hs = HouseSpec::Get(GetHouseType(testtile));
+ /* Information about the grf local classid if the house has a class */
+ uint houseclass = 0;
+ if (hs->class_id != HOUSE_NO_CLASS) {
+ houseclass = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8;
+ houseclass |= _class_mapping[hs->class_id].class_id;
+ }
+ /* old house type or grf-local houseid */
+ uint local_houseid = 0;
+ if (this->house_id < NEW_HOUSE_OFFSET) {
+ local_houseid = this->house_id;
+ } else {
+ local_houseid = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8;
+ local_houseid |= hs->grf_prop.local_id;
+ }
+ return houseclass << 16 | local_houseid;
}
/* GRFID of nearby house tile */
@@ -516,10 +445,6 @@ static uint32 GetHouseIDClassInfo(HouseID house, bool is_own_house)
* in case the newgrf was removed. */
return _house_mngr.GetGRFID(house_id);
}
-
- /* Visualization context of the house. */
- case 0x68:
- return HIT_HOUSE_TILE;
}
DEBUG(grf, 1, "Unhandled house variable 0x%X", variable);
@@ -542,19 +467,19 @@ static uint32 GetHouseIDClassInfo(HouseID house, bool is_own_house)
case 0x41: return 0;
/* Town zone */
- case 0x42: return FindFirstBit(HouseSpec::Get(this->house_id)->building_availability & HZ_ZONALL); // last available
+ case 0x42: return FIND_FIRST_BIT(HouseSpec::Get(this->house_id)->building_availability & HZ_ZONALL); // first available
/* Terrain type */
case 0x43: return _settings_game.game_creation.landscape == LT_ARCTIC && (HouseSpec::Get(house_id)->building_availability & (HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW)) == HZ_SUBARTC_ABOVE ? 4 : 0;
/* Number of this type of building on the map. */
- case 0x44: return 0x01010101;
+ case 0x44: return 0;
- /* Whether the town is being created or just expanded and whether the house is being placed manually. */
- case 0x45: return TEB_NONE;
+ /* Whether the town is being created or just expanded. */
+ case 0x45: return 0;
/* Current animation frame. */
- case 0x46: return this->anim_frame;
+ case 0x46: return 0;
/* Position of the house */
case 0x47: return 0xFFFFFFFF;
@@ -563,13 +488,7 @@ static uint32 GetHouseIDClassInfo(HouseID house, bool is_own_house)
case 0x60: return 0;
/* Building counts for new houses with id = parameter. */
- case 0x61: {
- HouseID test_north = _house_mngr.GetID(parameter, this->ro.grffile->grfid);
- GetHouseNorthPart(test_north);
- HouseID cur_north = this->house_id;
- GetHouseNorthPart(cur_north);
- return test_north == cur_north ? 1 : 0;
- }
+ case 0x61: return 0;
/* Land info for nearby tiles. */
case 0x62: return 0;
@@ -584,20 +503,10 @@ static uint32 GetHouseIDClassInfo(HouseID house, bool is_own_house)
case 0x65: return 0;
/* Class and ID of nearby house tile */
- case 0x66: {
- HouseID nearby_house = this->GetHouseNearbyPart(parameter);
- if (nearby_house == INVALID_HOUSE_ID) return 0xFFFFFFFF;
- return GetHouseIDClassInfo(nearby_house, true);
- }
+ case 0x66: return 0xFFFFFFFF;
/* GRFID of nearby house tile */
- case 0x67:
- if (this->GetHouseNearbyPart(parameter) == INVALID_HOUSE_ID) return 0xFFFFFFFF;
- return this->ro.grffile->grfid;
-
- /* Visualization context of the house. */
- case 0x68:
- return this->image_type;
+ case 0x67: return 0xFFFFFFFF;
}
DEBUG(grf, 1, "Unhandled house variable 0x%X", variable);
@@ -606,66 +515,27 @@ static uint32 GetHouseIDClassInfo(HouseID house, bool is_own_house)
return UINT_MAX;
}
-HouseID FakeHouseScopeResolver::GetHouseNearbyPart(byte offset) const
+uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile,
+ bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers)
{
- if (offset == 0) return this->house_id;
-
- int8 x = GB(offset, 0, 4);
- int8 y = GB(offset, 4, 4);
- if (x >= 8) x -= 16;
- if (y >= 8) y -= 16;
-
- HouseID house = this->house_id;
- TileIndexDiffC diff = GetHouseNorthPartDiffC(house); // modifies 'house'!
- x -= diff.x;
- y -= diff.y;
- if (!IsInsideBS(x, 0, 2) || !IsInsideBS(y, 0, 2)) return INVALID_HOUSE_ID;
-
- BuildingFlags flags = HouseSpec::Get(house)->building_flags;
- if (x > 0 && !(flags & BUILDING_2_TILES_X)) return INVALID_HOUSE_ID;
- if (y > 0 && !(flags & BUILDING_2_TILES_Y)) return INVALID_HOUSE_ID;
-
- house += x + y;
- if (flags & TILE_SIZE_2x2) house += y;
- return house;
-}
-
-/**
- * Perform a house callback.
- *
- * Callback can be done for a certain house tile or for a GUI house.
- *
- * @param callback The callback to perform.
- * @param param1 The first parameter.
- * @param param2 The second parameter.
- * @param house_id The house to do the callback for.
- * @param town The town the house is located in, \c NULL to query a town-less house (GUI houses).
- * @param tile The tile associated with the callback, #INVALID_TILE when querying a tile-less house (GUI houses).
- * @param image_type House context.
- * @param variant House variant (GUI houses only)
- * @return The callback result.
- */
-uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, HouseImageType image_type, HouseVariant variant)
-{
- return (image_type == HIT_HOUSE_TILE) ?
- HouseResolverObject(house_id, tile, town, callback, param1, param2).ResolveCallback() :
- HouseResolverObject(house_id, variant, image_type, callback, param1, param2).ResolveCallback();
+ HouseResolverObject object(house_id, tile, town, callback, param1, param2,
+ not_yet_constructed, initial_random_bits, watched_cargo_triggers);
+ return object.ResolveCallback();
}
/**
* Get the name of a house.
- * @param house_id House type.
- * @param tile Tile where the house is located. #INVALID_TILE to get general name (GUI houses).
- * @param variant GUI house variant, only when \c tile is #INVALID_TILE.
+ * @param house House type.
+ * @param tile Tile where the house is located. INVALID_TILE to get the general name of houses of the given type.
* @return Name of the house.
*/
-StringID GetHouseName(HouseID house_id, TileIndex tile, HouseVariant variant)
+StringID GetHouseName(HouseID house_id, TileIndex tile)
{
const HouseSpec *hs = HouseSpec::Get(house_id);
+ bool house_completed = (tile == INVALID_TILE) || IsHouseCompleted(tile);
+ Town *t = (tile == INVALID_TILE) ? NULL : Town::GetByTile(tile);
- uint16 callback_res = (tile != INVALID_TILE) ?
- GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, IsHouseCompleted(tile) ? 1 : 0, 0, house_id, Town::GetByTile(tile), tile, HIT_HOUSE_TILE) :
- GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, 0, 0, house_id, NULL, INVALID_TILE, HIT_GUI_HOUSE_PREVIEW, variant);
+ uint16 callback_res = GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, house_completed ? 1 : 0, 0, house_id, t, tile);
if (callback_res != CALLBACK_FAILED && callback_res != 0x400) {
if (callback_res > 0x400) {
ErrorUnknownCallbackResult(hs->grf_prop.grffile->grfid, CBID_HOUSE_CUSTOM_NAME, callback_res);
@@ -678,21 +548,12 @@ StringID GetHouseName(HouseID house_id, TileIndex tile, HouseVariant variant)
return hs->building_name;
}
-/**
- * Get colour palette to be used to draw a house.
- *
- * @param house_id Type of the house.
- * @param image_type Context in which the house is being drawn.
- * @param tile Tile where the house is located. #INVALID_TILE when drawing houses in GUI.
- * @param variant GUI house variant, only when \c tile is #INVALID_TILE.
- * @return The palette.
- */
-static PaletteID GetHouseColour(HouseID house_id, HouseImageType image_type, TileIndex tile = INVALID_TILE, HouseVariant variant = HOUSE_NO_VARIANT)
+static inline PaletteID GetHouseColour(HouseID house_id, TileIndex tile = INVALID_TILE)
{
const HouseSpec *hs = HouseSpec::Get(house_id);
if (HasBit(hs->callback_mask, CBM_HOUSE_COLOUR)) {
Town *t = (tile != INVALID_TILE) ? Town::GetByTile(tile) : NULL;
- uint16 callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, t, tile, image_type, variant);
+ uint16 callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, t, tile);
if (callback != CALLBACK_FAILED) {
/* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
return HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
@@ -705,7 +566,7 @@ static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *grou
{
const DrawTileSprites *dts = group->ProcessRegisters(&stage);
- PaletteID palette = GetHouseColour(house_id, HIT_HOUSE_TILE, ti->tile);
+ PaletteID palette = GetHouseColour(house_id, ti->tile);
SpriteID image = dts->ground.sprite;
PaletteID pal = dts->ground.pal;
@@ -720,12 +581,12 @@ 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, HouseVariant variant, HouseImageType image_type, bool ground)
+static void DrawTileLayoutInGUI(int x, int y, const TileLayoutSpriteGroup *group, HouseID house_id, bool ground)
{
byte stage = TOWN_HOUSE_COMPLETED;
const DrawTileSprites *dts = group->ProcessRegisters(&stage);
- PaletteID palette = GetHouseColour(house_id, image_type, INVALID_TILE, variant);
+ PaletteID palette = GetHouseColour(house_id);
if (ground) {
PalSpriteID image = dts->ground;
@@ -766,20 +627,19 @@ void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
}
}
-void DrawNewHouseTileInGUI(int x, int y, HouseID house_id, HouseVariant variant, HouseImageType image_type, bool ground)
+void DrawNewHouseTileInGUI(int x, int y, HouseID house_id, bool ground)
{
- HouseResolverObject object(house_id, variant, image_type);
+ HouseResolverObject object(house_id);
const SpriteGroup *group = object.Resolve();
if (group != NULL && group->type == SGT_TILELAYOUT) {
- DrawTileLayoutInGUI(x, y, (const TileLayoutSpriteGroup*)group, house_id, variant, image_type, ground);
+ DrawTileLayoutInGUI(x, y, (const TileLayoutSpriteGroup*)group, house_id, ground);
}
}
/* Simple wrapper for GetHouseCallback to keep the animation unified. */
uint16 GetSimpleHouseCallback(CallbackID callback, uint32 param1, uint32 param2, const HouseSpec *spec, Town *town, TileIndex tile, uint32 extra_data)
{
- HouseResolverObject object(spec - HouseSpec::Get(0), tile, town, callback, param1, param2, false, 0, extra_data);
- return object.ResolveCallback();
+ return GetHouseCallback(callback, param1, param2, spec - HouseSpec::Get(0), town, tile, false, 0, extra_data);
}
/** Helper class for animation control. */
@@ -799,15 +659,6 @@ void AnimateNewHouseTile(TileIndex tile)
HouseAnimationBase::AnimateTile(hs, Town::GetByTile(tile), tile, HasBit(hs->extra_flags, CALLBACK_1A_RANDOM_BITS));
}
-void AnimateNewHouseSetupVariant(TileIndex tile, byte variant)
-{
- const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
-
- if (HasBit(hs->callback_mask, CBM_HOUSE_SETUP_VARIANT)) {
- HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_SETUP_VARIANT, hs, Town::GetByTile(tile), tile, 0, variant);
- }
-}
-
void AnimateNewHouseConstruction(TileIndex tile)
{
const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
@@ -820,29 +671,21 @@ void AnimateNewHouseConstruction(TileIndex tile)
/**
* Check if GRF allows a given house to be constructed (callback 17)
* @param house_id house type
- * @param variant house variant
* @param tile tile where the house is about to be placed
* @param t town in which we are building
* @param random_bits feature random bits for the house
* @return false if callback 17 disallows construction, true in other cases
*/
-CommandCost HouseAllowsConstruction(HouseID house_id, HouseVariant variant, TileIndex tile, Town *t, byte random_bits)
+bool HouseAllowsConstruction(HouseID house_id, TileIndex tile, Town *t, byte random_bits)
{
const HouseSpec *hs = HouseSpec::Get(house_id);
- if (variant > hs->num_variants) return CMD_ERROR;
-
- if (!HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) return CommandCost();
-
- HouseResolverObject object(house_id, tile, t, CBID_HOUSE_ALLOW_CONSTRUCTION, 0, variant, true, random_bits);
- uint16 callback_res = object.ResolveCallback();
- if (callback_res == CALLBACK_FAILED) return CommandCost();
-
- if (hs->grf_prop.grffile->grf_version < 9) {
- if (Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_ALLOW_CONSTRUCTION, callback_res)) return CommandCost();
- return CommandCost(STR_ERROR_SITE_UNSUITABLE);
+ if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
+ uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house_id, t, tile, true, random_bits);
+ if (callback_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_ALLOW_CONSTRUCTION, callback_res)) {
+ return false;
+ }
}
-
- return GetErrorMessageFromLocationCallbackResult(callback_res, hs->grf_prop.grffile, STR_ERROR_SITE_UNSUITABLE);
+ return true;
}
bool CanDeleteHouse(TileIndex tile)
diff --git a/src/newgrf_house.h b/src/newgrf_house.h
index 1b3fa12687..a1bf0d79ca 100644
--- a/src/newgrf_house.h
+++ b/src/newgrf_house.h
@@ -14,7 +14,7 @@
#include "newgrf_callbacks.h"
#include "tile_cmd.h"
-#include "house.h"
+#include "house_type.h"
#include "newgrf_spritegroup.h"
#include "newgrf_town.h"
@@ -23,12 +23,11 @@ struct HouseScopeResolver : public ScopeResolver {
HouseID house_id; ///< Type of house being queried.
TileIndex tile; ///< Tile of this house.
Town *town; ///< Town of this house.
- bool placing; ///< True if the house is being placed currently.
bool not_yet_constructed; ///< True for construction check.
uint16 initial_random_bits; ///< Random bits during construction checks.
uint32 watched_cargo_triggers; ///< Cargo types that triggered the watched cargo callback.
- HouseScopeResolver(ResolverObject &ro, HouseID house_id, TileIndex tile, Town *town, bool placing,
+ HouseScopeResolver(ResolverObject &ro, HouseID house_id, TileIndex tile, Town *town,
bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers);
/* virtual */ uint32 GetRandomBits() const;
@@ -50,17 +49,12 @@ struct HouseScopeResolver : public ScopeResolver {
*/
struct FakeHouseScopeResolver : public ScopeResolver {
HouseID house_id; ///< Type of house being queried.
- HouseImageType image_type; ///< Context.
- byte anim_frame; ///< House animation frame.
- FakeHouseScopeResolver(ResolverObject &ro, HouseID house_id, HouseImageType image_type, byte anim_frame)
- : ScopeResolver(ro), house_id(house_id), image_type(image_type), anim_frame(anim_frame)
+ FakeHouseScopeResolver(ResolverObject &ro, HouseID house_id)
+ : ScopeResolver(ro), house_id(house_id)
{ }
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
-
-private:
- HouseID GetHouseNearbyPart(byte offset) const;
};
/** Resolver object to be used for houses (feature 07 spritegroups). */
@@ -68,13 +62,10 @@ struct HouseResolverObject : public ResolverObject {
ScopeResolver *house_scope;
ScopeResolver *town_scope;
- HouseResolverObject(HouseID house_id, TileIndex tile, Town *town,
+ HouseResolverObject(HouseID house_id, TileIndex tile = INVALID_TILE, Town *town = NULL,
CallbackID callback = CBID_NO_CALLBACK, uint32 param1 = 0, uint32 param2 = 0,
bool not_yet_constructed = false, uint8 initial_random_bits = 0, uint32 watched_cargo_triggers = 0);
- HouseResolverObject(HouseID house_id, HouseVariant variant, HouseImageType image_type = HIT_GUI_HOUSE_PREVIEW,
- CallbackID callback = CBID_NO_CALLBACK, uint32 param1 = 0, uint32 param2 = 0);
-
/* virtual */ ~HouseResolverObject();
/* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0)
@@ -107,21 +98,20 @@ struct HouseClassMapping {
HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid);
-void InitializeHouses();
-
void InitializeBuildingCounts();
void IncreaseBuildingCount(Town *t, HouseID house_id);
void DecreaseBuildingCount(Town *t, HouseID house_id);
void DrawNewHouseTile(TileInfo *ti, HouseID house_id);
-void DrawNewHouseTileInGUI(int x, int y, HouseID house_id, HouseVariant variant, HouseImageType image_type, bool ground);
+void DrawNewHouseTileInGUI(int x, int y, HouseID house_id, bool ground);
void AnimateNewHouseTile(TileIndex tile);
void AnimateNewHouseConstruction(TileIndex tile);
-void AnimateNewHouseSetupVariant(TileIndex tile, HouseVariant variant);
-uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, HouseImageType image_type = HIT_HOUSE_TILE, HouseVariant variant = HOUSE_NO_VARIANT);
+uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town = NULL, TileIndex tile = INVALID_TILE,
+ bool not_yet_constructed = false, uint8 initial_random_bits = 0, uint32 watched_cargo_triggers = 0);
void WatchedCargoCallback(TileIndex tile, uint32 trigger_cargoes);
-CommandCost HouseAllowsConstruction(HouseID house_id, HouseVariant variant, TileIndex tile, Town *t, byte random_bits);
+
+bool HouseAllowsConstruction(HouseID house_id, TileIndex tile, Town *t, byte random_bits);
bool CanDeleteHouse(TileIndex tile);
bool NewHouseTileLoop(TileIndex tile);
diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq
index 566337c351..ff23f77c78 100644
--- a/src/script/api/game/game_window.hpp.sq
+++ b/src/script/api/game/game_window.hpp.sq
@@ -1141,6 +1141,7 @@ void SQGSWindow_Register(Squirrel *engine)
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_ROCKS, "WID_ETT_PLACE_ROCKS");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_DESERT, "WID_ETT_PLACE_DESERT");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_OBJECT, "WID_ETT_PLACE_OBJECT");
+ SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_HOUSE, "WID_ETT_PLACE_HOUSE");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_END, "WID_ETT_BUTTONS_END");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_INCREASE_SIZE, "WID_ETT_INCREASE_SIZE");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DECREASE_SIZE, "WID_ETT_DECREASE_SIZE");
@@ -1251,9 +1252,6 @@ void SQGSWindow_Register(Squirrel *engine)
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID2, "WID_TF_LAYOUT_GRID2");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID3, "WID_TF_LAYOUT_GRID3");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_RANDOM, "WID_TF_LAYOUT_RANDOM");
- SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ST_CAPTION, "WID_ST_CAPTION");
- SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ST_PANEL, "WID_ST_PANEL");
- SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ST_SCROLLBAR, "WID_ST_SCROLLBAR");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_CAPTION, "WID_HP_CAPTION");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_MAIN_PANEL_SEL, "WID_HP_MAIN_PANEL_SEL");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_SETS_SEL, "WID_HP_HOUSE_SETS_SEL");
@@ -1262,10 +1260,6 @@ void SQGSWindow_Register(Squirrel *engine)
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_SELECT_SCROLL, "WID_HP_HOUSE_SELECT_SCROLL");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_SELECT, "WID_HP_HOUSE_SELECT");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_PREVIEW, "WID_HP_HOUSE_PREVIEW");
- SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_PREV_VARIANT_SEL, "WID_HP_PREV_VARIANT_SEL");
- SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_PREV_VARIANT, "WID_HP_PREV_VARIANT");
- SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_NEXT_VARIANT_SEL, "WID_HP_NEXT_VARIANT_SEL");
- SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_NEXT_VARIANT, "WID_HP_NEXT_VARIANT");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_NAME, "WID_HP_HOUSE_NAME");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HISTORICAL_BUILDING, "WID_HP_HISTORICAL_BUILDING");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_POPULATION, "WID_HP_HOUSE_POPULATION");
@@ -1275,6 +1269,9 @@ void SQGSWindow_Register(Squirrel *engine)
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_YEARS, "WID_HP_HOUSE_YEARS");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_ACCEPTANCE, "WID_HP_HOUSE_ACCEPTANCE");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_SUPPLY, "WID_HP_HOUSE_SUPPLY");
+ SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ST_CAPTION, "WID_ST_CAPTION");
+ SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ST_PANEL, "WID_ST_PANEL");
+ SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ST_SCROLLBAR, "WID_ST_SCROLLBAR");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BEGIN, "WID_TT_BEGIN");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SIGNS, "WID_TT_SIGNS");
SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_TREES, "WID_TT_TREES");
diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp
index d79b64dc06..9b41adf605 100644
--- a/src/script/api/script_window.hpp
+++ b/src/script/api/script_window.hpp
@@ -2342,6 +2342,7 @@ public:
WID_ETT_PLACE_ROCKS = ::WID_ETT_PLACE_ROCKS, ///< Place rocks button.
WID_ETT_PLACE_DESERT = ::WID_ETT_PLACE_DESERT, ///< Place desert button (in tropical climate).
WID_ETT_PLACE_OBJECT = ::WID_ETT_PLACE_OBJECT, ///< Place transmitter button.
+ WID_ETT_PLACE_HOUSE = ::WID_ETT_PLACE_HOUSE, ///< Place house button.
WID_ETT_BUTTONS_END = ::WID_ETT_BUTTONS_END, ///< End of pushable buttons.
WID_ETT_INCREASE_SIZE = ::WID_ETT_INCREASE_SIZE, ///< Upwards arrow button to increase terraforming size.
WID_ETT_DECREASE_SIZE = ::WID_ETT_DECREASE_SIZE, ///< Downwards arrow button to decrease terraforming size.
@@ -2486,13 +2487,6 @@ public:
WID_TF_LAYOUT_RANDOM = ::WID_TF_LAYOUT_RANDOM, ///< Selection for a randomly chosen town layout.
};
- /** Widgets of the #SelectTownWindow class. */
- enum SelectTownWidgets {
- WID_ST_CAPTION = ::WID_ST_CAPTION, ///< Caption of the window.
- WID_ST_PANEL = ::WID_ST_PANEL, ///< Main panel.
- WID_ST_SCROLLBAR = ::WID_ST_SCROLLBAR, ///< Scrollbar of the panel.
- };
-
/** Widgets of the #HousePickerWindow class. */
enum HousePickerWidgets {
WID_HP_CAPTION = ::WID_HP_CAPTION,
@@ -2503,10 +2497,6 @@ public:
WID_HP_HOUSE_SELECT_SCROLL = ::WID_HP_HOUSE_SELECT_SCROLL, ///< Scrollbar associated with the house matrix.
WID_HP_HOUSE_SELECT = ::WID_HP_HOUSE_SELECT, ///< Panels with house images in the house matrix.
WID_HP_HOUSE_PREVIEW = ::WID_HP_HOUSE_PREVIEW, ///< House preview panel.
- WID_HP_PREV_VARIANT_SEL = ::WID_HP_PREV_VARIANT_SEL, ///< Selection widget to show/hide the prev variant buttons.
- WID_HP_PREV_VARIANT = ::WID_HP_PREV_VARIANT, ///< Prev variant button.
- WID_HP_NEXT_VARIANT_SEL = ::WID_HP_NEXT_VARIANT_SEL, ///< Selection widget to show/hide the next variant buttons.
- WID_HP_NEXT_VARIANT = ::WID_HP_NEXT_VARIANT, ///< Next variant button.
WID_HP_HOUSE_NAME = ::WID_HP_HOUSE_NAME, ///< House name display.
WID_HP_HISTORICAL_BUILDING = ::WID_HP_HISTORICAL_BUILDING, ///< "Historical building" label.
WID_HP_HOUSE_POPULATION = ::WID_HP_HOUSE_POPULATION, ///< House population display.
@@ -2518,6 +2508,13 @@ public:
WID_HP_HOUSE_SUPPLY = ::WID_HP_HOUSE_SUPPLY, ///< Cargo supplied.
};
+ /** Widgets of the #SelectTownWindow class. */
+ enum SelectTownWidgets {
+ WID_ST_CAPTION = ::WID_ST_CAPTION, ///< Caption of the window.
+ WID_ST_PANEL = ::WID_ST_PANEL, ///< Main panel.
+ WID_ST_SCROLLBAR = ::WID_ST_SCROLLBAR, ///< Scrollbar of the panel.
+ };
+
/* automatically generated from ../../widgets/transparency_widget.h */
/** Widgets of the #TransparenciesWindow class. */
enum TransparencyToolbarWidgets {
diff --git a/src/script/api/template/template_window.hpp.sq b/src/script/api/template/template_window.hpp.sq
index 76371b605b..445e90fe4e 100644
--- a/src/script/api/template/template_window.hpp.sq
+++ b/src/script/api/template/template_window.hpp.sq
@@ -233,10 +233,10 @@ namespace SQConvert {
template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> inline ScriptWindow::TownFoundingWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownFoundingWidgets)tmp; }
template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownFoundingWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
- template <> inline ScriptWindow::SelectTownWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectTownWidgets)tmp; }
- template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectTownWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> inline ScriptWindow::HousePickerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::HousePickerWidgets)tmp; }
template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::HousePickerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
+ template <> inline ScriptWindow::SelectTownWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectTownWidgets)tmp; }
+ template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectTownWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> inline ScriptWindow::TransparencyToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TransparencyToolbarWidgets)tmp; }
template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TransparencyToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
template <> inline ScriptWindow::BuildTreesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildTreesWidgets)tmp; }
diff --git a/src/settings.cpp b/src/settings.cpp
index 8f4baa5fd1..e6754bb905 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -1057,14 +1057,6 @@ static bool TownFoundingChanged(int32 p1)
return true;
}
-static bool AllowPlacingHousesChanged(int32 p1)
-{
- if (_game_mode != GM_EDITOR && !_settings_game.economy.allow_placing_houses) {
- DeleteWindowById(WC_BUILD_HOUSE, 0);
- }
- return true;
-}
-
static bool InvalidateVehTimetableWindow(int32 p1)
{
InvalidateWindowClassesData(WC_VEHICLE_TIMETABLE, VIWD_MODIFY_ORDERS);
diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp
index 9dc562fb70..0652d1bd81 100644
--- a/src/settings_gui.cpp
+++ b/src/settings_gui.cpp
@@ -1695,7 +1695,6 @@ static SettingsContainer &GetSettingsTree()
towns->Add(new SettingEntry("economy.allow_town_roads"));
towns->Add(new SettingEntry("economy.allow_town_level_crossings"));
towns->Add(new SettingEntry("economy.found_town"));
- towns->Add(new SettingEntry("economy.allow_placing_houses"));
}
SettingsPage *industries = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES));
diff --git a/src/settings_type.h b/src/settings_type.h
index 729129765c..41366a7719 100644
--- a/src/settings_type.h
+++ b/src/settings_type.h
@@ -487,7 +487,6 @@ struct EconomySettings {
bool station_noise_level; ///< build new airports when the town noise level is still within accepted limits
uint16 town_noise_population[3]; ///< population to base decision on noise evaluation (@see town_council_tolerance)
bool allow_town_level_crossings; ///< towns are allowed to build level crossings
- bool allow_placing_houses; ///< whether to allow placing houses manually also during gameplay, not only in scenario editor
bool infrastructure_maintenance; ///< enable monthly maintenance fee for owner infrastructure
};
diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h
index a332037c2f..b7d0c92024 100644
--- a/src/table/newgrf_debug_data.h
+++ b/src/table/newgrf_debug_data.h
@@ -159,7 +159,6 @@ static const NIFeature _nif_station = {
#define NICH(cb_id, bit) NIC(cb_id, HouseSpec, callback_mask, bit)
static const NICallback _nic_house[] = {
NICH(CBID_HOUSE_ALLOW_CONSTRUCTION, CBM_HOUSE_ALLOW_CONSTRUCTION),
- NICH(CBID_HOUSE_SETUP_VARIANT, CBM_HOUSE_SETUP_VARIANT),
NICH(CBID_HOUSE_ANIMATION_NEXT_FRAME, CBM_HOUSE_ANIMATION_NEXT_FRAME),
NICH(CBID_HOUSE_ANIMATION_START_STOP, CBM_HOUSE_ANIMATION_START_STOP),
NICH(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE),
diff --git a/src/table/pricebase.h b/src/table/pricebase.h
index 45d692e8f8..9dc2ee2ba7 100644
--- a/src/table/pricebase.h
+++ b/src/table/pricebase.h
@@ -81,6 +81,5 @@ extern const PriceBaseSpec _price_base_specs[] = {
{ 8, PCAT_RUNNING, GSF_END, PR_BUILD_CANAL }, ///< PR_INFRASTRUCTURE_WATER
{ 100, PCAT_RUNNING, GSF_END, PR_STATION_VALUE }, ///< PR_INFRASTRUCTURE_STATION
{ 5000, PCAT_RUNNING, GSF_END, PR_BUILD_STATION_AIRPORT}, ///< PR_INFRASTRUCTURE_AIRPORT
- {1000000, PCAT_CONSTRUCTION, GSF_END, PR_BUILD_INDUSTRY }, ///< PR_BUILD_HOUSE
};
assert_compile(lengthof(_price_base_specs) == PR_END);
diff --git a/src/table/settings.ini b/src/table/settings.ini
index 42501b27e0..f314f21e92 100644
--- a/src/table/settings.ini
+++ b/src/table/settings.ini
@@ -25,7 +25,6 @@ static bool TrainSlopeSteepnessChanged(int32 p1);
static bool RoadVehSlopeSteepnessChanged(int32 p1);
static bool DragSignalsDensityChanged(int32);
static bool TownFoundingChanged(int32 p1);
-static bool AllowPlacingHousesChanged(int32 p1);
static bool DifficultyNoiseChange(int32 i);
static bool MaxNoAIsChange(int32 i);
static bool CheckRoadSide(int p1);
@@ -618,17 +617,6 @@ def = true
str = STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS
strhelp = STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT
-; TODO: add this setting to savegames
-[SDT_BOOL]
-base = GameSettings
-var = economy.allow_placing_houses
-flags = SLF_NOT_IN_SAVE
-def = false
-str = STR_CONFIG_SETTING_ALLOW_PLACING_HOUSES
-strhelp = STR_CONFIG_SETTING_ALLOW_PLACING_HOUSES_HELPTEXT
-proc = AllowPlacingHousesChanged
-cat = SC_BASIC
-
; link graph
[SDT_VAR]
diff --git a/src/table/town_land.h b/src/table/town_land.h
index 4e524ec0a0..e4098334ac 100644
--- a/src/table/town_land.h
+++ b/src/table/town_land.h
@@ -1812,8 +1812,8 @@ assert_compile(lengthof(_town_draw_tile_data) == (NEW_HOUSE_OFFSET) * 4 * 4);
* @see HouseSpec
*/
#define MS(mnd, mxd, p, rc, bn, rr, mg, ca1, ca2, ca3, bf, ba, cg1, cg2, cg3) \
- {mnd, mxd, p, rc, DefaultHouseCostBaseMultiplier(0, p, mg, ca1, ca2, ca3, cg1, cg2, cg3), bn, rr, mg, {ca1, ca2, ca3}, {cg1, cg2, cg3}, bf, ba, true, \
- GRFFileProps(INVALID_HOUSE_ID), 0, {0, 0, 0, 0}, 0, 16, NO_EXTRA_FLAG, HOUSE_NO_CLASS, {0, 2, 0, 0}, 0, 0, 0}
+ {mnd, mxd, p, rc, bn, rr, mg, {ca1, ca2, ca3}, {cg1, cg2, cg3}, bf, ba, true, \
+ GRFFileProps(INVALID_HOUSE_ID), 0, {0, 0, 0, 0}, 16, NO_EXTRA_FLAG, HOUSE_NO_CLASS, {0, 2, 0, 0}, 0, 0, 0}
/** House specifications from original data */
static const HouseSpec _original_house_specs[] = {
/**
diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp
index 7a319d66fc..99b6ad2ec6 100644
--- a/src/terraform_gui.cpp
+++ b/src/terraform_gui.cpp
@@ -32,6 +32,7 @@
#include "hotkeys.h"
#include "engine_base.h"
#include "terraform_gui.h"
+#include "town_gui.h"
#include "zoom_func.h"
#include "widgets/terraform_widget.h"
@@ -465,6 +466,9 @@ static const 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),
@@ -609,6 +613,10 @@ 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;
@@ -730,6 +738,7 @@ 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),
HOTKEY_LIST_END
};
diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp
index ef785f4d05..45d751dc56 100644
--- a/src/toolbar_gui.cpp
+++ b/src/toolbar_gui.cpp
@@ -497,28 +497,9 @@ static CallBackFunction MenuClickMap(int index)
/* --- Town button menu --- */
-enum TownMenuEntries {
- TME_SHOW_TOWNDIRECTORY = 0,
- TME_SHOW_FOUNDTOWN,
- TME_SHOW_BUILDHOUSE,
-};
-
static CallBackFunction ToolbarTownClick(Window *w)
{
- DropDownList *list = new DropDownList();
- *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, TME_SHOW_TOWNDIRECTORY, false);
-
- /* Hide "found town" and "fund new house" if we are a spectator */
- if (_local_company != COMPANY_SPECTATOR) {
- if (_game_mode == GM_EDITOR || _settings_game.economy.found_town != TF_FORBIDDEN) {
- *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_FOUND_TOWN, TME_SHOW_FOUNDTOWN, false);
- }
- if (_game_mode == GM_EDITOR || _settings_game.economy.allow_placing_houses) {
- *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_FUND_HOUSE, TME_SHOW_BUILDHOUSE, false);
- }
- }
-
- PopupMainToolbMenu(w, WID_TN_TOWNS, list, TME_SHOW_TOWNDIRECTORY);
+ PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2);
return CBF_NONE;
}
@@ -531,9 +512,10 @@ static CallBackFunction ToolbarTownClick(Window *w)
static CallBackFunction MenuClickTown(int index)
{
switch (index) {
- case TME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break;
- case TME_SHOW_FOUNDTOWN: ShowFoundTownWindow(); break;
- case TME_SHOW_BUILDHOUSE: ShowBuildHousePicker(); break;
+ case 0: ShowTownDirectory(); break;
+ case 1: // setting could be changed when the dropdown was open
+ if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow();
+ break;
}
return CBF_NONE;
}
@@ -1237,10 +1219,9 @@ static CallBackFunction ToolbarScenGenLand(Window *w)
static CallBackFunction ToolbarScenGenTown(Window *w)
{
- DropDownList *list = new DropDownList();
- *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_FOUND_TOWN, TME_SHOW_FOUNDTOWN, false);
- *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_FUND_HOUSE, TME_SHOW_BUILDHOUSE, false);
- PopupMainToolbMenu(w, WID_TE_TOWN_GENERATE, list, TME_SHOW_FOUNDTOWN);
+ w->HandleButtonClick(WID_TE_TOWN_GENERATE);
+ if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
+ ShowFoundTownWindow();
return CBF_NONE;
}
@@ -2067,10 +2048,9 @@ struct ScenarioEditorToolbarWindow : Window {
virtual void OnDropdownSelect(int widget, int index)
{
- /* The map and the town buttons are in a different location on
- * the scenario editor toolbar, so we need to adjust for it. */
+ /* The map button is in a different location on the scenario
+ * editor toolbar, so we need to adjust for it. */
if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP;
- if (widget == WID_TE_TOWN_GENERATE) widget = WID_TN_TOWNS;
CallBackFunction cbf = _menu_clicked_procs[widget](index);
if (cbf != CBF_NONE) this->last_started_action = cbf;
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
@@ -2223,7 +2203,7 @@ static const NWidgetPart _nested_toolb_scen_inner_widgets[] = {
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
NWidget(NWID_SPACER),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION),
- NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
+ NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION),
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS),
diff --git a/src/town.h b/src/town.h
index 0795767c53..06edbe80ad 100644
--- a/src/town.h
+++ b/src/town.h
@@ -170,19 +170,7 @@ enum TownFlags {
CommandCost CheckforTownRating(DoCommandFlag flags, Town *t, TownRatingCheckType type);
-TileIndexDiffC GetHouseNorthPartDiffC(HouseID &house);
-
-/**
- * Determines if a given HouseID is part of a multitile house.
- * The given ID is set to the ID of the north tile and the TileDiff to the north tile is returned.
- *
- * @param house Is changed to the HouseID of the north tile of the same house
- * @return TileDiff from the tile of the given HouseID to the north tile
- */
-static inline TileIndexDiff GetHouseNorthPart(HouseID &house)
-{
- return ToTileIndexDiff(GetHouseNorthPartDiffC(house));
-}
+TileIndexDiff GetHouseNorthPart(HouseID &house);
Town *CalcClosestTownFromTile(TileIndex tile, uint threshold = UINT_MAX);
@@ -200,7 +188,7 @@ void UpdateTownCargoBitmap();
CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags);
Town *ClosestTownFromTile(TileIndex tile, uint threshold);
void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags);
-HouseZonesBits TryGetTownRadiusGroup(const Town *t, TileIndex tile, uint *distance = NULL, uint *zone_inner = NULL, uint *zone_outer = NULL);
+HouseZonesBits TryGetTownRadiusGroup(const Town *t, TileIndex tile);
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile);
void SetTownRatingTestMode(bool mode);
uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t);
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index 68eddb8649..83e21d935f 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -52,8 +52,6 @@
#include "safeguards.h"
-static const uint SQUARED_TOWN_RADIUS_FUNDED_CENTRE = 26; ///< Squared radius (exclusive) for the most inner #HZB_TOWN_CENTRE town zone while "fund buildings" is in progress.
-
TownID _new_town_id;
uint32 _town_cargoes_accepted; ///< Bitmap of all cargoes accepted by houses.
@@ -72,10 +70,6 @@ Town::~Town()
* and remove from list of sorted towns */
DeleteWindowById(WC_TOWN_VIEW, this->index);
- /* It is possible that "select town to join house to" window
- * contain this town. Simply close it. */
- DeleteWindowById(WC_SELECT_TOWN, 0);
-
/* Check no industry is related to us. */
const Industry *i;
FOR_ALL_INDUSTRIES(i) assert(i->town != this);
@@ -168,64 +162,6 @@ void Town::InitializeLayout(TownLayout layout)
return Town::Get(index);
}
-static inline uint16 DefaultHouseCostForCargoAccepted(uint16 callback_mask, byte cargo_acceptance, CargoID accepts_cargo)
-{
- uint16 cost = HasBit(callback_mask, CBM_HOUSE_CARGO_ACCEPTANCE) ? 6 : cargo_acceptance; // assume 75% (6/8) if cb 1F is available
- if (HasBit(callback_mask, CBM_HOUSE_ACCEPT_CARGO)) {
- return cost * 4; // assume 50% if cb 2A is available (all three cargoes)
- } else if (accepts_cargo == CT_PASSENGERS || accepts_cargo == CT_MAIL) {
- return cost * 2; // 25% for passengers/mail
- } else if (accepts_cargo != CT_INVALID) {
- return cost * 8; // 100% for other cargo (goods etc.)
- } else {
- return 0;
- }
-}
-
-/**
- * Generate default value of the house build cost multiplier for a
- * house of given properties.
- *
- * @param callback_mask The bitmask of callbacks defined for the house. Used to determine
- * if the house has custom cargo production/acceptance.
- * @param population Population of the house.
- * @param mail_generation Mail generation multiplier of the house.
- * @param cargo_acceptance1 How much cargo is accepted by the house (first cargo).
- * @param cargo_acceptance2 How much cargo is accepted by the house (second cargo).
- * @param cargo_acceptance3 How much cargo is accepted by the house (third cargo).
- * @param accepts_cargo1 Cargo accepted by the house (first).
- * @param accepts_cargo2 Cargo accepted by the house (second).
- * @param accepts_cargo3 Cargo accepted by the house (third).
- * @return Default build cost multiplier.
- *
- * @see HouseSpec
- */
-uint16 DefaultHouseCostBaseMultiplier(uint16 callback_mask, byte population, byte mail_generation, byte cargo_acceptance1, byte cargo_acceptance2, byte cargo_acceptance3, CargoID accepts_cargo1, CargoID accepts_cargo2, CargoID accepts_cargo3)
-{
- uint16 cost = 64;
-
- if (HasBit(callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
- cost += 128 * 3 / 4; // assume 75% if cb 2E is available
- } else {
- cost += 128 * (population * population + mail_generation * mail_generation) / (255 * 255 + 255 * 255);
- }
-
- cost += DefaultHouseCostForCargoAccepted(callback_mask, cargo_acceptance1, accepts_cargo1);
- cost += DefaultHouseCostForCargoAccepted(callback_mask, cargo_acceptance2, accepts_cargo2);
- cost += DefaultHouseCostForCargoAccepted(callback_mask, cargo_acceptance3, accepts_cargo3);
-
- return cost;
-}
-
-/**
- * Get the cost for building this house
- * @return the cost (inflation corrected etc)
- */
-Money HouseSpec::GetConstructionCost() const
-{
- return (_price[PR_BUILD_HOUSE] * this->construction_cost) >> 8;
-}
-
/**
* Get the cost for removing this house
* @return the cost (inflation corrected etc)
@@ -337,8 +273,7 @@ static void DrawOldHouseTileInGUI(int x, int y, HouseID house_id, bool ground)
} else {
/* Add a house on top of the ground? */
if (dcts->building.sprite != 0) {
- Point sub = RemapCoords(dcts->subtile_x, dcts->subtile_y, 0);
- DrawSprite(dcts->building.sprite, dcts->building.pal, x + UnScaleGUI(sub.x), y + UnScaleGUI(sub.y));
+ 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);
@@ -346,17 +281,15 @@ static void DrawOldHouseTileInGUI(int x, int y, HouseID house_id, bool ground)
}
/**
- * Draw image of a house. Image will be centered between the \c left and the \c right and vertically aligned to the \c bottom.
+ * 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
- * @param image_type Context in which the house is being drawn
- * @param variant house variant
*/
-void DrawHouseImage(HouseID house_id, int left, int top, int right, int bottom, HouseImageType image_type, HouseVariant variant)
+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;
@@ -365,14 +298,13 @@ void DrawHouseImage(HouseID house_id, int left, int top, int right, int bottom,
const HouseSpec *hs = HouseSpec::Get(house_id);
- /* sprites are relative to the top corner of the ground tile */
- const uint gui_tile_pixels = ScaleGUITrad(TILE_PIXELS); // TILE_PIXELS rescaled to current GUI zoom
- uint x = (right - left) / 2;
- uint y = bottom - top - gui_tile_pixels;
- if (hs->building_flags & TILE_SIZE_1x2) x -= gui_tile_pixels / 2;
- if (hs->building_flags & TILE_SIZE_2x1) x += gui_tile_pixels / 2;
- if (hs->building_flags & BUILDING_HAS_2_TILES) y -= gui_tile_pixels / 2;
- if (hs->building_flags & BUILDING_HAS_4_TILES) y -= gui_tile_pixels / 2;
+ /* sprites are relative to the topmost pixel of the ground tile */
+ uint x = (right - left + 1) / 2;
+ uint y = bottom - top + 1 - TILE_PIXELS;
+ if (hs->building_flags & TILE_SIZE_1x2) x -= TILE_PIXELS / 2;
+ if (hs->building_flags & TILE_SIZE_2x1) x += TILE_PIXELS / 2;
+ if (hs->building_flags & BUILDING_HAS_2_TILES) y -= TILE_PIXELS / 2;
+ if (hs->building_flags & BUILDING_HAS_4_TILES) y -= TILE_PIXELS / 2;
bool new_house = false;
if (house_id >= NEW_HOUSE_OFFSET) {
@@ -394,10 +326,10 @@ void DrawHouseImage(HouseID house_id, int left, int top, int right, int bottom,
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 = UnScaleGUI(offset.x);
- offset.y = UnScaleGUI(offset.y);
+ 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, variant, image_type, ground);
+ DrawNewHouseTileInGUI(x + offset.x, y + offset.y, hid, ground);
} else {
DrawOldHouseTileInGUI(x + offset.x, y + offset.y, hid, ground);
}
@@ -726,15 +658,14 @@ static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags)
return cost;
}
-void AddProducedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &produced, HouseVariant variant)
+void AddProducedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &produced)
{
const HouseSpec *hs = HouseSpec::Get(house_id);
if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
Town *t = (tile == INVALID_TILE) ? NULL : Town::GetByTile(tile);
- HouseImageType image_type = (tile == INVALID_TILE) ? HIT_GUI_HOUSE_PREVIEW : HIT_HOUSE_TILE;
for (uint i = 0; i < 256; i++) {
- uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile, image_type, variant);
+ uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile);
if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
@@ -765,11 +696,10 @@ static inline void AddAcceptedCargoSetMask(CargoID cargo, uint amount, CargoArra
SetBit(*always_accepted, cargo);
}
-void AddAcceptedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &acceptance, uint32 *always_accepted, HouseVariant variant)
+void AddAcceptedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
{
const HouseSpec *hs = HouseSpec::Get(house_id);
Town *t = (tile == INVALID_TILE) ? NULL : Town::GetByTile(tile);
- HouseImageType image_type = (tile == INVALID_TILE) ? HIT_GUI_HOUSE_PREVIEW : HIT_HOUSE_TILE;
CargoID accepts[3];
/* Set the initial accepted cargo types */
@@ -779,7 +709,7 @@ void AddAcceptedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &accepta
/* Check for custom accepted cargo types */
if (HasBit(hs->callback_mask, CBM_HOUSE_ACCEPT_CARGO)) {
- uint16 callback = GetHouseCallback(CBID_HOUSE_ACCEPT_CARGO, 0, 0, house_id, t, tile, image_type, variant);
+ uint16 callback = GetHouseCallback(CBID_HOUSE_ACCEPT_CARGO, 0, 0, house_id, t, tile);
if (callback != CALLBACK_FAILED) {
/* Replace accepted cargo types with translated values from callback */
accepts[0] = GetCargoTranslation(GB(callback, 0, 5), hs->grf_prop.grffile);
@@ -790,7 +720,7 @@ void AddAcceptedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &accepta
/* Check for custom cargo acceptance */
if (HasBit(hs->callback_mask, CBM_HOUSE_CARGO_ACCEPTANCE)) {
- uint16 callback = GetHouseCallback(CBID_HOUSE_CARGO_ACCEPTANCE, 0, 0, house_id, t, tile, image_type, variant);
+ uint16 callback = GetHouseCallback(CBID_HOUSE_CARGO_ACCEPTANCE, 0, 0, house_id, t, tile);
if (callback != CALLBACK_FAILED) {
AddAcceptedCargoSetMask(accepts[0], GB(callback, 0, 4), acceptance, always_accepted);
AddAcceptedCargoSetMask(accepts[1], GB(callback, 4, 4), acceptance, always_accepted);
@@ -2141,52 +2071,32 @@ bool GenerateTowns(TownLayout layout)
/**
- * Returns the bit corresponding to the town zone of the specified tile.
- * Also returns bounds of this zone.
- *
- * Unlikely to #GetTownRadiusGroup, returns #HZB_END if the tile is outside of the town.
- *
- * When returning #HZB_END (outside of the town) \c zone_outer will be set to \c UINT_MAX.
+ * Returns the bit corresponding to the town zone of the specified tile
+ * or #HZB_END if the tile is ouside of the town.
*
* @param t Town on which town zone is to be found
* @param tile TileIndex where town zone needs to be found
- * @param [out] distance (may be NULL) squared euclidean distance (#DistanceSquare) between the tile and center of the town
- * @param [out] zone_inner (may be NULL) squared radius of inner edge of the returned zone (inclusive)
- * @param [out] zone_outer (may be NULL) squared radius of outer edge of the returned zone (exclusive)
* @return the bit position of the given zone, as defined in HouseZones
+ *
+ * @see GetTownRadiusGroup
*/
-HouseZonesBits TryGetTownRadiusGroup(const Town *t, TileIndex tile, uint *distance, uint *zone_inner, uint *zone_outer)
+HouseZonesBits TryGetTownRadiusGroup(const Town *t, TileIndex tile)
{
- uint dist = DistanceSquare(t->xy, tile);
- uint funded_rad = (t->fund_buildings_months > 0) ? SQUARED_TOWN_RADIUS_FUNDED_CENTRE : 0;
- const uint32 (&zones)[HZB_END] = t->cache.squared_town_zone_radius;
+ uint dist = DistanceSquare(tile, t->xy);
- /* Check if we are within the town at all. */
- uint inner_rad = max(zones[HZB_TOWN_EDGE], funded_rad);
- uint outer_rad = 0;
- HouseZonesBits ret = HZB_END;
- if (dist < inner_rad) {
- /* Loop through zones and find the one that contains the tile. */
- inner_rad = 0;
- outer_rad = max(zones[HZB_TOWN_CENTRE], funded_rad);
- for (ret = HZB_TOWN_CENTRE; ret > HZB_TOWN_EDGE; ret--) {
- if (dist < outer_rad) break;
- inner_rad = max(inner_rad, outer_rad);
- outer_rad = zones[ret - 1];
- }
+ if (t->fund_buildings_months && dist <= 25) return HZB_TOWN_CENTRE;
+
+ HouseZonesBits smallest = HZB_END;
+ for (HouseZonesBits i = HZB_BEGIN; i < HZB_END; i++) {
+ if (dist < t->cache.squared_town_zone_radius[i]) smallest = i;
}
- if (distance != NULL) *distance = dist;
- if (zone_inner != NULL) *zone_inner = inner_rad;
- if (zone_outer != NULL) *zone_outer = outer_rad;
-
- return ret;
+ return smallest;
}
/**
* Returns the bit corresponding to the town zone of the specified tile.
- *
- * Unlikely to #TryGetTownRadiusGroup, returns #HZB_TOWN_EDGE if the tile outside of the town.
+ * Returns #HZB_TOWN_EDGE if the tile is either in an edge zone or ouside of the town.
*
* @param t Town on which town zone is to be found
* @param tile TileIndex where town zone needs to be found
@@ -2251,7 +2161,7 @@ static void MakeTownHouse(TileIndex t, Town *town, byte counter, byte stage, Hou
* @param tile tile to check
* @param town town that is checking
* @param noslope are slopes (foundations) allowed?
- * @return cost of building here or error message
+ * @return success if house can be built here, error message otherwise
*/
static inline CommandCost CanBuildHouseHere(TileIndex tile, TownID town, bool noslope)
{
@@ -2272,330 +2182,206 @@ static inline CommandCost CanBuildHouseHere(TileIndex tile, TownID town, bool no
/* do not try to build over house owned by another town */
if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) != town) return CMD_ERROR;
- return ret;
+ return CommandCost();
}
/**
- * Checks if a house can be built at this tile, must have the same max z as parameter.
- * @param tile tile to check
- * @param town town that is checking
- * @param z max z of this tile so more parts of a house are at the same height (with foundation)
- * @param noslope are slopes (foundations) allowed?
- * @return cost of building here or error message
- * @see CanBuildHouseHere()
- */
-static CommandCost CheckBuildHouseSameZ(TileIndex tile, TownID town, int z, bool noslope)
-{
- CommandCost ret = CanBuildHouseHere(tile, town, noslope);
-
- /* if building on slopes is allowed, there will be flattening foundation (to tile max z) */
- if (ret.Succeeded() && GetTileMaxZ(tile) != z) ret = CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
-
- return ret;
-}
-
-
-/**
- * Checks if a house of size 2x2 can be built at this tile
- * @param tile tile, N corner
- * @param town town that is checking
- * @param z maximum tile z so all tile have the same max z
- * @param noslope are slopes (foundations) allowed?
- * @return true iff house can be built
- * @see CheckBuildHouseSameZ()
- */
-static bool CheckFree2x2Area(TileIndex tile, TownID town, int z, bool noslope)
-{
- /* we need to check this tile too because we can be at different tile now */
- if (CheckBuildHouseSameZ(tile, town, z, noslope).Failed()) return false;
-
- for (DiagDirection d = DIAGDIR_SE; d < DIAGDIR_END; d++) {
- tile += TileOffsByDiagDir(d);
- if (CheckBuildHouseSameZ(tile, town, z, noslope).Failed()) return false;
- }
-
- return true;
-}
-
-
-/**
- * Check whether houses of given type are buildable in current game.
+ * Checks if a house can be built here. Important is slope, bridge above
+ * and ability to clear the land.
*
- * @param house house type
- * @param availability house must be allowed in any of the given climates (#HZ_CLIMALL bits)
- * and in any of the given town zones (#HZ_ZONALL bits), skip testing
- * climate if no climate bits are given, skip testing town zones if no
- * town zone bits are given
- * @return success if house is available, error message otherwise
+ * @param ta tile area to check
+ * @param town town that is checking
+ * @param maxz z level of the house, check if all tiles have this max z level
+ * @param noslope are slopes (foundations) allowed?
+ * @return success if house can be built here, error message otherwise
+ *
+ * @see TownLayoutAllowsHouseHere
*/
-CommandCost IsHouseTypeAllowed(HouseID house, HouseZones availability, bool allow_historical)
+static inline CommandCost CanBuildHouseHere(const TileArea &ta, TownID town, int maxz, bool noslope)
{
- const HouseSpec *hs = HouseSpec::Get(house);
-
- /* Disallow disabled and replaced houses. */
- if (!hs->enabled || hs->grf_prop.override != INVALID_HOUSE_ID) return CMD_ERROR;
-
- /* Disallow additional parts of a multi-tile building. */
- if (!(hs->building_flags & BUILDING_HAS_1_TILE)) return CMD_ERROR;
-
- /* Check if the house is allowed in all of the given house zones. */
- if ((availability & HZ_ZONALL) && !(availability & HZ_ZONALL & hs->building_availability)) {
- return_cmd_error(STR_ERROR_BUILDING_NOT_ALLOWED_IN_THIS_TOWN_ZONE);
+ TILE_AREA_LOOP(tile, ta) {
+ CommandCost ret = CanBuildHouseHere(tile, town, noslope);
+ /* if building on slopes is allowed, there will be flattening foundation (to tile max z) */
+ if (ret.Succeeded() && GetTileMaxZ(tile) != maxz) ret = CommandCost(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
+ if (ret.Failed()) return ret;
}
- /* Check if we can build this house in any of the given climates. */
- if ((availability & HZ_CLIMALL) && !(availability & HZ_CLIMALL & hs->building_availability)) {
- if ((availability & HZ_SUBARTC_ABOVE) && (hs->building_availability & HZ_SUBARTC_BELOW)) {
- return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE);
- }
- if ((availability & HZ_SUBARTC_BELOW) && (hs->building_availability & HZ_SUBARTC_ABOVE)) {
- return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE);
- }
- return CMD_ERROR;
- }
-
- /* Check for historical buildings. */
- if (!allow_historical && hs->extra_flags & BUILDING_IS_HISTORICAL) return CMD_ERROR;
-
- /* Check if the house can be placed manually. */
- if (_current_company != OWNER_TOWN && (hs->extra_flags & DISALLOW_BUILDING_MANUALLY)) return CMD_ERROR;
- if (_current_company < MAX_COMPANIES && (hs->extra_flags & DISALLOW_BUILDING_BY_COMPANIES)) return CMD_ERROR;
-
return CommandCost();
}
+
/**
- * Check if house is currently buildable.
+ * Test whether houses of given type are avaliable in current game.
+ *
+ * The function will check whether the house is available at all e.g. is not overriden.
+ * Also availability for current climate and given house zone will be tested.
*
* @param house house type
- * @param t the town the house is about to be built
- * @param ignore_year allow obsolete and feature houses
- * @return success if house is buildable, error message otherwise
+ * @param above_snowline true to test availability above the snow line, false for below (arctic climate only)
+ * @param zone return error if houses are forbidden in this house zone
+ * @return success if house is avaliable, error message otherwise
*/
-static CommandCost CheckCanBuildHouse(HouseID house, const Town *t, bool ignore_year)
+static inline CommandCost IsHouseTypeAllowed(HouseID house, bool above_snowline, HouseZonesBits zone)
+ {
+ const HouseSpec *hs = HouseSpec::Get(house);
+ /* Disallow disabled and replaced houses. */
+ if (!hs->enabled || hs->grf_prop.override != INVALID_HOUSE_ID) return CMD_ERROR;
+
+ /* Check if we can build this house in current climate. */
+ if (_settings_game.game_creation.landscape != LT_ARCTIC) {
+ if (!(hs->building_availability & (HZ_TEMP << _settings_game.game_creation.landscape))) return CMD_ERROR;
+ } else if (above_snowline) {
+ if (!(hs->building_availability & HZ_SUBARTC_ABOVE)) return_cmd_error(STR_ERROR_BUILDING_NOT_ALLOWED_ABOVE_SNOW_LINE);
+ } else {
+ if (!(hs->building_availability & HZ_SUBARTC_BELOW)) return_cmd_error(STR_ERROR_BUILDING_NOT_ALLOWED_BELOW_SNOW_LINE);
+ }
+
+ /* 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);
+ }
+
+ return CommandCost();
+}
+
+
+/**
+ * Check whether a town can hold more house types.
+ * @param t the town we wan't to check
+ * @param house type of the house we wan't to add
+ * @return success if houses of this type are allowed, error message otherwise
+ */
+static inline CommandCost IsAnotherHouseTypeAllowedInTown(Town *t, HouseID house)
{
const HouseSpec *hs = HouseSpec::Get(house);
- if (!ignore_year && (_cur_year > hs->max_year || _cur_year < hs->min_year)) return CMD_ERROR;
-
/* Don't let these counters overflow. Global counters are 32bit, there will never be that many houses. */
if (hs->class_id != HOUSE_NO_CLASS) {
/* id_count is always <= class_count, so it doesn't need to be checked */
- if (t->cache.building_counts.class_count[hs->class_id] == UINT16_MAX) return CMD_ERROR;
+ if (t->cache.building_counts.class_count[hs->class_id] == UINT16_MAX) return_cmd_error(STR_ERROR_TOO_MANY_HOUSE_SETS);
} else {
/* If the house has no class, check id_count instead */
- if (t->cache.building_counts.id_count[house] == UINT16_MAX) return CMD_ERROR;
- }
-
- /* Special houses that there can be only one of. */
- if (hs->building_flags & BUILDING_IS_CHURCH) {
- if (HasBit(t->flags, TOWN_HAS_CHURCH)) return_cmd_error(STR_ERROR_ONLY_ONE_CHURCH_PER_TOWN);
- } else if (hs->building_flags & BUILDING_IS_STADIUM) {
- if (HasBit(t->flags, TOWN_HAS_STADIUM)) return_cmd_error(STR_ERROR_ONLY_ONE_STADIUM_PER_TOWN);
+ if (t->cache.building_counts.id_count[house] == UINT16_MAX) return_cmd_error(STR_ERROR_TOO_MANY_HOUSE_TYPES);
}
return CommandCost();
}
-/**
- * Check if a house can be built at a given area.
- * @param house house type
- * @param tile northern tile of the area to check
- * @return cost of building here or error message
- * @see CanBuildHouseHere()
- */
-CommandCost CheckFlatLandHouse(HouseID house, TileIndex tile)
-{
- 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;
- int maxz = GetTileMaxZ(tile);
- CommandCost cost(EXPENSES_CONSTRUCTION);
- TILE_AREA_LOOP(ti, TileArea(tile, w, h)) {
- CommandCost ret = (ti == tile) ?
- CanBuildHouseHere(ti, INVALID_TOWN, noslope) :
- CheckBuildHouseSameZ(ti, INVALID_TOWN, maxz, noslope);
- if (ret.Failed()) return ret;
- cost.AddCost(ret);
- }
-
- return cost;
-}
-
-
/**
* Checks if current town layout allows building here
* @param t town
- * @param tile tile to check
+ * @param ta tile area to check
* @return true iff town layout allows building here
* @note see layouts
*/
-static inline bool TownLayoutAllowsHouseHere(Town *t, TileIndex tile)
+static inline bool TownLayoutAllowsHouseHere(Town *t, const TileArea &ta)
{
/* Allow towns everywhere when we don't build roads */
if (!_settings_game.economy.allow_town_roads && !_generating_world) return true;
- TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
+ TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, ta.tile);
+ const uint overflow = 3 * 4 * UINT16_MAX; // perform "floor division"
switch (t->layout) {
- case TL_2X2_GRID:
- if ((grid_pos.x % 3) == 0 || (grid_pos.y % 3) == 0) return false;
- break;
-
- case TL_3X3_GRID:
- if ((grid_pos.x % 4) == 0 || (grid_pos.y % 4) == 0) return false;
- break;
-
- default:
- break;
+ case TL_2X2_GRID: return (uint)(grid_pos.x + overflow) % 3 >= ta.w && (uint)(grid_pos.y + overflow) % 3 >= ta.h;
+ case TL_3X3_GRID: return (uint)(grid_pos.x + overflow) % 4 >= ta.w && (uint)(grid_pos.y + overflow) % 4 >= ta.h;
+ default: return true;
}
-
- return true;
}
/**
- * Checks if current town layout allows 2x2 building here
- * @param t town
- * @param tile tile to check
- * @return true iff town layout allows 2x2 building here
- * @note see layouts
- */
-static inline bool TownLayoutAllows2x2HouseHere(Town *t, TileIndex tile)
-{
- /* Allow towns everywhere when we don't build roads */
- if (!_settings_game.economy.allow_town_roads && !_generating_world) return true;
-
- /* Compute relative position of tile. (Positive offsets are towards north) */
- TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile);
-
- switch (t->layout) {
- case TL_2X2_GRID:
- grid_pos.x %= 3;
- grid_pos.y %= 3;
- if ((grid_pos.x != 2 && grid_pos.x != -1) ||
- (grid_pos.y != 2 && grid_pos.y != -1)) return false;
- break;
-
- case TL_3X3_GRID:
- if ((grid_pos.x & 3) < 2 || (grid_pos.y & 3) < 2) return false;
- break;
-
- default:
- break;
- }
-
- return true;
-}
-
-
-/**
- * Checks if 1x2 or 2x1 building is allowed here, also takes into account current town layout
- * Also, tests both building positions that occupy this tile
- * @param tile tile where the building should be built
- * @param t town
- * @param maxz all tiles should have the same height
- * @param noslope are slopes forbidden?
- * @param second diagdir from first tile to second tile
- */
-static bool CheckTownBuild2House(TileIndex *tile, Town *t, int maxz, bool noslope, DiagDirection second)
-{
- /* 'tile' is already checked in BuildTownHouse() - CanBuildHouseHere() and slope test */
-
- TileIndex tile2 = *tile + TileOffsByDiagDir(second);
- if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope).Succeeded()) return true;
-
- tile2 = *tile + TileOffsByDiagDir(ReverseDiagDir(second));
- if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope).Succeeded()) {
- *tile = tile2;
- return true;
- }
-
- return false;
-}
-
-
-/**
- * Checks if 2x2 building is allowed here, also takes into account current town layout
- * Also, tests all four building positions that occupy this tile
- * @param tile tile where the building should be built
- * @param t town
- * @param maxz all tiles should have the same height
- * @param noslope are slopes forbidden?
- */
-static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, int maxz, bool noslope)
-{
- TileIndex tile2 = *tile;
-
- for (DiagDirection d = DIAGDIR_SE;; d++) { // 'd' goes through DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_END
- if (TownLayoutAllows2x2HouseHere(t, tile2) && CheckFree2x2Area(tile2, t->index, maxz, noslope)) {
- *tile = tile2;
- return true;
- }
- if (d == DIAGDIR_END) break;
- tile2 += TileOffsByDiagDir(ReverseDiagDir(d)); // go clockwise
- }
-
- return false;
-}
-
-
-/**
- * Check if a given tile is not too far from town for placing a house.
+ * Find a suitable place (free of any obstacles) for a new town house. Search around a given location
+ * taking into account the layout of the town.
*
+ * @param tile tile that must be included by the building
+ * @param t the town we are building in
+ * @param house house type
+ * @return where the building can be placed, INVALID_TILE if no lacation was found
+ *
+ * @pre CanBuildHouseHere(tile, t->index, false)
+ *
+ * @see CanBuildHouseHere
+ */
+static TileIndex FindPlaceForTownHouseAroundTile(TileIndex tile, Town *t, HouseID house)
+{
+ const HouseSpec *hs = HouseSpec::Get(house);
+ bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0;
+
+ TileArea ta(tile, 1, 1);
+ DiagDirection dir;
+ uint count;
+ if (hs->building_flags & TILE_SIZE_2x2) {
+ ta.w = ta.h = 2;
+ dir = DIAGDIR_NW; // 'd' goes through DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_SE
+ count = 4;
+ } else if (hs->building_flags & TILE_SIZE_2x1) {
+ ta.w = 2;
+ dir = DIAGDIR_NE;
+ count = 2;
+ } else if (hs->building_flags & TILE_SIZE_1x2) {
+ ta.h = 2;
+ dir = DIAGDIR_NW;
+ count = 2;
+ } else { // TILE_SIZE_1x1
+ /* CanBuildHouseHere(tile, t->index, false) already checked */
+ if (noslope && !IsTileFlat(tile)) return INVALID_TILE;
+ return tile;
+ }
+
+ int maxz = GetTileMaxZ(tile);
+ /* Drift around the tile and find a place for the house. For 1x2 and 2x1 houses just two
+ * positions will be checked (at the exact tile and the other). In case of 2x2 houses
+ * 4 positions have to be checked (clockwise). */
+ while (count-- > 0) {
+ if (!TownLayoutAllowsHouseHere(t, ta)) continue;
+ if (CanBuildHouseHere(ta, t->index, maxz, noslope).Succeeded()) return ta.tile;
+ ta.tile += TileOffsByDiagDir(dir);
+ dir = ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT);
+ }
+
+ return INVALID_TILE;
+}
+
+
+/**
+ * Check if a given house can be built in a given town.
+ * @param house house type
* @param t the town
- * @param tile the tile
- * @param allow_outside whether to allow some area outside but near to the town.
- * @return success or an error
+ * @return success if house can be built, error message otherwise
*/
-CommandCost CheckHouseDistanceFromTown(const Town *t, TileIndex tile, bool allow_outside)
+static CommandCost CheckCanBuildHouse(HouseID house, const Town *t)
{
- uint square_dist = DistanceSquare(t->xy, tile);
- uint square_rad = t->cache.squared_town_zone_radius[HZB_BEGIN];
- if (t->fund_buildings_months > 0) square_rad = max(square_rad, SQUARED_TOWN_RADIUS_FUNDED_CENTRE);
+ const HouseSpec *hs = HouseSpec::Get(house);
- if (square_dist < square_rad) return CommandCost();
-
- if (allow_outside) {
- /* How far from edge of a town a house can be placed (in tiles). */
- const uint overdist = 8;
- if (SqrtCmp(square_dist, square_rad, overdist * overdist)) return CommandCost();
+ if (_loaded_newgrf_features.has_newhouses && !_generating_world &&
+ _game_mode != GM_EDITOR && (hs->extra_flags & BUILDING_IS_HISTORICAL) != 0) {
+ return CMD_ERROR;
}
- return_cmd_error(STR_ERROR_TOO_FAR_FROM_TOWN);
+ if (_cur_year > hs->max_year) return_cmd_error(STR_ERROR_BUILDING_IS_TOO_OLD);
+ if (_cur_year < hs->min_year) return_cmd_error(STR_ERROR_BUILDING_IS_TOO_MODERN);
+
+ /* Special houses that there can be only one of. */
+ if (hs->building_flags & BUILDING_IS_CHURCH) {
+ if (HasBit(t->flags, TOWN_HAS_CHURCH)) return_cmd_error(STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN);
+ } else if (hs->building_flags & BUILDING_IS_STADIUM) {
+ if (HasBit(t->flags, TOWN_HAS_STADIUM)) return_cmd_error(STR_ERROR_ONLY_ONE_BUILDING_ALLOWED_PER_TOWN);
+ }
+
+ return CommandCost();
}
-/**
- * Set house variant after placing a house.
- *
- * @param tile tile where the house was placed
- * @param variant house variant
- */
-static void SetupHouseVariant(TileIndex tile, byte variant)
-{
- if (!_loaded_newgrf_features.has_newhouses) return;
-
- HouseID house = GetHouseType(tile);
- if (house < NEW_HOUSE_OFFSET) return;
-
- BuildingFlags flags = HouseSpec::Get(house)->building_flags;
- AnimateNewHouseSetupVariant(tile, variant);
- if (flags & BUILDING_2_TILES_Y) AnimateNewHouseSetupVariant(tile + TileDiffXY(0, 1), variant);
- if (flags & BUILDING_2_TILES_X) AnimateNewHouseSetupVariant(tile + TileDiffXY(1, 0), variant);
- if (flags & BUILDING_HAS_4_TILES) AnimateNewHouseSetupVariant(tile + TileDiffXY(1, 1), variant);
-}
/**
* Really build a house.
* @param t town to build house in
* @param tile house location
* @param house house type
- * @param variant house variant
* @param random_bits random bits for the house
*/
-static void DoBuildHouse(Town *t, TileIndex tile, HouseID house, byte variant, byte random_bits)
+static void DoBuildHouse(Town *t, TileIndex tile, HouseID house, byte random_bits)
{
t->cache.num_houses++;
@@ -2625,80 +2411,56 @@ static void DoBuildHouse(Town *t, TileIndex tile, HouseID house, byte variant, b
}
MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits);
- SetupHouseVariant(tile, variant);
UpdateTownRadius(t);
UpdateTownCargoes(t, tile);
}
-/**
- * Convert current climate to corresponding #HouseZones.
- *
- * @param altitude Test against given tile height (above/below snowline).
- * -1 to return all bits possible in current climate e.g.
- * both HZ_SUBARTC_ABOVE and HZ_SUBARTC_BELOW in arctic.
- * @return Bitmask related to current climate (subset of #HZ_CLIMALL).
- */
-HouseZones CurrentClimateHouseZones(int altitude)
-{
- if (_settings_game.game_creation.landscape == LT_ARCTIC) {
- if (altitude < 0) return HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW;
- if (altitude > HighestSnowLine()) return HZ_SUBARTC_ABOVE;
- }
- return (HouseZones)(HZ_TEMP << _settings_game.game_creation.landscape);
-}
-
-static Money GetHouseConstructionCost(HouseID house)
-{
- const HouseSpec *hs = HouseSpec::Get(house);
- uint flags = hs->building_flags;
- Money cost = hs->GetConstructionCost();
- if (flags & BUILDING_2_TILES_Y) cost += (++hs)->GetConstructionCost();
- if (flags & BUILDING_2_TILES_X) cost += (++hs)->GetConstructionCost();
- if (flags & BUILDING_HAS_4_TILES) cost += (++hs)->GetConstructionCost();
- return cost;
-}
-
/**
* Place a custom house
* @param tile tile where the house will be located
* @param flags flags for the command
- * @param p1
- * - p1 = (bit 0-15) - the HouseID of the house
- * - p1 = (bit 16-31) - the TownID of the town
- * @param p2
- * - p2 = (bit 0-7 ) - random bits
- * - p2 = (bit 8-15) - house variant (1..num_variants) or 0 for no variant
+ * @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 p1, uint32 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::GetIfValid(GB(p1, 16, 16));
+ Town *t = Town::Get(GB(p1, 16, 16));
if (t == NULL) return CMD_ERROR;
byte random_bits = GB(p2, 0, 8);
- byte variant = GB(p2, 8, 8);
- bool deity = (_current_company == OWNER_DEITY) || (_game_mode == GM_EDITOR && _current_company == OWNER_NONE);
- if (!deity && !_settings_game.economy.allow_placing_houses) return CMD_ERROR;
- HouseZones zones = CurrentClimateHouseZones(deity ? -1 : GetTileMaxZ(tile));
- if (!deity) zones |= (HouseZones)(HZ_ZON1 << GetTownRadiusGroup(t, tile));
+ int max_z = GetTileMaxZ(tile);
+ bool above_snowline = (_settings_game.game_creation.landscape == LT_ARCTIC) && (max_z > HighestSnowLine());
- CommandCost cost(EXPENSES_CONSTRUCTION);
-
- CommandCost ret = CheckHouseDistanceFromTown(t, tile, deity);
- if (ret.Succeeded()) ret = IsHouseTypeAllowed(house, zones, deity);
- if (ret.Succeeded()) ret = CheckCanBuildHouse(house, t, deity);
- if (ret.Succeeded()) ret = CheckFlatLandHouse(house, tile);
- if (ret.Succeeded()) cost.AddCost(ret);
- if (ret.Succeeded()) ret = HouseAllowsConstruction(house, variant, tile, t, random_bits);
+ CommandCost ret = IsHouseTypeAllowed(house, above_snowline, TryGetTownRadiusGroup(t, tile));
+ if (ret.Succeeded()) ret = IsAnotherHouseTypeAllowedInTown(t, house);
+ if (ret.Succeeded()) ret = CheckCanBuildHouse(house, t);
+ 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;
- /* Place the house. */
- if (flags & DC_EXEC) DoBuildHouse(t, tile, house, variant, random_bits);
+ /* Check if GRF allows this house */
+ if (!HouseAllowsConstruction(house, tile, t, random_bits)) return_cmd_error(STR_ERROR_BUILDING_NOT_ALLOWED);
- cost.AddCost(GetHouseConstructionCost(house));
- return cost;
+ if (flags & DC_EXEC) DoBuildHouse(t, tile, house, random_bits);
+ return CommandCost();
}
/**
@@ -2710,18 +2472,17 @@ CommandCost CmdBuildHouse(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
static bool BuildTownHouse(Town *t, TileIndex tile)
{
/* forbidden building here by town layout */
- if (!TownLayoutAllowsHouseHere(t, tile)) return false;
+ if (!TownLayoutAllowsHouseHere(t, TileArea(tile, 1, 1))) return false;
/* no house allowed at all, bail out */
if (CanBuildHouseHere(tile, t->index, false).Failed()) return false;
- Slope slope = GetTileSlope(tile);
- int maxz = GetTileMaxZ(tile);
-
- /* Get the town zone type of the current tile, as well as the climate.
- * This will allow to easily compare with the specs of the new house to build */
- HouseZones bitmask = (HouseZones)(HZ_ZON1 << GetTownRadiusGroup(t, tile)) | CurrentClimateHouseZones(maxz);
+ bool above_snowline = _settings_game.game_creation.landscape == LT_ARCTIC && GetTileMaxZ(tile) > HighestSnowLine();
+ HouseZonesBits zone = GetTownRadiusGroup(t, tile);
+ /* bits 0-4 are used
+ * bits 11-15 are used
+ * bits 5-10 are not used. */
HouseID houses[NUM_HOUSES];
uint num = 0;
uint probs[NUM_HOUSES];
@@ -2729,7 +2490,8 @@ static bool BuildTownHouse(Town *t, TileIndex tile)
/* Generate a list of all possible houses that can be built. */
for (uint i = 0; i < NUM_HOUSES; i++) {
- if (IsHouseTypeAllowed(i, bitmask, _generating_world || _game_mode == GM_EDITOR).Failed()) continue;
+ if (IsHouseTypeAllowed((HouseID)i, above_snowline, zone).Failed()) continue;
+ if (IsAnotherHouseTypeAllowedInTown(t, (HouseID)i).Failed()) continue;
/* Without NewHouses, all houses have probability '1' */
uint cur_prob = (_loaded_newgrf_features.has_newhouses ? HouseSpec::Get(i)->probability : 1);
@@ -2763,30 +2525,18 @@ static bool BuildTownHouse(Town *t, TileIndex tile)
houses[i] = houses[num];
probs[i] = probs[num];
- if (CheckCanBuildHouse(house, t, false).Failed()) continue;
+ CommandCost ret = CheckCanBuildHouse(house, t);
+ if (ret.Failed()) continue;
- const HouseSpec *hs = HouseSpec::Get(house);
-
- /* Make sure there is no slope? */
- bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0;
- if (noslope && slope != SLOPE_FLAT) continue;
-
- if (hs->building_flags & TILE_SIZE_2x2) {
- if (!CheckTownBuild2x2House(&tile, t, maxz, noslope)) continue;
- } else if (hs->building_flags & TILE_SIZE_2x1) {
- if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SW)) continue;
- } else if (hs->building_flags & TILE_SIZE_1x2) {
- if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SE)) continue;
- } else {
- /* 1x1 house checks are already done */
- }
+ tile = FindPlaceForTownHouseAroundTile(tile, t, house);
+ if (tile == INVALID_TILE) continue;
byte random_bits = Random();
/* Check if GRF allows this house */
- if (HouseAllowsConstruction(house, HOUSE_NO_VARIANT, tile, t, random_bits).Failed()) continue;
+ if (!HouseAllowsConstruction(house, tile, t, random_bits)) continue;
- DoBuildHouse(t, tile, house, HOUSE_NO_VARIANT, random_bits);
+ DoBuildHouse(t, tile, house, random_bits);
return true;
}
@@ -2810,27 +2560,30 @@ static void DoClearTownHouseHelper(TileIndex tile, Town *t, HouseID house)
}
/**
- * Determines if a given HouseID is part of a multi-tile house.
+ * Determines if a given HouseID is part of a multitile house.
* The given ID is set to the ID of the north tile and the TileDiff to the north tile is returned.
*
* @param house Is changed to the HouseID of the north tile of the same house
- * @return TileIndexDiffC from the tile of the given HouseID to the north tile
+ * @return TileDiff from the tile of the given HouseID to the north tile
*/
-TileIndexDiffC GetHouseNorthPartDiffC(HouseID &house)
+TileIndexDiff GetHouseNorthPart(HouseID &house)
{
- TileIndexDiffC ret = { 0, 0 };
if (house >= 3) { // house id 0,1,2 MUST be single tile houses, or this code breaks.
if (HouseSpec::Get(house - 1)->building_flags & TILE_SIZE_2x1) {
- house--, ret.x = -1, ret.y = 0;
+ house--;
+ return TileDiffXY(-1, 0);
} else if (HouseSpec::Get(house - 1)->building_flags & BUILDING_2_TILES_Y) {
- house--, ret.x = 0, ret.y = -1;
+ house--;
+ return TileDiffXY(0, -1);
} else if (HouseSpec::Get(house - 2)->building_flags & BUILDING_HAS_4_TILES) {
- house -= 2, ret.x = -1, ret.y = 0;
+ house -= 2;
+ return TileDiffXY(-1, 0);
} else if (HouseSpec::Get(house - 3)->building_flags & BUILDING_HAS_4_TILES) {
- house -= 3, ret.x = -1, ret.y = -1;
+ house -= 3;
+ return TileDiffXY(-1, -1);
}
}
- return ret;
+ return 0;
}
void ClearTownHouse(Town *t, TileIndex tile)
@@ -2898,7 +2651,6 @@ CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
t->UpdateVirtCoord();
InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
- SetWindowDirty(WC_SELECT_TOWN, 0); // only repaint this window even thought it may be too narrow for the new name
UpdateAllStationVirtCoords();
}
return CommandCost();
diff --git a/src/town_gui.cpp b/src/town_gui.cpp
index 5fa57b296a..ed19d033a4 100644
--- a/src/town_gui.cpp
+++ b/src/town_gui.cpp
@@ -18,7 +18,6 @@
#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"
@@ -36,20 +35,17 @@
#include "newgrf_config.h"
#include "newgrf_house.h"
#include "date_func.h"
-#include "zoom_func.h"
+#include "core/random_func.hpp"
#include "widgets/town_widget.h"
#include "table/strings.h"
-#include
-
#include "safeguards.h"
typedef GUIList GUITownList;
-static CommandCost ListTownsToJoinHouseTo(HouseID house, TileIndex tile, TownList *towns);
-static void ShowSelectTownWindow(const TownList &towns, const CommandContainer &cmd);
+static void PlaceProc_House(TileIndex tile);
static const NWidgetPart _nested_town_authority_widgets[] = {
NWidget(NWID_HORIZONTAL),
@@ -1204,15 +1200,11 @@ static WindowDesc _found_town_desc(
void ShowFoundTownWindow()
{
- if (_game_mode != GM_EDITOR) {
- if (_settings_game.economy.found_town == TF_FORBIDDEN) return;
- if (!Company::IsValidID(_local_company)) return;
- }
+ if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
AllocateWindowDescFront(&_found_town_desc, 0);
}
-/** List of buildable houses and house sets. */
-class GUIHouseList : protected SmallVector {
+class GUIHouseList : public SmallVector {
protected:
SmallVector house_sets; ///< list of house sets, each item points the first house of the set in the houses array
@@ -1242,112 +1234,82 @@ public:
*this->house_sets.Append() = 0; // terminator
}
- /**
- * 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
+ inline HouseID GetHouseAtOffset(uint house_set, uint 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
}
- /**
- * 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
+ uint NumHousesInHouseSet(uint house_set) const
{
- assert(house_set < (int)this->NumHouseSets());
+ 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 house_set < 0 ? 0 : this->house_sets[house_set + 1] - this->house_sets[house_set];
+ return this->house_sets[house_set + 1] - this->house_sets[house_set];
}
- /**
- * Find the house set of a given house.
- *
- * 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;
- }
+ 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
+ int FindHouseOffset(uint house_set, HouseID house) 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;
+ uint count = this->NumHousesInHouseSet(house_set);
+ for (uint i = 0; i < count; i++) {
+ if (this->GetHouseAtOffset(house_set, i) == house) return i;
}
+ return -1;
}
- /** (Re)build the list. */
+ 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;
+ }
+
+ /**
+ * Notify the sortlist that the rebuild is done
+ *
+ * @note This forces a resort
+ */
void Build()
{
/* collect items */
this->Clear();
- HouseZones zones = CurrentClimateHouseZones();
for (HouseID house = 0; house < NUM_HOUSES; house++) {
- if (IsHouseTypeAllowed(house, zones, _game_mode == GM_EDITOR).Succeeded()) *this->Append() = 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;
}
- this->Compact();
/* arrange items */
QSortT(this->Begin(), this->Length(), HouseSorter);
@@ -1368,121 +1330,85 @@ public:
}
};
-static struct {
- HouseID id;
- HouseVariant variant;
-}
-_cur_house = { INVALID_HOUSE_ID, HOUSE_NO_VARIANT }; ///< house selected in the house picker window
+static HouseID _cur_house = INVALID_HOUSE_ID; ///< house selected in the house picker window
/** The window used for building houses. */
class HousePickerWindow : public Window {
- friend void ShowBuildHousePicker();
-
protected:
- 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)
+ 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
- /**
- * Get the height of a single line in the list of house sets.
- * @return the height
- */
- inline uint GetLineHeight() const
+ void RestoreSelectedHouseIndex()
{
- return FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
+ this->house_set = 0;
+ this->house_offset = 0;
+
+ if (this->house_list.Length() == 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;
}
- /**
- * 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
+ void SelectHouseIntl(uint new_house_set, int new_house_offset)
{
- return _thd.window_class == WC_BUILD_HOUSE;
- }
-
- /**
- * 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);
+ 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, -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)
+ * @param new_house_set index of the house set
+ * @param new_house_offset offset of the house
*/
- void SelectOtherHouse(int new_house_set, int new_house_offset, int new_house_variant, int clicked)
+ void SelectOtherHouse(uint new_house_set, int new_house_offset)
{
- 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;
- }
+ 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);
- /* 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
- }
+ SelectHouseIntl(new_house_set, new_house_offset);
NWidgetMatrix *matrix = this->GetWidget(WID_HP_HOUSE_SELECT_MATRIX);
- matrix->SetCount(this->house_list.NumHousesInHouseSet(new_house_set));
- matrix->SetClicked(clicked > 0 ? new_house_offset : -1);
-
- this->GetWidget(WID_HP_PREV_VARIANT_SEL)->SetDisplayedPlane(hs->num_variants > 1 ? 0 : SZSP_NONE);
- this->GetWidget(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);
-
+ matrix->SetCount(this->house_list.NumHousesInHouseSet(this->house_set));
+ matrix->SetClicked(this->house_offset);
+ this->UpdateSelectSize();
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);
+ 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), tileselect_zone(HZB_END), tileselect_bad_land(false)
+ 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 */
@@ -1490,117 +1416,151 @@ public:
NWidgetMatrix *matrix = this->GetWidget(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
}
- ~HousePickerWindow()
- {
- DeleteWindowById(WC_SELECT_TOWN, 0);
- }
-
- virtual void OnInit()
+ virtual void OnInit() override
{
this->house_list.Build();
+ this->RestoreSelectedHouseIndex();
+ this->UpdateSelectSize();
- /* restore last house */
- this->SelectOtherHouse(-1, -1, -1, -1);
+ /* 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(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;
/* hide widgets if we have no houses to show */
- this->SetShaded(this->house_list.NumHouseSets() == 0);
+ this->SetShaded(this->house_list.Length() == 0);
- if (this->house_list.NumHouseSets() != 0) {
+ if (this->house_list.Length() != 0) {
/* show the list of house sets if we have at least 2 items to show */
this->GetWidget(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(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(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(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(int widget) const
{
- switch (widget) {
- case WID_HP_CAPTION:
- 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;
+ 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_NAME:
- SetDParam(0, GetHouseName(_cur_house.id, INVALID_TILE, _cur_house.variant));
- 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, i + 1);
+ }
+ break;
- case WID_HP_HISTORICAL_BUILDING:
- SetDParam(0, HouseSpec::Get(_cur_house.id)->extra_flags & BUILDING_IS_HISTORICAL ? STR_HOUSE_BUILD_HISTORICAL_BUILDING : STR_EMPTY);
- 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_POPULATION:
- SetDParam(0, HouseSpec::Get(_cur_house.id)->population);
- break;
+ case WID_HP_HOUSE_ACCEPTANCE:
+ SetDParamStr(0, "");
+ break;
- case WID_HP_HOUSE_ZONES: {
- 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_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_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;
+ 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: 1(center)/2/3/4/5(edge) */
+ SetDParam(2 * i + 1, i + 1);
+ }
+ break;
}
- break;
- case WID_HP_HOUSE_YEARS: {
- 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_YEAR_GOOD : STR_HOUSE_BUILD_YEAR_BAD);
- SetDParam(3, hs->max_year);
- break;
- }
-
- case WID_HP_HOUSE_ACCEPTANCE: {
- static char buff[DRAW_STRING_BUFFER] = "";
- char *str = buff;
- CargoArray cargo;
- uint32 dummy = 0;
- 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 */
- 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);
- str = GetString(str, str == buff ? STR_HOUSE_BUILD_CARGO_FIRST : STR_HOUSE_BUILD_CARGO_SEPARATED, lastof(buff));
+ 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;
}
- if (str == buff) GetString(buff, STR_JUST_NOTHING, lastof(buff));
- SetDParamStr(0, buff);
- break;
- }
- case WID_HP_HOUSE_SUPPLY: {
- CargoArray 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);
- break;
- }
+ case WID_HP_HOUSE_YEARS: {
+ const HouseSpec *hs = HouseSpec::Get(this->display_house);
+ SetDParam(0, hs->min_year <= _cur_year ? STR_HOUSE_BUILD_YEARS_GOOD_YEAR : STR_HOUSE_BUILD_YEARS_BAD_YEAR);
+ 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(3, hs->max_year);
+ break;
+ }
- default: break;
+ case WID_HP_HOUSE_ACCEPTANCE: {
+ static char buff[DRAW_STRING_BUFFER] = "";
+ char *str = buff;
+ CargoArray cargo;
+ uint32 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);
+ str = GetString(str, str == buff ? STR_HOUSE_BUILD_CARGO_FIRST : STR_HOUSE_BUILD_CARGO_SEPARATED, lastof(buff));
+ }
+ if (str == buff) GetString(buff, STR_JUST_NOTHING, lastof(buff));
+ SetDParamStr(0, buff);
+ break;
+ }
+
+ case WID_HP_HOUSE_SUPPLY: {
+ CargoArray cargo;
+ AddProducedHouseCargo(this->display_house, INVALID_TILE, cargo);
+ uint32 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;
+ }
}
}
@@ -1613,15 +1573,11 @@ public:
max_w = max(max_w, GetStringBoundingBox(this->house_list.GetNameOfHouseSet(i)).width);
}
size->width = max(size->width, max_w + padding.width);
- size->height = this->house_list.NumHouseSets() * this->GetLineHeight();
+ this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
+ size->height = this->house_list.NumHouseSets() * this->line_height;
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;
@@ -1632,20 +1588,25 @@ public:
case WID_HP_HOUSE_POPULATION:
SetDParam(0, 0);
- SetDParamMaxValue(0, UINT8_MAX);
- size->width = max(size->width, GetStringBoundingBox(STR_HOUSE_BUILD_HOUSE_POPULATION).width + padding.width);
+ /* max popultion is 255 - 3 digits */
+ size->width = 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 = 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_GOOD);
+ SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE);
dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE));
- 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);
+ 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;
@@ -1654,17 +1615,12 @@ public:
}
case WID_HP_HOUSE_YEARS: {
- 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;
+ 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;
@@ -1674,11 +1630,6 @@ 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:
@@ -1694,31 +1645,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++) {
- 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();
+ 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;
}
break;
}
case WID_HP_HOUSE_PREVIEW:
- DrawHouseImage(_cur_house.id, r.left, r.top, r.right, r.bottom, HIT_GUI_HOUSE_PREVIEW, _cur_house.variant);
+ 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->GetCurrentHouseSet(), GB(widget, 16, 16));
- int lowered = (house == _cur_house.id) ? 1 : 0;
+ HouseID house = this->house_list.GetHouseAtOffset(this->house_set, GB(widget, 16, 16));
+ int lowered = (house == _cur_house) ? 1 : 0;
DrawHouseImage(house,
- 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);
+ 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);
+ }
break;
}
}
@@ -1728,104 +1679,30 @@ public:
{
switch (GB(widget, 0, 16)) {
case WID_HP_HOUSE_SETS: {
- uint index = (uint)(pt.y - this->GetWidget(widget)->pos_y) / this->GetLineHeight();
- if (index < this->house_list.NumHouseSets()) {
- this->SelectOtherHouse(index, -1, -1, -1);
- }
+ uint index = (uint)(pt.y - this->GetWidget(widget)->pos_y) / this->line_height;
+ if (index < this->house_list.NumHouseSets() && index != this->house_set) this->SelectOtherHouse(index, 0);
break;
}
- 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);
+ this->SelectOtherHouse(this->house_set, GB(widget, 16, 16));
break;
}
}
- virtual void OnPlaceObject(Point pt, TileIndex tile)
+ virtual void OnPlaceObject(Point pt, TileIndex tile) override
{
- 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);
+ PlaceProc_House(tile);
}
- virtual void OnPlaceObjectAbort()
+ virtual void OnPlaceObjectAbort() override
{
- 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);
- }
+ this->house_offset = -1;
+ _cur_house = INVALID_HOUSE_ID;
+ NWidgetMatrix *matrix = this->GetWidget(WID_HP_HOUSE_SELECT_MATRIX);
+ matrix->SetClicked(-1);
+ this->UpdateSelectSize();
+ this->SetDirty();
}
};
@@ -1849,30 +1726,9 @@ static const NWidgetPart _nested_house_picker_widgets[] = {
SetMatrixDataTip(1, 1, STR_HOUSE_BUILD_HOUSESET_LIST_TOOLTIP),
EndContainer(),
EndContainer(),
- /* 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),
+ /* 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),
@@ -1883,8 +1739,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(5, 2, 2, 4), SetScrollbar(WID_HP_HOUSE_SELECT_SCROLL),
- NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_HP_HOUSE_SELECT),
+ 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(),
@@ -1916,12 +1772,11 @@ static WindowDesc _house_picker_desc(
/**
* Show our house picker.
+ * @param parent The toolbar window we're associated with.
*/
void ShowBuildHousePicker()
{
- if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
- HousePickerWindow *w = AllocateWindowDescFront(&_house_picker_desc, 0, true);
- if (w != NULL) w->SelectOtherHouse(-1, -1, -1, 1); // push the button
+ AllocateWindowDescFront(&_house_picker_desc, 0);
}
@@ -1941,21 +1796,6 @@ 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;
@@ -1963,7 +1803,8 @@ struct SelectTownWindow : Window {
/* Determine the widest string */
Dimension d = { 0, 0 };
for (uint i = 0; i < this->towns.Length(); i++) {
- d = maxdim(d, GetStringBoundingBox(this->GetTownString(i)));
+ SetDParam(0, this->towns[i]);
+ d = maxdim(d, GetStringBoundingBox(STR_SELECT_TOWN_LIST_ITEM));
}
resize->height = d.height;
@@ -1980,7 +1821,8 @@ 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++) {
- DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, this->GetTownString(i));
+ SetDParam(0, this->towns[i]);
+ DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SELECT_TOWN_LIST_ITEM);
y += this->resize.step_height;
}
}
@@ -2034,53 +1876,59 @@ 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.
-
- 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);
- }
-};
-
-/**
- * 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)
+static void PlaceProc_House(TileIndex tile)
{
- const bool deity = (_game_mode == GM_EDITOR);
- StringID error = STR_ERROR_MUST_FOUND_TOWN_FIRST;
+ if (_town_pool.items == 0) {
+ ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HOUSE_HERE, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO);
+ return;
+ }
+
+ 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;
const Town *t;
FOR_ALL_TOWNS(t) {
- CommandCost ret = CheckHouseDistanceFromTown(t, tile, deity);
- if (ret.Failed()) {
- if (error == STR_ERROR_MUST_FOUND_TOWN_FIRST) error = ret.GetErrorMessage();
- continue;
+ 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;
}
- 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) return CommandCost(error);
- TownsToJoinHouseToListSorter compare = { tile };
- std::sort(towns->Begin(), towns->End(), compare);
- return CommandCost();
+ 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);
+ }
}
diff --git a/src/town_gui.h b/src/town_gui.h
new file mode 100644
index 0000000000..3b22d68daf
--- /dev/null
+++ b/src/town_gui.h
@@ -0,0 +1,17 @@
+/* $Id$ */
+
+/*
+ * 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 .
+ */
+
+/** @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 */
diff --git a/src/widgets/terraform_widget.h b/src/widgets/terraform_widget.h
index 7f8a4c4d1b..67c9f09318 100644
--- a/src/widgets/terraform_widget.h
+++ b/src/widgets/terraform_widget.h
@@ -39,6 +39,7 @@ enum EditorTerraformToolbarWidgets {
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.
diff --git a/src/widgets/town_widget.h b/src/widgets/town_widget.h
index 54c38d8903..59412ee17d 100644
--- a/src/widgets/town_widget.h
+++ b/src/widgets/town_widget.h
@@ -62,13 +62,6 @@ enum TownFoundingWidgets {
WID_TF_LAYOUT_RANDOM, ///< Selection for a randomly chosen town layout.
};
-/** Widgets of the #SelectTownWindow class. */
-enum SelectTownWidgets {
- WID_ST_CAPTION, ///< Caption of the window.
- WID_ST_PANEL, ///< Main panel.
- WID_ST_SCROLLBAR, ///< Scrollbar of the panel.
-};
-
/** Widgets of the #HousePickerWindow class. */
enum HousePickerWidgets {
WID_HP_CAPTION,
@@ -79,10 +72,6 @@ enum HousePickerWidgets {
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_PREV_VARIANT_SEL, ///< Selection widget to show/hide the prev variant buttons.
- WID_HP_PREV_VARIANT, ///< Prev variant button.
- WID_HP_NEXT_VARIANT_SEL, ///< Selection widget to show/hide the next variant buttons.
- WID_HP_NEXT_VARIANT, ///< Next variant button.
WID_HP_HOUSE_NAME, ///< House name display.
WID_HP_HISTORICAL_BUILDING, ///< "Historical building" label.
WID_HP_HOUSE_POPULATION, ///< House population display.
@@ -94,4 +83,11 @@ enum HousePickerWidgets {
WID_HP_HOUSE_SUPPLY, ///< Cargo supplied.
};
+/** Widgets of the #SelectTownWindow class. */
+enum SelectTownWidgets {
+ WID_ST_CAPTION, ///< Caption of the window.
+ WID_ST_PANEL, ///< Main panel.
+ WID_ST_SCROLLBAR, ///< Scrollbar of the panel.
+};
+
#endif /* WIDGETS_TOWN_WIDGET_H */