Import Picking and placing single houses in scenario editor patch
Minor whitespace fixes http://www.tt-forums.net/viewtopic.php?f=33&t=68894&view=unread#p1099696
This commit is contained in:
		
				
					committed by
					
						
						Jonathan G Rennison
					
				
			
			
				
	
			
			
			
						parent
						
							e6782df9ba
						
					
				
				
					commit
					19dcbb1cb9
				
			@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -50,6 +50,7 @@ CommandProc CmdRemoveSingleSignal;
 | 
			
		||||
CommandProc CmdTerraformLand;
 | 
			
		||||
 | 
			
		||||
CommandProc CmdBuildObject;
 | 
			
		||||
CommandProc CmdBuildHouse;
 | 
			
		||||
CommandProc CmdSellLandArea;
 | 
			
		||||
 | 
			
		||||
CommandProc CmdBuildTunnel;
 | 
			
		||||
@@ -220,6 +221,7 @@ static const Command _command_proc_table[] = {
 | 
			
		||||
	DEF_CMD(CmdRemoveSingleSignal,                      CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_SIGNALS
 | 
			
		||||
	DEF_CMD(CmdTerraformLand,           CMD_ALL_TILES | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_TERRAFORM_LAND
 | 
			
		||||
	DEF_CMD(CmdBuildObject,              CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_OBJECT
 | 
			
		||||
	DEF_CMD(CmdBuildHouse,   CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_HOUSE
 | 
			
		||||
	DEF_CMD(CmdBuildTunnel,                 CMD_DEITY | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_TUNNEL
 | 
			
		||||
	DEF_CMD(CmdRemoveFromRailStation,                          0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_FROM_RAIL_STATION
 | 
			
		||||
	DEF_CMD(CmdConvertRail,                                    0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CONVERT_RAILD
 | 
			
		||||
 
 | 
			
		||||
@@ -187,6 +187,7 @@ enum Commands {
 | 
			
		||||
	CMD_REMOVE_SIGNALS,               ///< remove a signal
 | 
			
		||||
	CMD_TERRAFORM_LAND,               ///< terraform a tile
 | 
			
		||||
	CMD_BUILD_OBJECT,                 ///< build an object
 | 
			
		||||
	CMD_BUILD_HOUSE,                  ///< build a house
 | 
			
		||||
	CMD_BUILD_TUNNEL,                 ///< build a tunnel
 | 
			
		||||
 | 
			
		||||
	CMD_REMOVE_FROM_RAIL_STATION,     ///< remove a (rectangle of) tiles from a rail station
 | 
			
		||||
 
 | 
			
		||||
@@ -143,4 +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, 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 */
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -2486,6 +2487,36 @@ STR_OBJECT_BUILD_SIZE                                           :{BLACK}Size: {G
 | 
			
		||||
STR_OBJECT_CLASS_LTHS                                           :Lighthouses
 | 
			
		||||
STR_OBJECT_CLASS_TRNS                                           :Transmitters
 | 
			
		||||
 | 
			
		||||
#House construction window (for SE only)
 | 
			
		||||
STR_HOUSE_BUILD_CAPTION                                         :{WHITE}House Selection
 | 
			
		||||
STR_HOUSE_BUILD_CUSTOM_CAPTION                                  :{WHITE}{RAW_STRING}
 | 
			
		||||
STR_HOUSE_BUILD_HOUSESET_LIST_TOOLTIP                           :{BLACK}Select set of houses
 | 
			
		||||
STR_HOUSE_BUILD_SELECT_HOUSE_TOOLTIP                            :{BLACK}Select house to build
 | 
			
		||||
STR_HOUSE_BUILD_HOUSE_NAME                                      :{GOLD}{STRING1}
 | 
			
		||||
STR_HOUSE_BUILD_HISTORICAL_BUILDING                             :{GOLD}(historical building)
 | 
			
		||||
STR_HOUSE_BUILD_HOUSE_POPULATION                                :{BLACK}Population: {GOLD}{NUM}
 | 
			
		||||
STR_HOUSE_BUILD_HOUSE_ZONES                                     :{BLACK}House zones: {STRING1} {STRING1} {STRING1} {STRING1} {STRING1}
 | 
			
		||||
STR_HOUSE_BUILD_HOUSE_ZONE_DISABLED                             :{GRAY}{NUM}
 | 
			
		||||
STR_HOUSE_BUILD_HOUSE_ZONE_ENABLED                              :{GOLD}{NUM}
 | 
			
		||||
STR_HOUSE_BUILD_LANDSCAPE                                       :{BLACK}Landscape: {STRING}
 | 
			
		||||
STR_HOUSE_BUILD_LANDSCAPE_ABOVE_OR_BELOW_SNOWLINE               :{GOLD}above or below snowline
 | 
			
		||||
STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE                   :{GOLD}only above snowline
 | 
			
		||||
STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE                   :{GOLD}only below snowline
 | 
			
		||||
STR_HOUSE_BUILD_YEARS                                           :{BLACK}Years: {STRING1}{GOLD} - {STRING1}
 | 
			
		||||
STR_HOUSE_BUILD_YEARS_BAD_YEAR                                  :{RED}{NUM}
 | 
			
		||||
STR_HOUSE_BUILD_YEARS_GOOD_YEAR                                 :{GOLD}{NUM}
 | 
			
		||||
STR_HOUSE_BUILD_SUPPLIED_CARGO                                  :{BLACK}Supplies: {GOLD}{CARGO_LIST}
 | 
			
		||||
STR_HOUSE_BUILD_ACCEPTED_CARGO                                  :{BLACK}Accepts: {GOLD}{RAW_STRING}
 | 
			
		||||
STR_HOUSE_BUILD_CARGO_FIRST                                     :{STRING2}
 | 
			
		||||
STR_HOUSE_BUILD_CARGO_SEPARATED                                 :, {STRING2}
 | 
			
		||||
STR_HOUSE_BUILD_CARGO_VALUE_JUST_NAME                           :{1:STRING}
 | 
			
		||||
STR_HOUSE_BUILD_CARGO_VALUE_EIGHTS                              :({COMMA}/8 {STRING})
 | 
			
		||||
STR_BASIC_HOUSE_SET_NAME                                        :Basic houses
 | 
			
		||||
 | 
			
		||||
#Town select window (for SE only)
 | 
			
		||||
STR_SELECT_TOWN_CAPTION                                         :{WHITE}Select town
 | 
			
		||||
STR_SELECT_TOWN_LIST_ITEM                                       :{BLACK}{TOWN}
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
@@ -4166,6 +4197,7 @@ STR_ERROR_CAN_T_GENERATE_TOWN                                   :{WHITE}Can't bu
 | 
			
		||||
STR_ERROR_CAN_T_RENAME_TOWN                                     :{WHITE}Can't rename town...
 | 
			
		||||
STR_ERROR_CAN_T_FOUND_TOWN_HERE                                 :{WHITE}Can't found town here...
 | 
			
		||||
STR_ERROR_CAN_T_EXPAND_TOWN                                     :{WHITE}Can't expand town...
 | 
			
		||||
STR_ERROR_CAN_T_BUILD_HOUSE_HERE                                :{WHITE}Can't build house here...
 | 
			
		||||
STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB                          :{WHITE}... too close to edge of map
 | 
			
		||||
STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN                             :{WHITE}... too close to another town
 | 
			
		||||
STR_ERROR_TOO_MANY_TOWNS                                        :{WHITE}... too many towns
 | 
			
		||||
@@ -4174,6 +4206,15 @@ STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS                             :{WHITE}The town
 | 
			
		||||
STR_ERROR_ROAD_WORKS_IN_PROGRESS                                :{WHITE}Road works in progress
 | 
			
		||||
STR_ERROR_TOWN_CAN_T_DELETE                                     :{WHITE}Can't delete this town...{}A station or depot is referring to the town or a town owned tile can't be removed
 | 
			
		||||
STR_ERROR_STATUE_NO_SUITABLE_PLACE                              :{WHITE}... there is no suitable place for a statue in the centre of this town
 | 
			
		||||
STR_ERROR_BUILDING_NOT_ALLOWED_IN_THIS_TOWN_ZONE                :{WHITE}... not allowed in this town zone.
 | 
			
		||||
STR_ERROR_BUILDING_NOT_ALLOWED_ABOVE_SNOW_LINE                  :{WHITE}... not allowed above the snow line.
 | 
			
		||||
STR_ERROR_BUILDING_NOT_ALLOWED_BELOW_SNOW_LINE                  :{WHITE}... not allowed below the snow line.
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
#include "landscape.h"
 | 
			
		||||
#include "newgrf_house.h"
 | 
			
		||||
#include "newgrf_spritegroup.h"
 | 
			
		||||
#include "newgrf_text.h"
 | 
			
		||||
#include "newgrf_town.h"
 | 
			
		||||
#include "newgrf_sound.h"
 | 
			
		||||
#include "company_func.h"
 | 
			
		||||
@@ -26,6 +27,8 @@
 | 
			
		||||
 | 
			
		||||
#include "safeguards.h"
 | 
			
		||||
 | 
			
		||||
#include "table/strings.h"
 | 
			
		||||
 | 
			
		||||
static BuildingCounts<uint32> _building_counts;
 | 
			
		||||
static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX];
 | 
			
		||||
 | 
			
		||||
@@ -67,7 +70,7 @@ static const GRFFile *GetHouseSpecGrf(HouseID house_id)
 | 
			
		||||
/**
 | 
			
		||||
 * Construct a resolver for a house.
 | 
			
		||||
 * @param house_id House to query.
 | 
			
		||||
 * @param tile %Tile containing the 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.
 | 
			
		||||
@@ -79,13 +82,28 @@ static const GRFFile *GetHouseSpecGrf(HouseID house_id)
 | 
			
		||||
HouseResolverObject::HouseResolverObject(HouseID house_id, TileIndex tile, Town *town,
 | 
			
		||||
		CallbackID callback, uint32 param1, uint32 param2,
 | 
			
		||||
		bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers)
 | 
			
		||||
	: ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2),
 | 
			
		||||
	house_scope(*this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers),
 | 
			
		||||
	town_scope(*this, town, not_yet_constructed) // Don't access StorePSA if house is not yet constructed.
 | 
			
		||||
	: ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2)
 | 
			
		||||
{
 | 
			
		||||
	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 = (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);
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	this->root_spritegroup = HouseSpec::Get(house_id)->grf_prop.spritegroup[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* virtual */ HouseResolverObject::~HouseResolverObject()
 | 
			
		||||
{
 | 
			
		||||
	delete this->house_scope;
 | 
			
		||||
	delete this->town_scope;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid)
 | 
			
		||||
{
 | 
			
		||||
	/* Start from 1 because 0 means that no class has been assigned. */
 | 
			
		||||
@@ -435,29 +453,120 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI
 | 
			
		||||
	return UINT_MAX;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @note Used by the resolver to get values for feature 07 deterministic spritegroups.
 | 
			
		||||
 */
 | 
			
		||||
/* virtual */ uint32 FakeHouseScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
 | 
			
		||||
{
 | 
			
		||||
	switch (variable) {
 | 
			
		||||
		/* Construction stage. */
 | 
			
		||||
		case 0x40: return TOWN_HOUSE_COMPLETED;
 | 
			
		||||
 | 
			
		||||
		/* Building age. */
 | 
			
		||||
		case 0x41: return 0;
 | 
			
		||||
 | 
			
		||||
		/* Town zone */
 | 
			
		||||
		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 0;
 | 
			
		||||
 | 
			
		||||
		/* Whether the town is being created or just expanded. */
 | 
			
		||||
		case 0x45: return 0;
 | 
			
		||||
 | 
			
		||||
		/* Current animation frame. */
 | 
			
		||||
		case 0x46: return 0;
 | 
			
		||||
 | 
			
		||||
		/* Position of the house */
 | 
			
		||||
		case 0x47: return 0xFFFFFFFF;
 | 
			
		||||
 | 
			
		||||
		/* Building counts for old houses with id = parameter. */
 | 
			
		||||
		case 0x60: return 0;
 | 
			
		||||
 | 
			
		||||
		/* Building counts for new houses with id = parameter. */
 | 
			
		||||
		case 0x61: return 0;
 | 
			
		||||
 | 
			
		||||
		/* Land info for nearby tiles. */
 | 
			
		||||
		case 0x62: return 0;
 | 
			
		||||
 | 
			
		||||
		/* Current animation frame of nearby house tiles */
 | 
			
		||||
		case 0x63: return 0;
 | 
			
		||||
 | 
			
		||||
		/* Cargo acceptance history of nearby stations */
 | 
			
		||||
		case 0x64: return 0;
 | 
			
		||||
 | 
			
		||||
		/* Distance test for some house types */
 | 
			
		||||
		case 0x65: return 0;
 | 
			
		||||
 | 
			
		||||
		/* Class and ID of nearby house tile */
 | 
			
		||||
		case 0x66: return 0xFFFFFFFF;
 | 
			
		||||
 | 
			
		||||
		/* GRFID of nearby house tile */
 | 
			
		||||
		case 0x67: return 0xFFFFFFFF;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUG(grf, 1, "Unhandled house variable 0x%X", variable);
 | 
			
		||||
 | 
			
		||||
	*available = false;
 | 
			
		||||
	return UINT_MAX;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
	assert(IsValidTile(tile) && (not_yet_constructed || IsTileType(tile, MP_HOUSE)));
 | 
			
		||||
 | 
			
		||||
	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 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)
 | 
			
		||||
{
 | 
			
		||||
	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 = 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);
 | 
			
		||||
		} else {
 | 
			
		||||
			StringID ret = GetGRFStringID(hs->grf_prop.grffile->grfid, 0xD000 + callback_res);
 | 
			
		||||
			if (ret != STR_NULL && ret != STR_UNDEFINED) return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return hs->building_name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
		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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return hs->random_colour[TileHash2Bit(TileX(tile), TileY(tile))] + PALETTE_RECOLOUR_START;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte stage, HouseID house_id)
 | 
			
		||||
{
 | 
			
		||||
	const DrawTileSprites *dts = group->ProcessRegisters(&stage);
 | 
			
		||||
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house_id);
 | 
			
		||||
	PaletteID palette = hs->random_colour[TileHash2Bit(ti->x, ti->y)] + PALETTE_RECOLOUR_START;
 | 
			
		||||
	if (HasBit(hs->callback_mask, CBM_HOUSE_COLOUR)) {
 | 
			
		||||
		uint16 callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
 | 
			
		||||
		if (callback != CALLBACK_FAILED) {
 | 
			
		||||
			/* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
 | 
			
		||||
			palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	PaletteID palette = GetHouseColour(house_id, ti->tile);
 | 
			
		||||
 | 
			
		||||
	SpriteID image = dts->ground.sprite;
 | 
			
		||||
	PaletteID pal  = dts->ground.pal;
 | 
			
		||||
@@ -472,6 +581,26 @@ static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *grou
 | 
			
		||||
	DrawNewGRFTileSeq(ti, dts, TO_HOUSES, stage, palette);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void DrawTileLayoutInGUI(int x, int y, const TileLayoutSpriteGroup *group, HouseID house_id, bool ground)
 | 
			
		||||
{
 | 
			
		||||
	byte stage = TOWN_HOUSE_COMPLETED;
 | 
			
		||||
	const DrawTileSprites *dts = group->ProcessRegisters(&stage);
 | 
			
		||||
 | 
			
		||||
	PaletteID palette = GetHouseColour(house_id);
 | 
			
		||||
 | 
			
		||||
	if (ground) {
 | 
			
		||||
		PalSpriteID image = dts->ground;
 | 
			
		||||
		if (HasBit(image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) image.sprite += stage;
 | 
			
		||||
		if (HasBit(image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) image.pal += stage;
 | 
			
		||||
 | 
			
		||||
		if (GB(image.sprite, 0, SPRITE_WIDTH) != 0) {
 | 
			
		||||
			DrawSprite(image.sprite, GroundSpritePaletteTransform(image.sprite, image.pal, palette), x, y);
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		DrawNewGRFTileSeqInGUI(x, y, dts, stage, palette);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
 | 
			
		||||
{
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house_id);
 | 
			
		||||
@@ -498,6 +627,15 @@ void DrawNewHouseTile(TileInfo *ti, HouseID house_id)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DrawNewHouseTileInGUI(int x, int y, HouseID house_id, bool ground)
 | 
			
		||||
{
 | 
			
		||||
	HouseResolverObject object(house_id);
 | 
			
		||||
	const SpriteGroup *group = object.Resolve();
 | 
			
		||||
	if (group != NULL && group->type == SGT_TILELAYOUT) {
 | 
			
		||||
		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)
 | 
			
		||||
{
 | 
			
		||||
@@ -530,6 +668,26 @@ void AnimateNewHouseConstruction(TileIndex tile)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check if GRF allows a given house to be constructed (callback 17)
 | 
			
		||||
 * @param house_id house type
 | 
			
		||||
 * @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
 | 
			
		||||
 */
 | 
			
		||||
bool HouseAllowsConstruction(HouseID house_id, TileIndex tile, Town *t, byte random_bits)
 | 
			
		||||
{
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house_id);
 | 
			
		||||
	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 true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CanDeleteHouse(TileIndex tile)
 | 
			
		||||
{
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
 | 
			
		||||
 
 | 
			
		||||
@@ -36,20 +36,43 @@ struct HouseScopeResolver : public ScopeResolver {
 | 
			
		||||
	/* virtual */ void SetTriggers(int triggers) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fake scope resolver for nonexistent houses.
 | 
			
		||||
 *
 | 
			
		||||
 * The purpose of this class is to provide a house resolver for a given house type
 | 
			
		||||
 * but not an actual house instatntion. We need this when e.g. drawing houses in
 | 
			
		||||
 * GUI to keep backward compatibility with GRFs that were created before this
 | 
			
		||||
 * functionality. When querying house sprites, certain GRF may read various house
 | 
			
		||||
 * variables e.g. the town zone where the building is located or the XY coordinates.
 | 
			
		||||
 * Since the building doesn't exists we have no real values that we can return.
 | 
			
		||||
 * Instead of failing, this resolver will return fake values.
 | 
			
		||||
 */
 | 
			
		||||
struct FakeHouseScopeResolver : public ScopeResolver {
 | 
			
		||||
	HouseID house_id; ///< Type of house being queried.
 | 
			
		||||
 | 
			
		||||
	FakeHouseScopeResolver(ResolverObject &ro, HouseID house_id)
 | 
			
		||||
		: ScopeResolver(ro), house_id(house_id)
 | 
			
		||||
	{ }
 | 
			
		||||
 | 
			
		||||
	/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Resolver object to be used for houses (feature 07 spritegroups). */
 | 
			
		||||
struct HouseResolverObject : public ResolverObject {
 | 
			
		||||
	HouseScopeResolver house_scope;
 | 
			
		||||
	TownScopeResolver  town_scope;
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	/* virtual */ ~HouseResolverObject();
 | 
			
		||||
 | 
			
		||||
	/* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0)
 | 
			
		||||
	{
 | 
			
		||||
		switch (scope) {
 | 
			
		||||
			case VSG_SCOPE_SELF:   return &this->house_scope;
 | 
			
		||||
			case VSG_SCOPE_PARENT: return &this->town_scope;
 | 
			
		||||
			case VSG_SCOPE_SELF:   return this->house_scope;
 | 
			
		||||
			case VSG_SCOPE_PARENT: return this->town_scope;
 | 
			
		||||
			default: return ResolverObject::GetScope(scope, relative);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -80,13 +103,15 @@ 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, bool ground);
 | 
			
		||||
void AnimateNewHouseTile(TileIndex tile);
 | 
			
		||||
void AnimateNewHouseConstruction(TileIndex tile);
 | 
			
		||||
 | 
			
		||||
uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile,
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
bool HouseAllowsConstruction(HouseID house_id, TileIndex tile, Town *t, byte random_bits);
 | 
			
		||||
bool CanDeleteHouse(TileIndex tile);
 | 
			
		||||
 | 
			
		||||
bool NewHouseTileLoop(TileIndex tile);
 | 
			
		||||
 
 | 
			
		||||
@@ -162,6 +162,30 @@ TownScopeResolver::TownScopeResolver(ResolverObject &ro, Town *t, bool readonly)
 | 
			
		||||
	t->psa_list.push_back(psa);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* virtual */ uint32 FakeTownScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
 | 
			
		||||
{
 | 
			
		||||
	switch (variable) {
 | 
			
		||||
		/* Town index */
 | 
			
		||||
		case 0x41: return 0xFFFF;
 | 
			
		||||
 | 
			
		||||
		case 0x40: case 0x7C: case 0x80: case 0x81: case 0x82: case 0x83: case 0x8A: case 0x92:
 | 
			
		||||
		case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: case 0x98: case 0x99: case 0x9A:
 | 
			
		||||
		case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: case 0xA0: case 0xA1: case 0xA2:
 | 
			
		||||
		case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7: case 0xA8: case 0xA9: case 0xAA:
 | 
			
		||||
		case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xB2: case 0xB6: case 0xB9: case 0xBA:
 | 
			
		||||
		case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: case 0xC0: case 0xC1: case 0xC2:
 | 
			
		||||
		case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: case 0xC9: case 0xCA:
 | 
			
		||||
		case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: case 0xD0: case 0xD1: case 0xD2:
 | 
			
		||||
		case 0xD3: case 0xD4: case 0xD5:
 | 
			
		||||
			return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DEBUG(grf, 1, "Unhandled town variable 0x%X", variable);
 | 
			
		||||
 | 
			
		||||
	*available = false;
 | 
			
		||||
	return UINT_MAX;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Resolver for a town.
 | 
			
		||||
 * @param grffile NewGRF file associated with the town.
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,24 @@ struct TownScopeResolver : public ScopeResolver {
 | 
			
		||||
	virtual void StorePSA(uint reg, int32 value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fake scope resolver for nonexistent towns.
 | 
			
		||||
 *
 | 
			
		||||
 * The purpose of this class is to provide a house resolver for a given house type
 | 
			
		||||
 * but not an actual house instatntion. We need this when e.g. drawing houses in
 | 
			
		||||
 * GUI to keep backward compatibility with GRFs that were created before this
 | 
			
		||||
 * functionality. When querying house sprites, certain GRF may read various town
 | 
			
		||||
 * variables e.g. the population. Since the building doesn't exists and is not
 | 
			
		||||
 * bounded to any town we have no real values that we can return. Instead of
 | 
			
		||||
 * failing, this resolver will return fake values.
 | 
			
		||||
 */
 | 
			
		||||
struct FakeTownScopeResolver : public ScopeResolver {
 | 
			
		||||
	FakeTownScopeResolver(ResolverObject &ro) : ScopeResolver(ro)
 | 
			
		||||
	{ }
 | 
			
		||||
 | 
			
		||||
	virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Resolver of town properties. */
 | 
			
		||||
struct TownResolverObject : public ResolverObject {
 | 
			
		||||
	TownScopeResolver town_scope; ///< Scope resolver specific for towns.
 | 
			
		||||
 
 | 
			
		||||
@@ -68,6 +68,7 @@ void SQGSWindow_Register(Squirrel *engine)
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_COLOUR,                         "WC_COMPANY_COLOUR");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_MANAGER_FACE,                   "WC_COMPANY_MANAGER_FACE");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_STATION,                         "WC_SELECT_STATION");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_TOWN,                            "WC_SELECT_TOWN");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWS_WINDOW,                            "WC_NEWS_WINDOW");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_DIRECTORY,                         "WC_TOWN_DIRECTORY");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SUBSIDIES_LIST,                         "WC_SUBSIDIES_LIST");
 | 
			
		||||
@@ -90,6 +91,7 @@ void SQGSWindow_Register(Squirrel *engine)
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_VIEW,                          "WC_INDUSTRY_VIEW");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY,                                "WC_COMPANY");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_OBJECT,                           "WC_BUILD_OBJECT");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_HOUSE,                            "WC_BUILD_HOUSE");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_VEHICLE,                          "WC_BUILD_VEHICLE");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_BRIDGE,                           "WC_BUILD_BRIDGE");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_STATION,                          "WC_BUILD_STATION");
 | 
			
		||||
@@ -1139,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");
 | 
			
		||||
@@ -1249,6 +1252,26 @@ 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_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");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_SETS,                         "WID_HP_HOUSE_SETS");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_SELECT_MATRIX,                "WID_HP_HOUSE_SELECT_MATRIX");
 | 
			
		||||
	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_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");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_ZONES,                        "WID_HP_HOUSE_ZONES");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_LANDSCAPE,                    "WID_HP_HOUSE_LANDSCAPE");
 | 
			
		||||
	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_HP_HOUSE_LANDSCAPE_SEL,                "WID_HP_HOUSE_LANDSCAPE_SEL");
 | 
			
		||||
	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");
 | 
			
		||||
 
 | 
			
		||||
@@ -319,6 +319,12 @@ public:
 | 
			
		||||
		 */
 | 
			
		||||
		WC_SELECT_STATION                            = ::WC_SELECT_STATION,
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Select town (when placing a house); %Window numbers:
 | 
			
		||||
		 *   - 0 = #SelectTownWidgets
 | 
			
		||||
		 */
 | 
			
		||||
		WC_SELECT_TOWN                               = ::WC_SELECT_TOWN,
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * News window; %Window numbers:
 | 
			
		||||
		 *   - 0 = #NewsWidgets
 | 
			
		||||
@@ -453,6 +459,12 @@ public:
 | 
			
		||||
		 */
 | 
			
		||||
		WC_BUILD_OBJECT                              = ::WC_BUILD_OBJECT,
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Build house; %Window numbers:
 | 
			
		||||
		 *  - 0 = #BuildHouseWidgets
 | 
			
		||||
		*/
 | 
			
		||||
		WC_BUILD_HOUSE                               = ::WC_BUILD_HOUSE,
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 * Build vehicle; %Window numbers:
 | 
			
		||||
		 *   - #VehicleType = #BuildVehicleWidgets
 | 
			
		||||
@@ -2330,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.
 | 
			
		||||
@@ -2474,6 +2487,34 @@ public:
 | 
			
		||||
		WID_TF_LAYOUT_RANDOM                         = ::WID_TF_LAYOUT_RANDOM,                         ///< Selection for a randomly chosen town layout.
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	/** Widgets of the #HousePickerWindow class. */
 | 
			
		||||
	enum HousePickerWidgets {
 | 
			
		||||
		WID_HP_CAPTION                               = ::WID_HP_CAPTION,
 | 
			
		||||
		WID_HP_MAIN_PANEL_SEL                        = ::WID_HP_MAIN_PANEL_SEL,                        ///< Selection widget to show/hide the main panel.
 | 
			
		||||
		WID_HP_HOUSE_SETS_SEL                        = ::WID_HP_HOUSE_SETS_SEL,                        ///< Selection widget to show/hide the list of house sets.
 | 
			
		||||
		WID_HP_HOUSE_SETS                            = ::WID_HP_HOUSE_SETS,                            ///< List of available house sets.
 | 
			
		||||
		WID_HP_HOUSE_SELECT_MATRIX                   = ::WID_HP_HOUSE_SELECT_MATRIX,                   ///< Matrix with houses to select.
 | 
			
		||||
		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_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.
 | 
			
		||||
		WID_HP_HOUSE_ZONES                           = ::WID_HP_HOUSE_ZONES,                           ///< House zones display.
 | 
			
		||||
		WID_HP_HOUSE_LANDSCAPE                       = ::WID_HP_HOUSE_LANDSCAPE,                       ///< Information about house availability against the landscape.
 | 
			
		||||
		WID_HP_HOUSE_LANDSCAPE_SEL                   = ::WID_HP_HOUSE_LANDSCAPE_SEL,                   ///< Selection widget to show/hide the landscape info.
 | 
			
		||||
		WID_HP_HOUSE_YEARS                           = ::WID_HP_HOUSE_YEARS,                           ///< Years display.
 | 
			
		||||
		WID_HP_HOUSE_ACCEPTANCE                      = ::WID_HP_HOUSE_ACCEPTANCE,                      ///< Cargo accepted.
 | 
			
		||||
		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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -233,6 +233,10 @@ namespace SQConvert {
 | 
			
		||||
	template <> inline int Return<ScriptWindow::TownViewWidgets>(HSQUIRRELVM vm, ScriptWindow::TownViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
 | 
			
		||||
	template <> inline ScriptWindow::TownFoundingWidgets GetParam(ForceType<ScriptWindow::TownFoundingWidgets>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownFoundingWidgets)tmp; }
 | 
			
		||||
	template <> inline int Return<ScriptWindow::TownFoundingWidgets>(HSQUIRRELVM vm, ScriptWindow::TownFoundingWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
 | 
			
		||||
	template <> inline ScriptWindow::HousePickerWidgets GetParam(ForceType<ScriptWindow::HousePickerWidgets>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::HousePickerWidgets)tmp; }
 | 
			
		||||
	template <> inline int Return<ScriptWindow::HousePickerWidgets>(HSQUIRRELVM vm, ScriptWindow::HousePickerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
 | 
			
		||||
	template <> inline ScriptWindow::SelectTownWidgets GetParam(ForceType<ScriptWindow::SelectTownWidgets>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectTownWidgets)tmp; }
 | 
			
		||||
	template <> inline int Return<ScriptWindow::SelectTownWidgets>(HSQUIRRELVM vm, ScriptWindow::SelectTownWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
 | 
			
		||||
	template <> inline ScriptWindow::TransparencyToolbarWidgets GetParam(ForceType<ScriptWindow::TransparencyToolbarWidgets>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TransparencyToolbarWidgets)tmp; }
 | 
			
		||||
	template <> inline int Return<ScriptWindow::TransparencyToolbarWidgets>(HSQUIRRELVM vm, ScriptWindow::TransparencyToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; }
 | 
			
		||||
	template <> inline ScriptWindow::BuildTreesWidgets GetParam(ForceType<ScriptWindow::BuildTreesWidgets>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildTreesWidgets)tmp; }
 | 
			
		||||
 
 | 
			
		||||
@@ -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_IMGBTN, 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,13 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
 | 
			
		||||
				ShowBuildObjectPicker();
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
				case WID_ETT_PLACE_HOUSE: // Place house button
 | 
			
		||||
				if (HandlePlacePushButton(this, WID_ETT_PLACE_HOUSE, SPR_CURSOR_TOWN, HT_RECT)) {
 | 
			
		||||
					ShowBuildHousePicker(this);
 | 
			
		||||
					this->last_user_action = widget;
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case WID_ETT_INCREASE_SIZE:
 | 
			
		||||
			case WID_ETT_DECREASE_SIZE: { // Increase/Decrease terraform size
 | 
			
		||||
				int size = (widget == WID_ETT_INCREASE_SIZE) ? 1 : -1;
 | 
			
		||||
@@ -674,6 +685,10 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
 | 
			
		||||
				VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_DESERT);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case WID_ETT_PLACE_HOUSE: // Place house button
 | 
			
		||||
				PlaceProc_House(tile);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			default: NOT_REACHED();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -705,6 +720,8 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
 | 
			
		||||
		this->RaiseButtons();
 | 
			
		||||
		this->SetDirty();
 | 
			
		||||
		DeleteWindowById(WC_BUILD_OBJECT, 0);
 | 
			
		||||
		DeleteWindowById(WC_BUILD_HOUSE, 0);
 | 
			
		||||
		DeleteWindowById(WC_SELECT_STATION, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static HotkeyList hotkeys;
 | 
			
		||||
@@ -731,6 +748,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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -188,6 +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);
 | 
			
		||||
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile);
 | 
			
		||||
void SetTownRatingTestMode(bool mode);
 | 
			
		||||
uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										634
									
								
								src/town_cmd.cpp
									
									
									
									
									
								
							
							
						
						
									
										634
									
								
								src/town_cmd.cpp
									
									
									
									
									
								
							@@ -25,7 +25,6 @@
 | 
			
		||||
#include "genworld.h"
 | 
			
		||||
#include "newgrf_debug.h"
 | 
			
		||||
#include "newgrf_house.h"
 | 
			
		||||
#include "newgrf_text.h"
 | 
			
		||||
#include "autoslope.h"
 | 
			
		||||
#include "tunnelbridge_map.h"
 | 
			
		||||
#include "strings_func.h"
 | 
			
		||||
@@ -46,6 +45,7 @@
 | 
			
		||||
#include "object_base.h"
 | 
			
		||||
#include "ai/ai.hpp"
 | 
			
		||||
#include "game/game.hpp"
 | 
			
		||||
#include "zoom_func.h"
 | 
			
		||||
 | 
			
		||||
#include "table/strings.h"
 | 
			
		||||
#include "table/town_land.h"
 | 
			
		||||
@@ -189,6 +189,11 @@ static void TownDrawHouseLift(const TileInfo *ti)
 | 
			
		||||
	AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void DrawHouseLiftInGUI(int x, int y)
 | 
			
		||||
{
 | 
			
		||||
	DrawSprite(SPR_LIFT, PAL_NONE, x - 18, y + 7);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef void TownDrawTileProc(const TileInfo *ti);
 | 
			
		||||
static TownDrawTileProc * const _town_draw_tile_procs[1] = {
 | 
			
		||||
	TownDrawHouseLift
 | 
			
		||||
@@ -258,6 +263,85 @@ static void DrawTile_Town(TileInfo *ti)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void DrawOldHouseTileInGUI(int x, int y, HouseID house_id, bool ground)
 | 
			
		||||
{
 | 
			
		||||
	/* Retrieve pointer to the draw town tile struct */
 | 
			
		||||
	const DrawBuildingsTileStruct *dcts = &_town_draw_tile_data[house_id << 4 | TOWN_HOUSE_COMPLETED];
 | 
			
		||||
	if (ground) {
 | 
			
		||||
		/* Draw the ground sprite */
 | 
			
		||||
		DrawSprite(dcts->ground.sprite, dcts->ground.pal, x, y);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Add a house on top of the ground? */
 | 
			
		||||
		if (dcts->building.sprite != 0) {
 | 
			
		||||
			DrawSprite(dcts->building.sprite, dcts->building.pal, x + dcts->subtile_x, y + dcts->subtile_y);
 | 
			
		||||
		}
 | 
			
		||||
		/* Draw the lift */
 | 
			
		||||
		if (dcts->draw_proc == 1) DrawHouseLiftInGUI(x, y);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Draw image of a house. Image will be centered between the \c left and the \c right and verticaly aligned to the \c bottom.
 | 
			
		||||
 *
 | 
			
		||||
 * @param house_id house type
 | 
			
		||||
 * @param left left bound of the drawing area
 | 
			
		||||
 * @param top top bound of the drawing area
 | 
			
		||||
 * @param right right bound of the drawing area
 | 
			
		||||
 * @param bottom bottom bound of the drawing area
 | 
			
		||||
 */
 | 
			
		||||
void DrawHouseImage(HouseID house_id, int left, int top, int right, int bottom)
 | 
			
		||||
{
 | 
			
		||||
	DrawPixelInfo tmp_dpi;
 | 
			
		||||
	if (!FillDrawPixelInfo(&tmp_dpi, left, top, right - left + 1, bottom - top + 1)) return;
 | 
			
		||||
	DrawPixelInfo *old_dpi = _cur_dpi;
 | 
			
		||||
	_cur_dpi = &tmp_dpi;
 | 
			
		||||
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house_id);
 | 
			
		||||
 | 
			
		||||
	/* sprites are relative to the topmost pixel of the ground tile */
 | 
			
		||||
	uint x = (right - left + 1) / 2;
 | 
			
		||||
	uint y = bottom - top + 1 - 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) {
 | 
			
		||||
		/* Houses don't necessarily need new graphics. If they don't have a
 | 
			
		||||
		 * spritegroup associated with them, then the sprite for the substitute
 | 
			
		||||
		 * house id is drawn instead. */
 | 
			
		||||
		if (hs->grf_prop.spritegroup[0] != NULL) {
 | 
			
		||||
			new_house = true;
 | 
			
		||||
		} else {
 | 
			
		||||
			house_id = hs->grf_prop.subst_id;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint num_row = (hs->building_flags & BUILDING_2_TILES_X) ? 2 : 1;
 | 
			
		||||
	uint num_col = (hs->building_flags & BUILDING_2_TILES_Y) ? 2 : 1;
 | 
			
		||||
 | 
			
		||||
	for (bool ground = true; ; ground = !ground) {
 | 
			
		||||
		HouseID hid = house_id;
 | 
			
		||||
		for (uint row = 0; row < num_row; row++) {
 | 
			
		||||
			for (uint col = 0; col < num_col; col++) {
 | 
			
		||||
				Point offset = RemapCoords(row * TILE_SIZE, col * TILE_SIZE, 0); // offset for current tile
 | 
			
		||||
				offset.x = UnScaleByZoom(offset.x, ZOOM_LVL_GUI);
 | 
			
		||||
				offset.y = UnScaleByZoom(offset.y, ZOOM_LVL_GUI);
 | 
			
		||||
				if (new_house) {
 | 
			
		||||
					DrawNewHouseTileInGUI(x + offset.x, y + offset.y, hid, ground);
 | 
			
		||||
				} else {
 | 
			
		||||
					DrawOldHouseTileInGUI(x + offset.x, y + offset.y, hid, ground);
 | 
			
		||||
				}
 | 
			
		||||
				hid++;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if (!ground) break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_cur_dpi = old_dpi;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int GetSlopePixelZ_Town(TileIndex tile, uint x, uint y)
 | 
			
		||||
{
 | 
			
		||||
	return GetTileMaxPixelZ(tile);
 | 
			
		||||
@@ -574,13 +658,12 @@ static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags)
 | 
			
		||||
	return cost;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void AddProducedCargo_Town(TileIndex tile, CargoArray &produced)
 | 
			
		||||
void AddProducedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &produced)
 | 
			
		||||
{
 | 
			
		||||
	HouseID house_id = GetHouseType(tile);
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house_id);
 | 
			
		||||
	Town *t = Town::GetByTile(tile);
 | 
			
		||||
 | 
			
		||||
	if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) {
 | 
			
		||||
		Town *t = (tile == INVALID_TILE) ? NULL : Town::GetByTile(tile);
 | 
			
		||||
		for (uint i = 0; i < 256; i++) {
 | 
			
		||||
			uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile);
 | 
			
		||||
 | 
			
		||||
@@ -601,6 +684,11 @@ static void AddProducedCargo_Town(TileIndex tile, CargoArray &produced)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void AddProducedCargo_Town(TileIndex tile, CargoArray &produced)
 | 
			
		||||
{
 | 
			
		||||
	AddProducedHouseCargo(GetHouseType(tile), tile, produced);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void AddAcceptedCargoSetMask(CargoID cargo, uint amount, CargoArray &acceptance, uint32 *always_accepted)
 | 
			
		||||
{
 | 
			
		||||
	if (cargo == CT_INVALID || amount == 0) return;
 | 
			
		||||
@@ -608,9 +696,10 @@ static inline void AddAcceptedCargoSetMask(CargoID cargo, uint amount, CargoArra
 | 
			
		||||
	SetBit(*always_accepted, cargo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void AddAcceptedCargo_Town(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
 | 
			
		||||
void AddAcceptedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
 | 
			
		||||
{
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house_id);
 | 
			
		||||
	Town *t = (tile == INVALID_TILE) ? NULL : Town::GetByTile(tile);
 | 
			
		||||
	CargoID accepts[3];
 | 
			
		||||
 | 
			
		||||
	/* Set the initial accepted cargo types */
 | 
			
		||||
@@ -620,7 +709,7 @@ static void AddAcceptedCargo_Town(TileIndex tile, CargoArray &acceptance, uint32
 | 
			
		||||
 | 
			
		||||
	/* Check for custom accepted cargo types */
 | 
			
		||||
	if (HasBit(hs->callback_mask, CBM_HOUSE_ACCEPT_CARGO)) {
 | 
			
		||||
		uint16 callback = GetHouseCallback(CBID_HOUSE_ACCEPT_CARGO, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
 | 
			
		||||
		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);
 | 
			
		||||
@@ -631,7 +720,7 @@ static void AddAcceptedCargo_Town(TileIndex tile, CargoArray &acceptance, uint32
 | 
			
		||||
 | 
			
		||||
	/* Check for custom cargo acceptance */
 | 
			
		||||
	if (HasBit(hs->callback_mask, CBM_HOUSE_CARGO_ACCEPTANCE)) {
 | 
			
		||||
		uint16 callback = GetHouseCallback(CBID_HOUSE_CARGO_ACCEPTANCE, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile);
 | 
			
		||||
		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);
 | 
			
		||||
@@ -651,31 +740,23 @@ static void AddAcceptedCargo_Town(TileIndex tile, CargoArray &acceptance, uint32
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void AddAcceptedCargo_Town(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted)
 | 
			
		||||
{
 | 
			
		||||
	AddAcceptedHouseCargo(GetHouseType(tile), tile, acceptance, always_accepted);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void GetTileDesc_Town(TileIndex tile, TileDesc *td)
 | 
			
		||||
{
 | 
			
		||||
	const HouseID house = GetHouseType(tile);
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house);
 | 
			
		||||
	bool house_completed = IsHouseCompleted(tile);
 | 
			
		||||
 | 
			
		||||
	td->str = hs->building_name;
 | 
			
		||||
	td->str = GetHouseName(house, tile);
 | 
			
		||||
 | 
			
		||||
	uint16 callback_res = GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, house_completed ? 1 : 0, 0, house, Town::GetByTile(tile), 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);
 | 
			
		||||
		} else {
 | 
			
		||||
			StringID new_name = GetGRFStringID(hs->grf_prop.grffile->grfid, 0xD000 + callback_res);
 | 
			
		||||
			if (new_name != STR_NULL && new_name != STR_UNDEFINED) {
 | 
			
		||||
				td->str = new_name;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!house_completed) {
 | 
			
		||||
	if (!IsHouseCompleted(tile)) {
 | 
			
		||||
		SetDParamX(td->dparam, 0, td->str);
 | 
			
		||||
		td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house);
 | 
			
		||||
	if (hs->grf_prop.grffile != NULL) {
 | 
			
		||||
		const GRFConfig *gc = GetGRFConfig(hs->grf_prop.grffile->grfid);
 | 
			
		||||
		td->grf = gc->GetName();
 | 
			
		||||
@@ -1992,17 +2073,21 @@ bool GenerateTowns(TownLayout layout)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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
 | 
			
		||||
 * @return the bit position of the given zone, as defined in HouseZones
 | 
			
		||||
 *
 | 
			
		||||
 * @see GetTownRadiusGroup
 | 
			
		||||
 */
 | 
			
		||||
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile)
 | 
			
		||||
HouseZonesBits TryGetTownRadiusGroup(const Town *t, TileIndex tile)
 | 
			
		||||
{
 | 
			
		||||
	uint dist = DistanceSquare(tile, t->xy);
 | 
			
		||||
 | 
			
		||||
	if (t->fund_buildings_months && dist <= 25) return HZB_TOWN_CENTRE;
 | 
			
		||||
 | 
			
		||||
	HouseZonesBits smallest = HZB_TOWN_EDGE;
 | 
			
		||||
	HouseZonesBits smallest = HZB_END;
 | 
			
		||||
	for (HouseZonesBits i = HZB_BEGIN; i < HZB_END; i++) {
 | 
			
		||||
		if (dist < t->cache.squared_town_zone_radius[i]) smallest = i;
 | 
			
		||||
	}
 | 
			
		||||
@@ -2010,6 +2095,22 @@ HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile)
 | 
			
		||||
	return smallest;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Returns the bit corresponding to the town zone of the specified tile.
 | 
			
		||||
 * 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
 | 
			
		||||
 * @return the bit position of the given zone, as defined in HouseZones
 | 
			
		||||
 *
 | 
			
		||||
 * @see TryGetTownRadiusGroup
 | 
			
		||||
 */
 | 
			
		||||
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile)
 | 
			
		||||
{
 | 
			
		||||
	HouseZonesBits ret = TryGetTownRadiusGroup(t, tile);
 | 
			
		||||
	return ret != HZB_END ? ret : HZB_TOWN_EDGE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Clears tile and builds a house or house part.
 | 
			
		||||
 * @param tile tile index
 | 
			
		||||
@@ -2061,184 +2162,307 @@ 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 true iff house can be built here
 | 
			
		||||
 * @return success if house can be built here, error message otherwise
 | 
			
		||||
 */
 | 
			
		||||
static inline bool CanBuildHouseHere(TileIndex tile, TownID town, bool noslope)
 | 
			
		||||
static inline CommandCost CanBuildHouseHere(TileIndex tile, TownID town, bool noslope)
 | 
			
		||||
{
 | 
			
		||||
	/* cannot build on these slopes... */
 | 
			
		||||
	Slope slope = GetTileSlope(tile);
 | 
			
		||||
	if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false;
 | 
			
		||||
 | 
			
		||||
	/* building under a bridge? */
 | 
			
		||||
	if (IsBridgeAbove(tile)) return false;
 | 
			
		||||
 | 
			
		||||
	/* do not try to build over house owned by another town */
 | 
			
		||||
	if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) != town) return false;
 | 
			
		||||
 | 
			
		||||
	/* can we clear the land? */
 | 
			
		||||
	return DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 true iff house can be built here
 | 
			
		||||
 * @see CanBuildHouseHere()
 | 
			
		||||
 */
 | 
			
		||||
static inline bool CheckBuildHouseSameZ(TileIndex tile, TownID town, int z, bool noslope)
 | 
			
		||||
{
 | 
			
		||||
	if (!CanBuildHouseHere(tile, town, noslope)) return false;
 | 
			
		||||
 | 
			
		||||
	/* if building on slopes is allowed, there will be flattening foundation (to tile max z) */
 | 
			
		||||
	if (GetTileMaxZ(tile) != z) return false;
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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)) return false;
 | 
			
		||||
 | 
			
		||||
	for (DiagDirection d = DIAGDIR_SE; d < DIAGDIR_END; d++) {
 | 
			
		||||
		tile += TileOffsByDiagDir(d);
 | 
			
		||||
		if (!CheckBuildHouseSameZ(tile, town, z, noslope)) return false;
 | 
			
		||||
	if (noslope) {
 | 
			
		||||
		if (!IsTileFlat(tile)) return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (IsSteepSlope(GetTileSlope(tile))) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
	/* building under a bridge? */
 | 
			
		||||
	if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
 | 
			
		||||
 | 
			
		||||
	/* can we clear the land? */
 | 
			
		||||
	CommandCost ret = DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR);
 | 
			
		||||
	if (ret.Failed()) return ret;
 | 
			
		||||
 | 
			
		||||
	/* do not try to build over house owned by another town */
 | 
			
		||||
	if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) != town) return CMD_ERROR;
 | 
			
		||||
 | 
			
		||||
	return CommandCost();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Checks if a house can be built here. Important is slope, bridge above
 | 
			
		||||
 * and ability to clear the land.
 | 
			
		||||
 *
 | 
			
		||||
 * @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
 | 
			
		||||
 */
 | 
			
		||||
static inline CommandCost CanBuildHouseHere(const TileArea &ta, TownID town, int maxz, bool noslope)
 | 
			
		||||
{
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CommandCost();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 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 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);
 | 
			
		||||
 | 
			
		||||
	/* 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(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(STR_ERROR_TOO_MANY_HOUSE_TYPES);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CommandCost();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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
 | 
			
		||||
 * 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 inline bool TownLayoutAllows2x2HouseHere(Town *t, TileIndex tile)
 | 
			
		||||
static TileIndex FindPlaceForTownHouseAroundTile(TileIndex tile, Town *t, HouseID house)
 | 
			
		||||
{
 | 
			
		||||
	/* Allow towns everywhere when we don't build roads */
 | 
			
		||||
	if (!_settings_game.economy.allow_town_roads && !_generating_world) return true;
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house);
 | 
			
		||||
	bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0;
 | 
			
		||||
 | 
			
		||||
	/* 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;
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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
 | 
			
		||||
 * Check if a given house can be built in a given town.
 | 
			
		||||
 * @param house house type
 | 
			
		||||
 * @param t the town
 | 
			
		||||
 * @return success if house can be built, error message otherwise
 | 
			
		||||
 */
 | 
			
		||||
static bool CheckTownBuild2House(TileIndex *tile, Town *t, int maxz, bool noslope, DiagDirection second)
 | 
			
		||||
static CommandCost CheckCanBuildHouse(HouseID house, const Town *t)
 | 
			
		||||
{
 | 
			
		||||
	/* 'tile' is already checked in BuildTownHouse() - CanBuildHouseHere() and slope test */
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house);
 | 
			
		||||
 | 
			
		||||
	TileIndex tile2 = *tile + TileOffsByDiagDir(second);
 | 
			
		||||
	if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) return true;
 | 
			
		||||
 | 
			
		||||
	tile2 = *tile + TileOffsByDiagDir(ReverseDiagDir(second));
 | 
			
		||||
	if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) {
 | 
			
		||||
		*tile = tile2;
 | 
			
		||||
		return true;
 | 
			
		||||
	if (_loaded_newgrf_features.has_newhouses && !_generating_world &&
 | 
			
		||||
			_game_mode != GM_EDITOR && (hs->extra_flags & BUILDING_IS_HISTORICAL) != 0) {
 | 
			
		||||
		return CMD_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
	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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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?
 | 
			
		||||
 * Really build a house.
 | 
			
		||||
 * @param t town to build house in
 | 
			
		||||
 * @param tile house location
 | 
			
		||||
 * @param house house type
 | 
			
		||||
 * @param random_bits random bits for the house
 | 
			
		||||
 */
 | 
			
		||||
static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, int maxz, bool noslope)
 | 
			
		||||
static void DoBuildHouse(Town *t, TileIndex tile, HouseID house, byte random_bits)
 | 
			
		||||
{
 | 
			
		||||
	TileIndex tile2 = *tile;
 | 
			
		||||
	t->cache.num_houses++;
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
	const HouseSpec *hs = HouseSpec::Get(house);
 | 
			
		||||
 | 
			
		||||
	/* Special houses that there can be only one of. */
 | 
			
		||||
	if (hs->building_flags & BUILDING_IS_CHURCH) {
 | 
			
		||||
		SetBit(t->flags, TOWN_HAS_CHURCH);
 | 
			
		||||
	} else if (hs->building_flags & BUILDING_IS_STADIUM) {
 | 
			
		||||
		SetBit(t->flags, TOWN_HAS_STADIUM);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	byte construction_counter = 0;
 | 
			
		||||
	byte construction_stage = 0;
 | 
			
		||||
 | 
			
		||||
	if (_generating_world || _game_mode == GM_EDITOR) {
 | 
			
		||||
		uint32 r = Random();
 | 
			
		||||
 | 
			
		||||
		construction_stage = TOWN_HOUSE_COMPLETED;
 | 
			
		||||
		if (Chance16(1, 7)) construction_stage = GB(r, 0, 2);
 | 
			
		||||
 | 
			
		||||
		if (construction_stage == TOWN_HOUSE_COMPLETED) {
 | 
			
		||||
			ChangePopulation(t, hs->population);
 | 
			
		||||
		} else {
 | 
			
		||||
			construction_counter = GB(r, 2, 2);
 | 
			
		||||
		}
 | 
			
		||||
		if (d == DIAGDIR_END) break;
 | 
			
		||||
		tile2 += TileOffsByDiagDir(ReverseDiagDir(d)); // go clockwise
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
	MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits);
 | 
			
		||||
	UpdateTownRadius(t);
 | 
			
		||||
	UpdateTownCargoes(t, tile);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Place a custom house
 | 
			
		||||
 * @param tile tile where the house will be located
 | 
			
		||||
 * @param flags flags for the command
 | 
			
		||||
 * @param p1 \n
 | 
			
		||||
 *    bits  0..15 - the HouseID of the house \n
 | 
			
		||||
 *    bits 16..31 - the TownID of the town \n
 | 
			
		||||
 * @param p2 \n
 | 
			
		||||
 *    bits  0..7  - random bits \n
 | 
			
		||||
 * @param text unused
 | 
			
		||||
 * @return the cost of this operation or an error
 | 
			
		||||
 */
 | 
			
		||||
CommandCost CmdBuildHouse(TileIndex tile, DoCommandFlag flags, uint32 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::Get(GB(p1, 16, 16));
 | 
			
		||||
	if (t == NULL) return CMD_ERROR;
 | 
			
		||||
	byte random_bits = GB(p2, 0, 8);
 | 
			
		||||
 | 
			
		||||
	int max_z = GetTileMaxZ(tile);
 | 
			
		||||
	bool above_snowline = (_settings_game.game_creation.landscape == LT_ARCTIC) && (max_z > HighestSnowLine());
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
	/* Check if GRF allows this house */
 | 
			
		||||
	if (!HouseAllowsConstruction(house, tile, t, random_bits)) return_cmd_error(STR_ERROR_BUILDING_NOT_ALLOWED);
 | 
			
		||||
 | 
			
		||||
	if (flags & DC_EXEC) DoBuildHouse(t, tile, house, random_bits);
 | 
			
		||||
	return CommandCost();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tries to build a house at this tile
 | 
			
		||||
@@ -2249,23 +2473,13 @@ static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, int maxz, bool nosl
 | 
			
		||||
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)) return false;
 | 
			
		||||
	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 */
 | 
			
		||||
	HouseZonesBits rad = GetTownRadiusGroup(t, tile);
 | 
			
		||||
 | 
			
		||||
	/* Above snow? */
 | 
			
		||||
	int land = _settings_game.game_creation.landscape;
 | 
			
		||||
	if (land == LT_ARCTIC && maxz > HighestSnowLine()) land = -1;
 | 
			
		||||
 | 
			
		||||
	uint bitmask = (1 << rad) + (1 << (land + 12));
 | 
			
		||||
	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
 | 
			
		||||
@@ -2277,22 +2491,11 @@ 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++) {
 | 
			
		||||
		const HouseSpec *hs = HouseSpec::Get(i);
 | 
			
		||||
 | 
			
		||||
		/* Verify that the candidate house spec matches the current tile status */
 | 
			
		||||
		if ((~hs->building_availability & bitmask) != 0 || !hs->enabled || hs->grf_prop.override != INVALID_HOUSE_ID) continue;
 | 
			
		||||
 | 
			
		||||
		/* 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) continue;
 | 
			
		||||
		} else {
 | 
			
		||||
			/* If the house has no class, check id_count instead */
 | 
			
		||||
			if (t->cache.building_counts.id_count[i] == UINT16_MAX) 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 ? hs->probability : 1);
 | 
			
		||||
		uint cur_prob = (_loaded_newgrf_features.has_newhouses ? HouseSpec::Get(i)->probability : 1);
 | 
			
		||||
		probability_max += cur_prob;
 | 
			
		||||
		probs[num] = cur_prob;
 | 
			
		||||
		houses[num++] = (HouseID)i;
 | 
			
		||||
@@ -2323,73 +2526,18 @@ static bool BuildTownHouse(Town *t, TileIndex tile)
 | 
			
		||||
		houses[i] = houses[num];
 | 
			
		||||
		probs[i] = probs[num];
 | 
			
		||||
 | 
			
		||||
		const HouseSpec *hs = HouseSpec::Get(house);
 | 
			
		||||
		CommandCost ret = CheckCanBuildHouse(house, t);
 | 
			
		||||
		if (ret.Failed()) continue;
 | 
			
		||||
 | 
			
		||||
		if (_loaded_newgrf_features.has_newhouses && !_generating_world &&
 | 
			
		||||
				_game_mode != GM_EDITOR && (hs->extra_flags & BUILDING_IS_HISTORICAL) != 0) {
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (_cur_year < hs->min_year || _cur_year > hs->max_year) continue;
 | 
			
		||||
 | 
			
		||||
		/* Special houses that there can be only one of. */
 | 
			
		||||
		uint oneof = 0;
 | 
			
		||||
 | 
			
		||||
		if (hs->building_flags & BUILDING_IS_CHURCH) {
 | 
			
		||||
			SetBit(oneof, TOWN_HAS_CHURCH);
 | 
			
		||||
		} else if (hs->building_flags & BUILDING_IS_STADIUM) {
 | 
			
		||||
			SetBit(oneof, TOWN_HAS_STADIUM);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (t->flags & oneof) continue;
 | 
			
		||||
 | 
			
		||||
		/* 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();
 | 
			
		||||
 | 
			
		||||
		if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) {
 | 
			
		||||
			uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile, true, random_bits);
 | 
			
		||||
			if (callback_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_ALLOW_CONSTRUCTION, callback_res)) continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* build the house */
 | 
			
		||||
		t->cache.num_houses++;
 | 
			
		||||
 | 
			
		||||
		/* Special houses that there can be only one of. */
 | 
			
		||||
		t->flags |= oneof;
 | 
			
		||||
 | 
			
		||||
		byte construction_counter = 0;
 | 
			
		||||
		byte construction_stage = 0;
 | 
			
		||||
 | 
			
		||||
		if (_generating_world || _game_mode == GM_EDITOR) {
 | 
			
		||||
			uint32 r = Random();
 | 
			
		||||
 | 
			
		||||
			construction_stage = TOWN_HOUSE_COMPLETED;
 | 
			
		||||
			if (Chance16(1, 7)) construction_stage = GB(r, 0, 2);
 | 
			
		||||
 | 
			
		||||
			if (construction_stage == TOWN_HOUSE_COMPLETED) {
 | 
			
		||||
				ChangePopulation(t, hs->population);
 | 
			
		||||
			} else {
 | 
			
		||||
				construction_counter = GB(r, 2, 2);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits);
 | 
			
		||||
		UpdateTownRadius(t);
 | 
			
		||||
		UpdateTownCargoes(t, tile);
 | 
			
		||||
		/* Check if GRF allows this house */
 | 
			
		||||
		if (!HouseAllowsConstruction(house, tile, t, random_bits)) continue;
 | 
			
		||||
 | 
			
		||||
		DoBuildHouse(t, tile, house, random_bits);
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										677
									
								
								src/town_gui.cpp
									
									
									
									
									
								
							
							
						
						
									
										677
									
								
								src/town_gui.cpp
									
									
									
									
									
								
							@@ -32,6 +32,10 @@
 | 
			
		||||
#include "core/geometry_func.hpp"
 | 
			
		||||
#include "genworld.h"
 | 
			
		||||
#include "widgets/dropdown_func.h"
 | 
			
		||||
#include "newgrf_config.h"
 | 
			
		||||
#include "newgrf_house.h"
 | 
			
		||||
#include "date_func.h"
 | 
			
		||||
#include "core/random_func.hpp"
 | 
			
		||||
 | 
			
		||||
#include "widgets/town_widget.h"
 | 
			
		||||
 | 
			
		||||
@@ -1197,3 +1201,676 @@ void ShowFoundTownWindow()
 | 
			
		||||
	if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
 | 
			
		||||
	AllocateWindowDescFront<FoundTownWindow>(&_found_town_desc, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GUIHouseList : public SmallVector<HouseID, 32> {
 | 
			
		||||
protected:
 | 
			
		||||
	SmallVector<uint16, 4> house_sets; ///< list of house sets, each item points the first house of the set in the houses array
 | 
			
		||||
 | 
			
		||||
	static int CDECL HouseSorter(const HouseID *a, const HouseID *b)
 | 
			
		||||
	{
 | 
			
		||||
		const HouseSpec *a_hs = HouseSpec::Get(*a);
 | 
			
		||||
		const GRFFile *a_set = a_hs->grf_prop.grffile;
 | 
			
		||||
		const HouseSpec *b_hs = HouseSpec::Get(*b);
 | 
			
		||||
		const GRFFile *b_set = b_hs->grf_prop.grffile;
 | 
			
		||||
 | 
			
		||||
		int ret = (a_set != NULL) - (b_set != NULL);
 | 
			
		||||
		if (ret == 0) {
 | 
			
		||||
			if (a_set != NULL) {
 | 
			
		||||
				assert_compile(sizeof(a_set->grfid) <= sizeof(int));
 | 
			
		||||
				ret = a_set->grfid - b_set->grfid;
 | 
			
		||||
				if (ret == 0) ret = a_hs->grf_prop.local_id - b_hs->grf_prop.local_id;
 | 
			
		||||
			} else {
 | 
			
		||||
				ret = *a - *b;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	GUIHouseList()
 | 
			
		||||
	{
 | 
			
		||||
		*this->house_sets.Append() = 0; // terminator
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline HouseID GetHouseAtOffset(uint house_set, uint house_offset) const
 | 
			
		||||
	{
 | 
			
		||||
		return *this->Get(this->house_sets[house_set] + house_offset);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint NumHouseSets() const
 | 
			
		||||
	{
 | 
			
		||||
		return this->house_sets.Length() - 1; // last item is a terminator
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint NumHousesInHouseSet(uint house_set) const
 | 
			
		||||
	{
 | 
			
		||||
		assert(house_set < this->NumHouseSets());
 | 
			
		||||
		/* There is a terminator on the list of house sets. It's equal to the number
 | 
			
		||||
		 * of all houses. We can safely use "house_set + 1" even for the last
 | 
			
		||||
		 * house set. */
 | 
			
		||||
		return this->house_sets[house_set + 1] - this->house_sets[house_set];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int FindHouseSet(HouseID house) const
 | 
			
		||||
	{
 | 
			
		||||
		const GRFFile *house_set = HouseSpec::Get(house)->grf_prop.grffile;
 | 
			
		||||
		for (uint i = 0; i < this->NumHouseSets(); i++) {
 | 
			
		||||
			if (HouseSpec::Get(this->GetHouseAtOffset(i, 0))->grf_prop.grffile == house_set) return i;
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int FindHouseOffset(uint house_set, HouseID house) const
 | 
			
		||||
	{
 | 
			
		||||
		assert(house_set < this->NumHouseSets());
 | 
			
		||||
		uint count = this->NumHousesInHouseSet(house_set);
 | 
			
		||||
		for (uint i = 0; i < count; i++) {
 | 
			
		||||
			if (this->GetHouseAtOffset(house_set, i) == house) return i;
 | 
			
		||||
		}
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const char *GetNameOfHouseSet(uint house_set) const
 | 
			
		||||
	{
 | 
			
		||||
		assert(house_set < this->NumHouseSets());
 | 
			
		||||
		const GRFFile *gf = HouseSpec::Get(this->GetHouseAtOffset(house_set, 0))->grf_prop.grffile;
 | 
			
		||||
		if (gf != 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();
 | 
			
		||||
		for (HouseID house = 0; house < NUM_HOUSES; house++) {
 | 
			
		||||
			const HouseSpec *hs = HouseSpec::Get(house);
 | 
			
		||||
			/* is the house enabled? */
 | 
			
		||||
			if (!hs->enabled) continue;
 | 
			
		||||
			/* is the house overriden? */
 | 
			
		||||
			if (hs->grf_prop.override != INVALID_HOUSE_ID) continue;
 | 
			
		||||
			/* is the house allownd in current landscape? */
 | 
			
		||||
			HouseZones landscapes = (HouseZones)(HZ_TEMP << _settings_game.game_creation.landscape);
 | 
			
		||||
			if (_settings_game.game_creation.landscape == LT_ARCTIC) landscapes |= HZ_SUBARTC_ABOVE;
 | 
			
		||||
			if (!(hs->building_availability & landscapes)) continue;
 | 
			
		||||
			/* is the house allowed at any of house zones at all? */
 | 
			
		||||
			if (!(hs->building_availability & HZ_ZONALL)) continue;
 | 
			
		||||
			/* is there any year in which the house is allowed? */
 | 
			
		||||
			if (hs->min_year > hs->max_year) continue;
 | 
			
		||||
 | 
			
		||||
			/* add the house */
 | 
			
		||||
			*this->Append() = house;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* arrange items */
 | 
			
		||||
		QSortT(this->Begin(), this->Length(), HouseSorter);
 | 
			
		||||
 | 
			
		||||
		/* list house sets */
 | 
			
		||||
		this->house_sets.Clear();
 | 
			
		||||
		const GRFFile *last_set;
 | 
			
		||||
		for (uint i = 0; i < this->Length(); i++) {
 | 
			
		||||
			const HouseSpec *hs = HouseSpec::Get((*this)[i]);
 | 
			
		||||
			/* add house set */
 | 
			
		||||
			if (this->house_sets.Length() == 0 || last_set != hs->grf_prop.grffile) {
 | 
			
		||||
				last_set = hs->grf_prop.grffile;
 | 
			
		||||
				*this->house_sets.Append() = i;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		/* put a terminator on the list to make counting easier */
 | 
			
		||||
		*this->house_sets.Append() = this->Length();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static HouseID _cur_house = INVALID_HOUSE_ID; ///< house selected in the house picker window
 | 
			
		||||
 | 
			
		||||
/** The window used for building houses. */
 | 
			
		||||
class HousePickerWindow : public PickerWindowBase {
 | 
			
		||||
protected:
 | 
			
		||||
	GUIHouseList house_list; ///< list of houses and house sets
 | 
			
		||||
	uint house_offset;       ///< index of selected house
 | 
			
		||||
	uint house_set;          ///< index of selected house set
 | 
			
		||||
	uint line_height;        ///< height of a single line in the list of house sets
 | 
			
		||||
 | 
			
		||||
	void RestoreSelectedHouseIndex()
 | 
			
		||||
	{
 | 
			
		||||
		this->house_set = 0;
 | 
			
		||||
		this->house_offset = 0;
 | 
			
		||||
 | 
			
		||||
		if (this->house_list.Length() == 0) { // no houses at all?
 | 
			
		||||
			_cur_house = INVALID_HOUSE_ID;
 | 
			
		||||
			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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Select another house.
 | 
			
		||||
	 * @param new_house_set index of the house set
 | 
			
		||||
	 * @param new_house_offset offset of the house
 | 
			
		||||
	 */
 | 
			
		||||
	void SelectOtherHouse(uint new_house_set, uint new_house_offset)
 | 
			
		||||
	{
 | 
			
		||||
		assert(new_house_set < this->house_list.NumHouseSets());
 | 
			
		||||
		assert(new_house_offset < this->house_list.NumHousesInHouseSet(new_house_set));
 | 
			
		||||
 | 
			
		||||
		_cur_house = this->house_list.GetHouseAtOffset(new_house_set, new_house_offset);
 | 
			
		||||
		this->house_set = new_house_set;
 | 
			
		||||
		this->house_offset = new_house_offset;
 | 
			
		||||
 | 
			
		||||
		NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_HP_HOUSE_SELECT_MATRIX);
 | 
			
		||||
		matrix->SetCount(this->house_list.NumHousesInHouseSet(this->house_set));
 | 
			
		||||
		matrix->SetClicked(this->house_offset);
 | 
			
		||||
		this->UpdateSelectSize();
 | 
			
		||||
		this->SetDirty();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void UpdateSelectSize()
 | 
			
		||||
	{
 | 
			
		||||
		uint w = 1, h = 1;
 | 
			
		||||
		if (_cur_house != INVALID_HOUSE_ID) {
 | 
			
		||||
			const HouseSpec *hs = HouseSpec::Get(_cur_house);
 | 
			
		||||
			if (hs->building_flags & BUILDING_2_TILES_X) w++;
 | 
			
		||||
			if (hs->building_flags & BUILDING_2_TILES_Y) h++;
 | 
			
		||||
		}
 | 
			
		||||
		SetTileSelectSize(w, h);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	HousePickerWindow(WindowDesc *desc, Window *w) : PickerWindowBase(desc, w)
 | 
			
		||||
	{
 | 
			
		||||
		this->CreateNestedTree();
 | 
			
		||||
		/* there is no shade box but we will shade the window if there is no house to show */
 | 
			
		||||
		this->shade_select = this->GetWidget<NWidgetStacked>(WID_HP_MAIN_PANEL_SEL);
 | 
			
		||||
		NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_HP_HOUSE_SELECT_MATRIX);
 | 
			
		||||
		matrix->SetScrollbar(this->GetScrollbar(WID_HP_HOUSE_SELECT_SCROLL));
 | 
			
		||||
		this->FinishInitNested(0);
 | 
			
		||||
 | 
			
		||||
		if (_cur_house != INVALID_HOUSE_ID) matrix->SetClicked(this->house_offset); // set clicked item again to make it visible
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~HousePickerWindow()
 | 
			
		||||
	{
 | 
			
		||||
		DeleteWindowById(WC_SELECT_TOWN, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void OnInit()
 | 
			
		||||
	{
 | 
			
		||||
		this->house_list.Build();
 | 
			
		||||
		this->RestoreSelectedHouseIndex();
 | 
			
		||||
		this->UpdateSelectSize();
 | 
			
		||||
 | 
			
		||||
		/* if we have exactly one set of houses and it's not the default one then display it's name in the title bar */
 | 
			
		||||
		this->GetWidget<NWidgetCore>(WID_HP_CAPTION)->widget_data =
 | 
			
		||||
				(this->house_list.NumHouseSets() == 1 && HouseSpec::Get(this->house_list[0])->grf_prop.grffile != NULL) ?
 | 
			
		||||
				STR_HOUSE_BUILD_CUSTOM_CAPTION : STR_HOUSE_BUILD_CAPTION;
 | 
			
		||||
 | 
			
		||||
		/* hide widgets if we have no houses to show */
 | 
			
		||||
		this->SetShaded(this->house_list.Length() == 0);
 | 
			
		||||
 | 
			
		||||
		if (this->house_list.Length() != 0) {
 | 
			
		||||
			/* show the list of house sets if we have at least 2 items to show */
 | 
			
		||||
			this->GetWidget<NWidgetStacked>(WID_HP_HOUSE_SETS_SEL)->SetDisplayedPlane(this->house_list.NumHouseSets() > 1 ? 0 : SZSP_NONE);
 | 
			
		||||
			/* set number of items in the list of house sets */
 | 
			
		||||
			this->GetWidget<NWidgetCore>(WID_HP_HOUSE_SETS)->widget_data = (this->house_list.NumHouseSets() << MAT_ROW_START) | (1 << MAT_COL_START);
 | 
			
		||||
			/* show the landscape info only in arctic climate (above/below snowline) */
 | 
			
		||||
			this->GetWidget<NWidgetStacked>(WID_HP_HOUSE_LANDSCAPE_SEL)->SetDisplayedPlane(_settings_game.game_creation.landscape == LT_ARCTIC ? 0 : SZSP_NONE);
 | 
			
		||||
			/* update the matrix of houses */
 | 
			
		||||
			NWidgetMatrix *matrix = this->GetWidget<NWidgetMatrix>(WID_HP_HOUSE_SELECT_MATRIX);
 | 
			
		||||
			matrix->SetCount(this->house_list.NumHousesInHouseSet(this->house_set));
 | 
			
		||||
			matrix->SetClicked(this->house_offset);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void SetStringParameters(int widget) const
 | 
			
		||||
	{
 | 
			
		||||
		switch (widget) {
 | 
			
		||||
			case WID_HP_CAPTION:
 | 
			
		||||
				if (this->house_list.NumHouseSets() == 1) SetDParamStr(0, this->house_list.GetNameOfHouseSet(0));
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_NAME:
 | 
			
		||||
				SetDParam(0, GetHouseName(_cur_house));
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HISTORICAL_BUILDING:
 | 
			
		||||
				SetDParam(0, HouseSpec::Get(_cur_house)->extra_flags & BUILDING_IS_HISTORICAL ? STR_HOUSE_BUILD_HISTORICAL_BUILDING : STR_EMPTY);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_POPULATION:
 | 
			
		||||
				SetDParam(0, HouseSpec::Get(_cur_house)->population);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_ZONES: {
 | 
			
		||||
				HouseZones zones = (HouseZones)(HouseSpec::Get(_cur_house)->building_availability & HZ_ZONALL);
 | 
			
		||||
				for (int i = 0; i < HZB_END; i++) {
 | 
			
		||||
					/* colour: gold(enabled)/grey(disabled)  */
 | 
			
		||||
					SetDParam(2 * i, HasBit(zones, HZB_END - i - 1) ? STR_HOUSE_BUILD_HOUSE_ZONE_ENABLED : STR_HOUSE_BUILD_HOUSE_ZONE_DISABLED);
 | 
			
		||||
					/* digit: 1(center)/2/3/4/5(edge) */
 | 
			
		||||
					SetDParam(2 * i + 1, i + 1);
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_LANDSCAPE: {
 | 
			
		||||
				StringID info = STR_HOUSE_BUILD_LANDSCAPE_ABOVE_OR_BELOW_SNOWLINE;
 | 
			
		||||
				switch (HouseSpec::Get(_cur_house)->building_availability & (HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW)) {
 | 
			
		||||
					case HZ_SUBARTC_ABOVE: info = STR_HOUSE_BUILD_LANDSCAPE_ONLY_ABOVE_SNOWLINE; break;
 | 
			
		||||
					case HZ_SUBARTC_BELOW: info = STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE; break;
 | 
			
		||||
					default: break;
 | 
			
		||||
				}
 | 
			
		||||
				SetDParam(0, info);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_YEARS: {
 | 
			
		||||
				const HouseSpec *hs = HouseSpec::Get(_cur_house);
 | 
			
		||||
				SetDParam(0, hs->min_year <= _cur_year ? STR_HOUSE_BUILD_YEARS_GOOD_YEAR : STR_HOUSE_BUILD_YEARS_BAD_YEAR);
 | 
			
		||||
				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;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_ACCEPTANCE: {
 | 
			
		||||
				static char buff[DRAW_STRING_BUFFER] = "";
 | 
			
		||||
				char *str = buff;
 | 
			
		||||
				CargoArray cargo;
 | 
			
		||||
				uint32 dummy = 0;
 | 
			
		||||
				AddAcceptedHouseCargo(_cur_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(_cur_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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 | 
			
		||||
	{
 | 
			
		||||
		switch (widget) {
 | 
			
		||||
			case WID_HP_HOUSE_SETS: {
 | 
			
		||||
				uint max_w = 0;
 | 
			
		||||
				for (uint i = 0; i < this->house_list.NumHouseSets(); i++) {
 | 
			
		||||
					max_w = max(max_w, GetStringBoundingBox(this->house_list.GetNameOfHouseSet(i)).width);
 | 
			
		||||
				}
 | 
			
		||||
				size->width = max(size->width, max_w + padding.width);
 | 
			
		||||
				this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
 | 
			
		||||
				size->height = this->house_list.NumHouseSets() * this->line_height;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_NAME:
 | 
			
		||||
				size->width = 120; // we do not want this window to get too wide, better clip
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HISTORICAL_BUILDING:
 | 
			
		||||
				size->width = max(size->width, GetStringBoundingBox(STR_HOUSE_BUILD_HISTORICAL_BUILDING).width + padding.width);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_POPULATION:
 | 
			
		||||
				SetDParam(0, 0);
 | 
			
		||||
				/* max popultion is 255 - 3 digits */
 | 
			
		||||
				size->width = 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);
 | 
			
		||||
				dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE));
 | 
			
		||||
				SetDParam(0, STR_HOUSE_BUILD_LANDSCAPE_ONLY_BELOW_SNOWLINE);
 | 
			
		||||
				dim = maxdim(dim, GetStringBoundingBox(STR_HOUSE_BUILD_LANDSCAPE));
 | 
			
		||||
				dim.width += padding.width;
 | 
			
		||||
				dim.height += padding.height;
 | 
			
		||||
				*size = maxdim(*size, dim);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_YEARS: {
 | 
			
		||||
				SetDParam(0, STR_HOUSE_BUILD_YEARS_GOOD_YEAR);
 | 
			
		||||
				SetDParam(1, 0);
 | 
			
		||||
				SetDParam(2, STR_HOUSE_BUILD_YEARS_GOOD_YEAR);
 | 
			
		||||
				SetDParam(3, 0);
 | 
			
		||||
				Dimension dim = GetStringBoundingBox(STR_HOUSE_BUILD_YEARS);
 | 
			
		||||
				dim.width += 14 * GetDigitWidth() + padding.width; // space for about 16 digits (14 + two zeros) should be enough, don't make the window too wide
 | 
			
		||||
				dim.height += padding.height;
 | 
			
		||||
				*size = maxdim(*size, dim);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_SELECT_MATRIX:
 | 
			
		||||
				resize->height = 1; // don't snap to rows of this matrix
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			/* these texts can be long, better clip */
 | 
			
		||||
			case WID_HP_HOUSE_ACCEPTANCE:
 | 
			
		||||
			case WID_HP_HOUSE_SUPPLY:
 | 
			
		||||
				size->width = 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			default: break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void DrawWidget(const Rect &r, int widget) const
 | 
			
		||||
	{
 | 
			
		||||
		switch (GB(widget, 0, 16)) {
 | 
			
		||||
			case WID_HP_HOUSE_SETS: {
 | 
			
		||||
				int y = r.top + WD_MATRIX_TOP;
 | 
			
		||||
				for (uint i = 0; i < this->house_list.NumHouseSets(); i++) {
 | 
			
		||||
					SetDParamStr(0, this->house_list.GetNameOfHouseSet(i));
 | 
			
		||||
					DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y, STR_JUST_RAW_STRING, i == this->house_set ? TC_WHITE : TC_BLACK);
 | 
			
		||||
					y += this->line_height;
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_PREVIEW:
 | 
			
		||||
				DrawHouseImage(_cur_house, r.left, r.top, r.right, r.bottom);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_SELECT: {
 | 
			
		||||
				HouseID house = this->house_list.GetHouseAtOffset(this->house_set, GB(widget, 16, 16));
 | 
			
		||||
				int lowered = (house == _cur_house) ? 1 : 0;
 | 
			
		||||
				DrawHouseImage(house,
 | 
			
		||||
						r.left  + WD_MATRIX_LEFT  + lowered, r.top    + WD_MATRIX_TOP    + lowered,
 | 
			
		||||
						r.right - WD_MATRIX_RIGHT + lowered, r.bottom - WD_MATRIX_BOTTOM + lowered);
 | 
			
		||||
				const HouseSpec *hs = HouseSpec::Get(house);
 | 
			
		||||
				/* disabled? */
 | 
			
		||||
				if (_cur_year < hs->min_year || _cur_year > hs->max_year) {
 | 
			
		||||
					GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER);
 | 
			
		||||
				}
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void OnClick(Point pt, int widget, int click_count)
 | 
			
		||||
	{
 | 
			
		||||
		switch (GB(widget, 0, 16)) {
 | 
			
		||||
			case WID_HP_HOUSE_SETS: {
 | 
			
		||||
				uint index = (uint)(pt.y - this->GetWidget<NWidgetBase>(widget)->pos_y) / this->line_height;
 | 
			
		||||
				if (index < this->house_list.NumHouseSets() && index != this->house_set) this->SelectOtherHouse(index, 0);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case WID_HP_HOUSE_SELECT:
 | 
			
		||||
				this->SelectOtherHouse(this->house_set, GB(widget, 16, 16));
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const NWidgetPart _nested_house_picker_widgets[] = {
 | 
			
		||||
	/* TOP */
 | 
			
		||||
	NWidget(NWID_HORIZONTAL),
 | 
			
		||||
		NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
 | 
			
		||||
		NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_HP_CAPTION), SetDataTip(STR_HOUSE_BUILD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 | 
			
		||||
		NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
 | 
			
		||||
	EndContainer(),
 | 
			
		||||
	NWidget(NWID_SELECTION, COLOUR_DARK_GREEN, WID_HP_MAIN_PANEL_SEL),
 | 
			
		||||
		NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_HP_HOUSE_SELECT_SCROLL),
 | 
			
		||||
			/* MIDDLE */
 | 
			
		||||
			NWidget(NWID_HORIZONTAL), SetPIP(5, 0, 0),
 | 
			
		||||
				/* LEFT */
 | 
			
		||||
				NWidget(NWID_VERTICAL), SetPIP(5, 2, 2),
 | 
			
		||||
					/* LIST OF HOUSE SETS */
 | 
			
		||||
					NWidget(NWID_SELECTION, COLOUR_DARK_GREEN, WID_HP_HOUSE_SETS_SEL),
 | 
			
		||||
						NWidget(NWID_HORIZONTAL),
 | 
			
		||||
							NWidget(WWT_MATRIX, COLOUR_GREY, WID_HP_HOUSE_SETS), SetMinimalSize(0, 60), SetFill(1, 0), SetResize(0, 0),
 | 
			
		||||
									SetMatrixDataTip(1, 1, STR_HOUSE_BUILD_HOUSESET_LIST_TOOLTIP),
 | 
			
		||||
						EndContainer(),
 | 
			
		||||
					EndContainer(),
 | 
			
		||||
					/* HOUSE PICTURE AND LABEL */
 | 
			
		||||
					NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_PREVIEW), SetFill(1, 1), SetResize(0, 1), SetMinimalSize(2 * TILE_PIXELS, 142),
 | 
			
		||||
					NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_HP_HOUSE_NAME), SetDataTip(STR_HOUSE_BUILD_HOUSE_NAME, STR_NULL), SetMinimalSize(120, 0),
 | 
			
		||||
					NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_HP_HISTORICAL_BUILDING), SetDataTip(STR_JUST_STRING, STR_NULL),
 | 
			
		||||
					/* HOUSE INFOS (SHORT TEXTS) */
 | 
			
		||||
					NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_POPULATION), SetDataTip(STR_HOUSE_BUILD_HOUSE_POPULATION, STR_NULL), SetPadding(5, 0, 0, 0),
 | 
			
		||||
					NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_ZONES), SetDataTip(STR_HOUSE_BUILD_HOUSE_ZONES, STR_NULL),
 | 
			
		||||
					NWidget(NWID_SELECTION, COLOUR_DARK_GREEN, WID_HP_HOUSE_LANDSCAPE_SEL),
 | 
			
		||||
						NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_LANDSCAPE), SetDataTip(STR_HOUSE_BUILD_LANDSCAPE, STR_NULL),
 | 
			
		||||
					EndContainer(),
 | 
			
		||||
					NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_YEARS), SetDataTip(STR_HOUSE_BUILD_YEARS, STR_NULL),
 | 
			
		||||
				EndContainer(),
 | 
			
		||||
				/* RIGHT: MATRIX OF HOUSES */
 | 
			
		||||
				NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_HP_HOUSE_SELECT_MATRIX), SetPIP(0, 2, 0), SetPadding(2, 2, 2, 2), SetScrollbar(WID_HP_HOUSE_SELECT_SCROLL),
 | 
			
		||||
					NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_HP_HOUSE_SELECT), SetMinimalSize(64, 64), SetFill(0, 0), SetResize(0, 0),
 | 
			
		||||
							SetDataTip(0x0, STR_HOUSE_BUILD_SELECT_HOUSE_TOOLTIP), SetScrollbar(WID_HP_HOUSE_SELECT_SCROLL),
 | 
			
		||||
					EndContainer(),
 | 
			
		||||
				EndContainer(),
 | 
			
		||||
				NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_HP_HOUSE_SELECT_SCROLL),
 | 
			
		||||
			EndContainer(),
 | 
			
		||||
			/* BOTTOM */
 | 
			
		||||
			NWidget(NWID_HORIZONTAL), SetPIP(5, 2, 0),
 | 
			
		||||
				/* HOUSE INFOS (LONG TEXTS) */
 | 
			
		||||
				NWidget(NWID_VERTICAL), SetPIP(0, 2, 5),
 | 
			
		||||
					NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_ACCEPTANCE), SetDataTip(STR_HOUSE_BUILD_ACCEPTED_CARGO, STR_NULL), SetFill(1, 0), SetResize(1, 0),
 | 
			
		||||
					NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_HP_HOUSE_SUPPLY), SetDataTip(STR_HOUSE_BUILD_SUPPLIED_CARGO, STR_NULL), SetFill(1, 0), SetResize(1, 0),
 | 
			
		||||
				EndContainer(),
 | 
			
		||||
				/* RESIZE BOX */
 | 
			
		||||
				NWidget(NWID_VERTICAL),
 | 
			
		||||
					NWidget(NWID_SPACER), SetFill(0, 1),
 | 
			
		||||
					NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
 | 
			
		||||
				EndContainer(),
 | 
			
		||||
			EndContainer(),
 | 
			
		||||
		EndContainer(),
 | 
			
		||||
	EndContainer(),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static WindowDesc _house_picker_desc(
 | 
			
		||||
	WDP_AUTO, "build_house", 0, 0,
 | 
			
		||||
	WC_BUILD_HOUSE, WC_BUILD_TOOLBAR,
 | 
			
		||||
	WDF_CONSTRUCTION,
 | 
			
		||||
	_nested_house_picker_widgets, lengthof(_nested_house_picker_widgets)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Show our house picker.
 | 
			
		||||
 * @param parent The toolbar window we're associated with.
 | 
			
		||||
 */
 | 
			
		||||
void ShowBuildHousePicker(Window *parent)
 | 
			
		||||
{
 | 
			
		||||
	new HousePickerWindow(&_house_picker_desc, parent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Window for selecting towns to build a house in.
 | 
			
		||||
 */
 | 
			
		||||
struct SelectTownWindow : Window {
 | 
			
		||||
	TownList towns;       ///< list of towns
 | 
			
		||||
	CommandContainer cmd; ///< command to build the house (CMD_BUILD_HOUSE)
 | 
			
		||||
	Scrollbar *vscroll;   ///< scrollbar for the town list
 | 
			
		||||
 | 
			
		||||
	SelectTownWindow(WindowDesc *desc, const TownList &towns, const CommandContainer &cmd) : Window(desc), towns(towns), cmd(cmd)
 | 
			
		||||
	{
 | 
			
		||||
		this->CreateNestedTree();
 | 
			
		||||
		this->vscroll = this->GetScrollbar(WID_ST_SCROLLBAR);
 | 
			
		||||
		this->vscroll->SetCount(this->towns.Length());
 | 
			
		||||
		this->FinishInitNested();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 | 
			
		||||
	{
 | 
			
		||||
		if (widget != WID_ST_PANEL) return;
 | 
			
		||||
 | 
			
		||||
		/* Determine the widest string */
 | 
			
		||||
		Dimension d = { 0, 0 };
 | 
			
		||||
		for (uint i = 0; i < this->towns.Length(); i++) {
 | 
			
		||||
			SetDParam(0, this->towns[i]);
 | 
			
		||||
			d = maxdim(d, GetStringBoundingBox(STR_SELECT_TOWN_LIST_ITEM));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		resize->height = d.height;
 | 
			
		||||
		d.height *= 5;
 | 
			
		||||
		d.width += WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT;
 | 
			
		||||
		d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
 | 
			
		||||
		*size = d;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void DrawWidget(const Rect &r, int widget) const
 | 
			
		||||
	{
 | 
			
		||||
		if (widget != WID_ST_PANEL) return;
 | 
			
		||||
 | 
			
		||||
		uint y = r.top + WD_FRAMERECT_TOP;
 | 
			
		||||
		uint end = min(this->vscroll->GetCount(), this->vscroll->GetPosition() + this->vscroll->GetCapacity());
 | 
			
		||||
		for (uint i = this->vscroll->GetPosition(); i < end; i++) {
 | 
			
		||||
			SetDParam(0, this->towns[i]);
 | 
			
		||||
			DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SELECT_TOWN_LIST_ITEM);
 | 
			
		||||
			y += this->resize.step_height;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void OnClick(Point pt, int widget, int click_count)
 | 
			
		||||
	{
 | 
			
		||||
		if (widget != WID_ST_PANEL) return;
 | 
			
		||||
 | 
			
		||||
		uint pos = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ST_PANEL, WD_FRAMERECT_TOP);
 | 
			
		||||
		if (pos >= this->towns.Length()) return;
 | 
			
		||||
 | 
			
		||||
		/* Place a house */
 | 
			
		||||
		SB(this->cmd.p1, 16, 16, this->towns[pos]);
 | 
			
		||||
		DoCommandP(&this->cmd);
 | 
			
		||||
 | 
			
		||||
		/* Close the window */
 | 
			
		||||
		delete this;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	virtual void OnResize()
 | 
			
		||||
	{
 | 
			
		||||
		this->vscroll->SetCapacityFromWidget(this, WID_ST_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const NWidgetPart _nested_select_town_widgets[] = {
 | 
			
		||||
	NWidget(NWID_HORIZONTAL),
 | 
			
		||||
		NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
 | 
			
		||||
		NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ST_CAPTION), SetDataTip(STR_SELECT_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 | 
			
		||||
		NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
 | 
			
		||||
	EndContainer(),
 | 
			
		||||
	NWidget(NWID_HORIZONTAL),
 | 
			
		||||
		NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_ST_PANEL), SetResize(1, 0), SetScrollbar(WID_ST_SCROLLBAR), EndContainer(),
 | 
			
		||||
		NWidget(NWID_VERTICAL),
 | 
			
		||||
			NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_ST_SCROLLBAR),
 | 
			
		||||
			NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN),
 | 
			
		||||
		EndContainer(),
 | 
			
		||||
	EndContainer(),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static WindowDesc _select_town_desc(
 | 
			
		||||
	WDP_AUTO, "select_town", 100, 0,
 | 
			
		||||
	WC_SELECT_TOWN, WC_NONE,
 | 
			
		||||
	WDF_CONSTRUCTION,
 | 
			
		||||
	_nested_select_town_widgets, lengthof(_nested_select_town_widgets)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
static void ShowSelectTownWindow(const TownList &towns, const CommandContainer &cmd)
 | 
			
		||||
{
 | 
			
		||||
	DeleteWindowByClass(WC_SELECT_TOWN);
 | 
			
		||||
	new SelectTownWindow(&_select_town_desc, towns, cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void PlaceProc_House(TileIndex tile)
 | 
			
		||||
{
 | 
			
		||||
	if (_town_pool.items == 0) {
 | 
			
		||||
		ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HOUSE_HERE, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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) {
 | 
			
		||||
		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 (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);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,10 +13,13 @@
 | 
			
		||||
#define TOWN_TYPE_H
 | 
			
		||||
 | 
			
		||||
#include "core/enum_type.hpp"
 | 
			
		||||
#include "core/smallvec_type.hpp"
 | 
			
		||||
 | 
			
		||||
typedef uint16 TownID;
 | 
			
		||||
struct Town;
 | 
			
		||||
 | 
			
		||||
typedef SmallVector<TownID, 8> TownList;
 | 
			
		||||
 | 
			
		||||
/** Supported initial town sizes */
 | 
			
		||||
enum TownSize {
 | 
			
		||||
	TSZ_SMALL,  ///< Small town.
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
@@ -62,4 +62,32 @@ enum TownFoundingWidgets {
 | 
			
		||||
	WID_TF_LAYOUT_RANDOM,     ///< Selection for a randomly chosen town layout.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Widgets of the #HousePickerWindow class. */
 | 
			
		||||
enum HousePickerWidgets {
 | 
			
		||||
	WID_HP_CAPTION,
 | 
			
		||||
	WID_HP_MAIN_PANEL_SEL,      ///< Selection widget to show/hide the main panel.
 | 
			
		||||
	WID_HP_HOUSE_SETS_SEL,      ///< Selection widget to show/hide the list of house sets.
 | 
			
		||||
	WID_HP_HOUSE_SETS,          ///< List of available house sets.
 | 
			
		||||
	WID_HP_HOUSE_SELECT_MATRIX, ///< Matrix with houses to select.
 | 
			
		||||
	WID_HP_HOUSE_SELECT_SCROLL, ///< Scrollbar associated with the house matrix.
 | 
			
		||||
	WID_HP_HOUSE_SELECT,        ///< Panels with house images in the house matrix.
 | 
			
		||||
	WID_HP_HOUSE_PREVIEW,       ///< House preview panel.
 | 
			
		||||
	WID_HP_HOUSE_NAME,          ///< House name display.
 | 
			
		||||
	WID_HP_HISTORICAL_BUILDING, ///< "Historical building" label.
 | 
			
		||||
	WID_HP_HOUSE_POPULATION,    ///< House population display.
 | 
			
		||||
	WID_HP_HOUSE_ZONES,         ///< House zones display.
 | 
			
		||||
	WID_HP_HOUSE_LANDSCAPE,     ///< Information about house availability against the landscape.
 | 
			
		||||
	WID_HP_HOUSE_LANDSCAPE_SEL, ///< Selection widget to show/hide the landscape info.
 | 
			
		||||
	WID_HP_HOUSE_YEARS,         ///< Years display.
 | 
			
		||||
	WID_HP_HOUSE_ACCEPTANCE,    ///< Cargo accepted.
 | 
			
		||||
	WID_HP_HOUSE_SUPPLY,        ///< Cargo supplied.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Widgets of the #SelectTownWindow class. */
 | 
			
		||||
enum SelectTownWidgets {
 | 
			
		||||
	WID_ST_CAPTION,   ///< Caption of the window.
 | 
			
		||||
	WID_ST_PANEL,     ///< Main panel.
 | 
			
		||||
	WID_ST_SCROLLBAR, ///< Scrollbar of the panel.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* WIDGETS_TOWN_WIDGET_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -236,6 +236,12 @@ enum WindowClass {
 | 
			
		||||
	 */
 | 
			
		||||
	WC_SELECT_STATION,
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Select town (when placing a house); %Window numbers:
 | 
			
		||||
	 *   - 0 = #SelectTownWidgets
 | 
			
		||||
	 */
 | 
			
		||||
	WC_SELECT_TOWN,
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * News window; %Window numbers:
 | 
			
		||||
	 *   - 0 = #NewsWidgets
 | 
			
		||||
@@ -370,6 +376,12 @@ enum WindowClass {
 | 
			
		||||
	 */
 | 
			
		||||
	WC_BUILD_OBJECT,
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Build house; %Window numbers:
 | 
			
		||||
	 *  - 0 = #BuildHouseWidgets
 | 
			
		||||
	*/
 | 
			
		||||
	WC_BUILD_HOUSE,
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Build vehicle; %Window numbers:
 | 
			
		||||
	 *   - #VehicleType = #BuildVehicleWidgets
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user