From d4f11eca421b757eff3c55be4fa2b10e7efcb94e Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 7 Feb 2022 01:16:45 +0000 Subject: [PATCH] Add NewGRF object properties to set viewport map mode/smallmap tile type --- docs/landscape.html | 1 + docs/landscape_grid.html | 2 +- docs/newgrf-additions-nml.html | 49 +++++++ docs/newgrf-additions.html | 50 +++++++ src/newgrf.cpp | 11 ++ src/newgrf_extension.cpp | 3 + src/newgrf_extension.h | 2 + src/newgrf_object.h | 17 +++ src/object_cmd.cpp | 7 +- src/object_map.h | 12 ++ src/saveload/afterload.cpp | 15 +- src/saveload/extended_ver_sl.cpp | 2 +- src/smallmap_gui.cpp | 111 ++++++++++++++- src/table/newgrf_debug_data.h | 1 + src/table/object_land.h | 2 +- src/viewport.cpp | 233 +++++++++++++++++++++++++++---- 16 files changed, 479 insertions(+), 39 deletions(-) diff --git a/docs/landscape.html b/docs/landscape.html index bd6cc4b5c8..8fc837d3a2 100644 --- a/docs/landscape.html +++ b/docs/landscape.html @@ -1895,6 +1895,7 @@
  • m7: animation counter
  • m4 bits 7..5: update counter (for objects using land ground sprites), incremented on every periodic processing.
    For snow and desert, these bits are not used, tile is updated on every periodic processing.
  • +
  • m4 bit 4: object type has viewport map colour/type override.
  • m4 bits 3..2: ground type (for objects using land ground sprites): diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html index c70a18eef0..a8d9a7361a 100644 --- a/docs/landscape_grid.html +++ b/docs/landscape_grid.html @@ -329,7 +329,7 @@ the array so you can quickly see what is used and what is not. - + diff --git a/docs/newgrf-additions-nml.html b/docs/newgrf-additions-nml.html index eda8a45b41..c7f00be5c9 100644 --- a/docs/newgrf-additions-nml.html +++ b/docs/newgrf-additions-nml.html @@ -161,6 +161,55 @@ Flood resistance is always enabled for objects which can be built on water.
    This property can be used to enable flood resistance without enabling the object to be built on water. + +
    OXX XXXXX XXXX XXXX XXXX XXXX XXXX XXXXPPPO PP PPPPP P PP PP XXXX XXXX OOOO OOPP XXXX XXXX
    map_tile_typeOBJECT_VIEWPORT_MAP_TILE_TYPE_XXX + Set tile type used for display in viewport map mode and the small-map window.
    + The value should be one of: + + + + + + + + + + + + + +
    ValueMeaningNotes
    OBJECT_VIEWPORT_MAP_TILE_TYPE_DEFAULTDefault object
    OBJECT_VIEWPORT_MAP_TILE_TYPE_CLEARClear/bare dirtIf use_land_ground is enabled, the underlying ground type will be used instead
    OBJECT_VIEWPORT_MAP_TILE_TYPE_GRASSGrass
    OBJECT_VIEWPORT_MAP_TILE_TYPE_ROUGHRough ground
    OBJECT_VIEWPORT_MAP_TILE_TYPE_ROCKSRocky ground
    OBJECT_VIEWPORT_MAP_TILE_TYPE_FIELDSFarm fieldsThe specific type of field can be set using map_tile_subtype
    OBJECT_VIEWPORT_MAP_TILE_TYPE_SNOWSnow
    OBJECT_VIEWPORT_MAP_TILE_TYPE_DESERTDesert
    OBJECT_VIEWPORT_MAP_TILE_TYPE_TREESTreesThe specific tree count and ground type/density can be set using map_tile_subtype
    OBJECT_VIEWPORT_MAP_TILE_TYPE_HOUSEHouse
    OBJECT_VIEWPORT_MAP_TILE_TYPE_WATERWater
    +
    map_tile_subtype0 .. 65535 +

    This can be used to further refine the type set in map_tile_type.

    +

    Farm fields: + + + +
    BitMeaning
    0 - 2 + Which field type to use +

    +

    Trees: + + + + + +
    BitMeaning
    0 - 3 + Tree ground type + + + + + + + +
    ValueMeaning
    OBJECT_VIEWPORT_MAP_TILE_TYPE_TREE_GROUND_GRASSGrass
    OBJECT_VIEWPORT_MAP_TILE_TYPE_TREE_GROUND_ROUGHRough ground
    OBJECT_VIEWPORT_MAP_TILE_TYPE_TREE_GROUND_SNOW_DESERTSnow/desert
    OBJECT_VIEWPORT_MAP_TILE_TYPE_TREE_GROUND_SHOREShore
    OBJECT_VIEWPORT_MAP_TILE_TYPE_TREE_GROUND_ROUGH_SNOWRough snow
    +
    4 - 7 + Tree ground density (clamped to: 0 - 3) +
    8 - 11 + Number of trees on the tile (clamped to: 1 - 4) +

    +

    Object variables

    Variables in the table below which are not supported by the version of OpenTTD being used return a value of 0.

    diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index 70c28fe32e..3eef52c1e1 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -413,6 +413,56 @@ This property can be used to enable flood resistance without enabling the object to be built on water.
    The property length is 1 byte. 0 is disabled (default). 1 is enabled.

    This is indicated by the feature name: action0_object_flood_resistant, version 1

    +

    Set tile type used for display in viewport map mode and the small-map window (mappable property: object_viewport_map_tile_type)

    +

    This property sets how object tiles are displayed in viewport map mode and the small-map window.
    + The property length is 1 byte.

    + + + + + + + + + + + + + +
    ValueMeaningNotes
    00Default object
    01Clear/bare dirtIf object_use_land_ground is enabled, the underlying ground type will be used instead
    02Grass
    03Rough ground
    04Rocky ground
    05Farm fieldsThe specific type of field can be set using object_viewport_map_tile_subtype
    06Snow
    07Desert
    08TreesThe specific tree count and ground type/density can be set using object_viewport_map_tile_subtype
    09House
    0AWater

    +

    This is indicated by the feature name: action0_object_viewport_map_tile_type, version 1

    +

    Set tile sub-type used for display in viewport map mode and the small-map window (mappable property: object_viewport_map_tile_subtype)

    +

    This property can be used to further refine the type set in object_viewport_map_tile_type.
    + The property length is 2 bytes.

    +

    Farm fields: + + + +
    BitValueMeaning
    0 - 20 - 7 + Which field type to use +

    +

    Trees: + + + + + +
    BitMeaning
    0 - 3 + Tree ground type + + + + + + + +
    ValueMeaning
    0Grass
    1Rough ground
    2Snow/desert
    3Shore
    4Rough snow
    +
    4 - 7 + Tree ground density (clamped to: 0 - 3) +
    8 - 11 + Number of trees on the tile (clamped to: 1 - 4) +

    +

    This is indicated by the feature name: action0_object_viewport_map_tile_type, version 1


    Action 14 - Variable Mapping for Variational Action 2

    See Action 14 Specification and Variational Action 2 Specification for background information.

    diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 734efc66ee..1c0cfe1d22 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -4327,6 +4327,17 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, const G if (buf->ReadByte() != 0) spec->ctrl_flags |= OBJECT_CTRL_FLAG_FLOOD_RESISTANT; break; + case A0RPI_OBJECT_VIEWPORT_MAP_TYPE: + if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break; + spec->vport_map_type = (ObjectViewportMapType)buf->ReadByte(); + spec->ctrl_flags |= OBJECT_CTRL_FLAG_VPORT_MAP_TYPE; + break; + + case A0RPI_OBJECT_VIEWPORT_MAP_SUBTYPE: + if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break; + spec->vport_map_subtype = buf->ReadWord(); + break; + default: ret = HandleAction0PropertyDefault(buf, prop); break; diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp index 78b3373e81..79116ff74c 100644 --- a/src/newgrf_extension.cpp +++ b/src/newgrf_extension.cpp @@ -50,6 +50,7 @@ extern const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("action0_object_use_land_ground", 1), GRFFeatureInfo("action0_object_edge_foundation_mode", 2), GRFFeatureInfo("action0_object_flood_resistant", 1), + GRFFeatureInfo("action0_object_viewport_map_tile_type", 1), GRFFeatureInfo(), }; @@ -85,6 +86,8 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = { GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_USE_LAND_GROUND, "object_use_land_ground"), GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_EDGE_FOUNDATION_MODE, "object_edge_foundation_mode"), GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_FLOOD_RESISTANT, "object_flood_resistant"), + GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_VIEWPORT_MAP_TYPE, "object_viewport_map_tile_type"), + GRFPropertyMapDefinition(GSF_OBJECTS, A0RPI_OBJECT_VIEWPORT_MAP_SUBTYPE, "object_viewport_map_tile_subtype"), GRFPropertyMapDefinition(), }; diff --git a/src/newgrf_extension.h b/src/newgrf_extension.h index bf14d0b02b..ca21497efc 100644 --- a/src/newgrf_extension.h +++ b/src/newgrf_extension.h @@ -37,6 +37,8 @@ enum Action0RemapPropertyIds { A0RPI_OBJECT_USE_LAND_GROUND, A0RPI_OBJECT_EDGE_FOUNDATION_MODE, A0RPI_OBJECT_FLOOD_RESISTANT, + A0RPI_OBJECT_VIEWPORT_MAP_TYPE, + A0RPI_OBJECT_VIEWPORT_MAP_SUBTYPE, }; diff --git a/src/newgrf_object.h b/src/newgrf_object.h index f95a98eef4..1ab3587b60 100644 --- a/src/newgrf_object.h +++ b/src/newgrf_object.h @@ -45,6 +45,7 @@ enum ObjectCtrlFlags { OBJECT_CTRL_FLAG_USE_LAND_GROUND = 1 << 0, ///< Use land for ground sprite. OBJECT_CTRL_FLAG_EDGE_FOUNDATION = 1 << 1, ///< Use edge foundation mode. OBJECT_CTRL_FLAG_FLOOD_RESISTANT = 1 << 2, ///< Object is flood-resistant. + OBJECT_CTRL_FLAG_VPORT_MAP_TYPE = 1 << 3, ///< Viewport map type is set. }; DECLARE_ENUM_AS_BIT_SET(ObjectCtrlFlags) @@ -67,6 +68,20 @@ enum ObjectClassID { /** Allow incrementing of ObjectClassID variables */ DECLARE_POSTFIX_INCREMENT(ObjectClassID) +enum ObjectViewportMapType { + OVMT_DEFAULT = 0, + OVMT_CLEAR, + OVMT_GRASS, + OVMT_ROUGH, + OVMT_ROCKS, + OVMT_FIELDS, + OVMT_SNOW, + OVMT_DESERT, + OVMT_TREES, + OVMT_HOUSE, + OVMT_WATER, +}; + /** An object that isn't use for transport, industries or houses. * @note If you change this struct, adopt the initialization of * default objects in table/object_land.h @@ -92,6 +107,8 @@ struct ObjectSpec { uint8 views; ///< The number of views. uint8 generate_amount; ///< Number of objects which are attempted to be generated per 256^2 map during world generation. bool enabled; ///< Is this spec enabled? + ObjectViewportMapType vport_map_type; ///< Viewport map type + uint16 vport_map_subtype; ///< Viewport map subtype /** * Get the cost for building a structure of this type. diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 3aa8c2da17..3bb79e0ba8 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -182,6 +182,9 @@ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, u SetObjectGroundTypeDensity(t, OBJECT_GROUND_GRASS, 0); } SetObjectFoundationType(t, SLOPE_ELEVATED, type, spec); + if (spec->ctrl_flags & OBJECT_CTRL_FLAG_VPORT_MAP_TYPE) { + SetObjectHasViewportMapViewOverride(t, true); + } MarkTileDirtyByTile(t, VMDF_NOT_MAP_MODE); } @@ -953,11 +956,11 @@ static void TileLoop_Object(TileIndex tile) } else { SetObjectGroundCounter(tile, 0); SetObjectGroundDensity(tile, GetObjectGroundDensity(tile) + 1); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + MarkTileDirtyByTile(tile, spec->vport_map_type != OVMT_CLEAR ? VMDF_NOT_MAP_MODE : VMDF_NONE); } } else { SetObjectGroundTypeDensity(tile, OBJECT_GROUND_GRASS, 3); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + MarkTileDirtyByTile(tile, spec->vport_map_type != OVMT_CLEAR ? VMDF_NOT_MAP_MODE : VMDF_NONE); } } } diff --git a/src/object_map.h b/src/object_map.h index 626f3a035a..6ffcfcb2b8 100644 --- a/src/object_map.h +++ b/src/object_map.h @@ -168,6 +168,18 @@ static inline void SetObjectEffectiveFoundationType(TileIndex t, ObjectEffective SB(_me[t].m6, 0, 2, foundation_type); } +static inline bool GetObjectHasViewportMapViewOverride(TileIndex t) +{ + assert_tile(IsTileType(t, MP_OBJECT), t); + return HasBit(_m[t].m4, 4); +} + +static inline void SetObjectHasViewportMapViewOverride(TileIndex t, bool map_view_override) +{ + assert_tile(IsTileType(t, MP_OBJECT), t); + SB(_m[t].m4, 4, 1, map_view_override ? 1 : 0); +} + /** * Make an Object tile. * @param t The tile to make and object tile. diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 8913e5cfcc..3e299e08a0 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3989,13 +3989,20 @@ bool AfterLoadGame() } } - if (SlXvIsFeatureMissing(XSLFI_OBJECT_GROUND_TYPES, 2)) { + if (SlXvIsFeatureMissing(XSLFI_OBJECT_GROUND_TYPES, 3)) { for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_OBJECT)) { if (SlXvIsFeatureMissing(XSLFI_OBJECT_GROUND_TYPES)) _m[t].m4 = 0; - ObjectType type = GetObjectType(t); - extern void SetObjectFoundationType(TileIndex tile, Slope tileh, ObjectType type, const ObjectSpec *spec); - SetObjectFoundationType(t, SLOPE_ELEVATED, type, ObjectSpec::Get(type)); + if (SlXvIsFeatureMissing(XSLFI_OBJECT_GROUND_TYPES, 2)) { + ObjectType type = GetObjectType(t); + extern void SetObjectFoundationType(TileIndex tile, Slope tileh, ObjectType type, const ObjectSpec *spec); + SetObjectFoundationType(t, SLOPE_ELEVATED, type, ObjectSpec::Get(type)); + } + if (SlXvIsFeatureMissing(XSLFI_OBJECT_GROUND_TYPES, 3)) { + if (ObjectSpec::GetByTile(t)->ctrl_flags & OBJECT_CTRL_FLAG_VPORT_MAP_TYPE) { + SetObjectHasViewportMapViewOverride(t, true); + } + } } } } diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 4c8c4e1d29..85a945082d 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -161,7 +161,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_DEPOT_ORDER_EXTRA_FLAGS,XSCF_IGNORABLE_UNKNOWN, 1, 1, "depot_order_extra_flags", nullptr, nullptr, nullptr }, { XSLFI_EXTRA_SIGNAL_TYPES, XSCF_NULL, 1, 1, "extra_signal_types", nullptr, nullptr, nullptr }, { XSLFI_BANKRUPTCY_EXTRA, XSCF_NULL, 1, 1, "bankruptcy_extra", nullptr, nullptr, nullptr }, - { XSLFI_OBJECT_GROUND_TYPES, XSCF_NULL, 2, 2, "object_ground_types", nullptr, nullptr, nullptr }, + { XSLFI_OBJECT_GROUND_TYPES, XSCF_NULL, 3, 3, "object_ground_types", nullptr, nullptr, nullptr }, { XSLFI_LINKGRAPH_AIRCRAFT, XSCF_NULL, 1, 1, "linkgraph_aircraft", nullptr, nullptr, nullptr }, { XSLFI_COMPANY_PW, XSCF_IGNORABLE_ALL, 1, 1, "company_password", nullptr, nullptr, "PLYP" }, { XSLFI_ST_INDUSTRY_CARGO_MODE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "st_industry_cargo_mode", nullptr, nullptr, nullptr }, diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 3c416530a0..dd7192f91c 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -24,6 +24,8 @@ #include "screenshot.h" #include "guitimer_func.h" #include "zoom_func.h" +#include "object_map.h" +#include "newgrf_object.h" #include "smallmap_colours.h" #include "smallmap_gui.h" @@ -319,6 +321,41 @@ void BuildOwnerLegend() _smallmap_company_count = i; } +static TileType GetSmallMapTileType(TileIndex tile, TileType t) +{ + if (t == MP_OBJECT && GetObjectHasViewportMapViewOverride(tile)) { + ObjectViewportMapType vmtype = OVMT_DEFAULT; + const ObjectSpec *spec = ObjectSpec::GetByTile(tile); + if (spec->ctrl_flags & OBJECT_CTRL_FLAG_VPORT_MAP_TYPE) vmtype = spec->vport_map_type; + if (vmtype == OVMT_CLEAR && spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) { + if (IsTileOnWater(tile) && GetObjectGroundType(tile) != OBJECT_GROUND_SHORE) { + vmtype = OVMT_WATER; + } + } + switch (vmtype) { + case OVMT_DEFAULT: + break; + + case OVMT_TREES: + t = MP_TREES; + break; + + case OVMT_HOUSE: + t = MP_HOUSE; + break; + + case OVMT_WATER: + t = MP_WATER; + break; + + default: + t = MP_CLEAR; + break; + } + } + return t; +} + /** * Return the colour a tile would be displayed with in the small map in mode "Contour". * @param tile The tile of which we would like to get the colour. @@ -328,7 +365,7 @@ void BuildOwnerLegend() static inline uint32 GetSmallMapContoursPixels(TileIndex tile, TileType t) { const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->height_colours[TileHeight(tile)], &_smallmap_contours_andor[t]); + return ApplyMask(cs->height_colours[TileHeight(tile)], &_smallmap_contours_andor[GetSmallMapTileType(tile, t)]); } /** @@ -341,7 +378,7 @@ static inline uint32 GetSmallMapContoursPixels(TileIndex tile, TileType t) static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile, TileType t) { const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[t]); + return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[GetSmallMapTileType(tile, t)]); } /** @@ -354,7 +391,7 @@ static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile, TileType t) static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t) { const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(_smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour, &_smallmap_vehicles_andor[t]); + return ApplyMask(_smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour, &_smallmap_vehicles_andor[GetSmallMapTileType(tile, t)]); } /** @@ -409,7 +446,7 @@ static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t) default: /* Ground colour */ const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]); + return ApplyMask(cs->default_colour, &_smallmap_contours_andor[GetSmallMapTileType(tile, t)]); } } @@ -451,6 +488,72 @@ static inline uint32 GetSmallMapVegetationPixels(TileIndex tile, TileType t) } return (GetTropicZone(tile) == TROPICZONE_RAINFOREST) ? MKCOLOUR_XYYX(PC_RAINFOREST, PC_TREES) : MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES); + case MP_OBJECT: { + if (!GetObjectHasViewportMapViewOverride(tile)) return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]); + ObjectViewportMapType vmtype = OVMT_DEFAULT; + const ObjectSpec *spec = ObjectSpec::GetByTile(tile); + if (spec->ctrl_flags & OBJECT_CTRL_FLAG_VPORT_MAP_TYPE) vmtype = spec->vport_map_type; + + switch (vmtype) { + case OVMT_CLEAR: + if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) { + if (IsTileOnWater(tile) && GetObjectGroundType(tile) != OBJECT_GROUND_SHORE) { + t = MP_WATER; + } else { + switch (GetObjectGroundType(tile)) { + case OBJECT_GROUND_GRASS: + if (GetObjectGroundDensity(tile) < 3) return MKCOLOUR_XXXX(PC_BARE_LAND); + if (GetTropicZone(tile) == TROPICZONE_RAINFOREST) return MKCOLOUR_XXXX(PC_RAINFOREST); + return _vegetation_clear_bits[CLEAR_GRASS]; + + case OBJECT_GROUND_SNOW_DESERT: + return _vegetation_clear_bits[_settings_game.game_creation.landscape == LT_TROPIC ? CLEAR_DESERT : CLEAR_SNOW]; + + case OBJECT_GROUND_SHORE: + t = MP_WATER; + break; + + default: + /* This should never be reached, just draw as normal as a fallback */ + break; + } + } + } else { + return MKCOLOUR_XXXX(PC_BARE_LAND); + } + case OVMT_GRASS: + if (GetTropicZone(tile) == TROPICZONE_RAINFOREST) return MKCOLOUR_XXXX(PC_RAINFOREST); + return _vegetation_clear_bits[CLEAR_GRASS]; + case OVMT_ROUGH: + return _vegetation_clear_bits[CLEAR_ROUGH]; + case OVMT_ROCKS: + return _vegetation_clear_bits[CLEAR_ROCKS]; + case OVMT_FIELDS: + return _vegetation_clear_bits[CLEAR_FIELDS]; + case OVMT_SNOW: + return _vegetation_clear_bits[CLEAR_SNOW]; + case OVMT_DESERT: + return _vegetation_clear_bits[CLEAR_DESERT]; + case OVMT_TREES: { + const TreeGround tg = (TreeGround)GB(spec->vport_map_subtype, 0, 4); + if (tg == TREE_GROUND_SNOW_DESERT || tg == TREE_GROUND_ROUGH_SNOW) { + return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR_XYYX(PC_LIGHT_BLUE, PC_TREES) : MKCOLOUR_XYYX(PC_ORANGE, PC_TREES); + } + return (GetTropicZone(tile) == TROPICZONE_RAINFOREST) ? MKCOLOUR_XYYX(PC_RAINFOREST, PC_TREES) : MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES); + } + case OVMT_HOUSE: + t = MP_HOUSE; + break; + case OVMT_WATER: + t = MP_WATER; + break; + + default: + break; + } + return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]); + } + default: return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]); } diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 9a1003567d..ddd4f0d240 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -926,6 +926,7 @@ class NIHObject : public NIHelper { check_ctrl_flag(OBJECT_CTRL_FLAG_USE_LAND_GROUND, "OBJECT_CTRL_FLAG_USE_LAND_GROUND"); check_ctrl_flag(OBJECT_CTRL_FLAG_EDGE_FOUNDATION, "OBJECT_CTRL_FLAG_EDGE_FOUNDATION"); check_ctrl_flag(OBJECT_CTRL_FLAG_FLOOD_RESISTANT, "OBJECT_CTRL_FLAG_FLOOD_RESISTANT"); + check_ctrl_flag(OBJECT_CTRL_FLAG_VPORT_MAP_TYPE, "OBJECT_CTRL_FLAG_VPORT_MAP_TYPE"); } } } diff --git a/src/table/object_land.h b/src/table/object_land.h index 402b6a9153..1c90a459e8 100644 --- a/src/table/object_land.h +++ b/src/table/object_land.h @@ -121,7 +121,7 @@ static const DrawTileSprites _object_hq[] = { #undef TILE_SPRITE_LINE -#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, MAX_DAY + 1, flags, OBJECT_CTRL_FLAG_NONE, {0, 0, 0, 0}, {0, 0, 0, 0}, 0, height, 1, gen_amount, true } +#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, MAX_DAY + 1, flags, OBJECT_CTRL_FLAG_NONE, {0, 0, 0, 0}, {0, 0, 0, 0}, 0, height, 1, gen_amount, true, OVMT_DEFAULT, 0 } /* Climates * T = Temperate diff --git a/src/viewport.cpp b/src/viewport.cpp index 18d6b159d9..991563dbac 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -109,6 +109,8 @@ #include "scope_info.h" #include "scope.h" #include "blitter/32bpp_base.hpp" +#include "object_map.h" +#include "newgrf_object.h" #include #include @@ -2618,10 +2620,143 @@ static const ClearGround _treeground_to_clearground[5] = { CLEAR_SNOW, // TREE_GROUND_ROUGH_SNOW, make it +1 if _settings_game.game_creation.landscape == LT_TROPIC }; +template +static inline uint32 ViewportMapGetColourVegetationTree(const TileIndex tile, const TreeGround tg, const uint td, const uint tc, const uint colour_index, Slope slope) +{ + if (IsTransparencySet(TO_TREES)) { + ClearGround cg = _treeground_to_clearground[tg]; + if (cg == CLEAR_SNOW && _settings_game.game_creation.landscape == LT_TROPIC) cg = CLEAR_DESERT; + uint32 ground_colour = _vp_map_vegetation_clear_colours[slope][cg][td]; + + if (IsInvisibilitySet(TO_TREES)) { + /* Like ground. */ + return ground_colour; + } + + /* Take ground and make it darker. */ + if (is_32bpp) { + return Blitter_32bppBase::MakeTransparent(ground_colour, 192, 256).data; + } else { + /* 8bpp transparent snow trees give blue. Definitely don't want that. Prefer grey. */ + if (cg == CLEAR_SNOW && td > 1) return GREY_SCALE(13 - tc); + return _pal2trsp_remap_ptr[ground_colour]; + } + } else { + if (tg == TREE_GROUND_SNOW_DESERT || tg == TREE_GROUND_ROUGH_SNOW) { + return _vp_map_vegetation_clear_colours[colour_index ^ slope][_settings_game.game_creation.landscape == LT_TROPIC ? CLEAR_DESERT : CLEAR_SNOW][td]; + } else { + const uint rnd = std::min(tc ^ (((tile & 3) ^ (TileY(tile) & 3)) * td), MAX_TREE_COUNT_BY_LANDSCAPE - 1); + return _vp_map_vegetation_tree_colours[slope][tg][rnd]; + } + } +} + +static bool ViewportMapGetColourVegetationCustomObject(uint32 &colour, const TileIndex tile, const uint colour_index, bool is_32bpp, bool show_slope) +{ + ObjectViewportMapType vmtype = OVMT_DEFAULT; + const ObjectSpec *spec = ObjectSpec::GetByTile(tile); + if (spec->ctrl_flags & OBJECT_CTRL_FLAG_VPORT_MAP_TYPE) vmtype = spec->vport_map_type; + + auto do_clear_ground = [&](ClearGround cg, uint multi) -> bool { + Slope slope = SLOPE_FLAT; + if (show_slope) { + slope = GetTileSlope(tile); + extern Foundation GetFoundation_Object(TileIndex tile, Slope tileh); + ApplyFoundationToSlope(GetFoundation_Object(tile, slope), &slope); + slope &= SLOPE_ELEVATED; + } + colour = _vp_map_vegetation_clear_colours[slope][cg][multi]; + return true; + }; + + auto do_water = [&](bool coast) -> bool { + if (is_32bpp) { + uint slope_index = 0; + if (!coast) GET_SLOPE_INDEX(slope_index); + colour = _vp_map_water_colour[slope_index]; + return true; + } + colour = ApplyMask(MKCOLOUR_XXXX(GREY_SCALE(3)), &_smallmap_vehicles_andor[MP_WATER]); + colour = COLOUR_FROM_INDEX(colour); + return false; + }; + + switch (vmtype) { + case OVMT_CLEAR: + if (spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) { + if (IsTileOnWater(tile) && GetObjectGroundType(tile) != OBJECT_GROUND_SHORE) { + return do_water(false); + } else { + switch (GetObjectGroundType(tile)) { + case OBJECT_GROUND_GRASS: + return do_clear_ground(CLEAR_GRASS, GetObjectGroundDensity(tile)); + + case OBJECT_GROUND_SNOW_DESERT: + return do_clear_ground(_settings_game.game_creation.landscape == LT_TROPIC ? CLEAR_DESERT : CLEAR_SNOW, GetObjectGroundDensity(tile)); + + case OBJECT_GROUND_SHORE: + return do_water(true); + + default: + /* This should never be reached, just draw as clear as a fallback */ + return do_clear_ground(CLEAR_GRASS, 0); + } + } + } + return do_clear_ground(CLEAR_GRASS, 0); + case OVMT_GRASS: + return do_clear_ground(CLEAR_GRASS, 3); + case OVMT_ROUGH: + return do_clear_ground(CLEAR_ROUGH, GB(TileX(tile) ^ TileY(tile), 4, 3)); + case OVMT_ROCKS: + return do_clear_ground(CLEAR_ROCKS, TileHash(TileX(tile), TileY(tile)) & 1); + case OVMT_FIELDS: + return (colour_index & 1) ? do_clear_ground(CLEAR_GRASS, 1) : do_clear_ground(CLEAR_FIELDS, spec->vport_map_subtype & 7); + case OVMT_SNOW: + return do_clear_ground(CLEAR_SNOW, 3); + case OVMT_DESERT: + return do_clear_ground(CLEAR_DESERT, 3); + case OVMT_TREES: { + Slope slope = SLOPE_FLAT; + if (show_slope) { + slope = GetTileSlope(tile); + extern Foundation GetFoundation_Object(TileIndex tile, Slope tileh); + ApplyFoundationToSlope(GetFoundation_Object(tile, slope), &slope); + slope &= SLOPE_ELEVATED; + } + TreeGround tg = (TreeGround)GB(spec->vport_map_subtype, 0, 4); + if (tg > TREE_GROUND_ROUGH_SNOW) tg = TREE_GROUND_GRASS; + const uint td = std::min(GB(spec->vport_map_subtype, 4, 4), 3); + const uint tc = Clamp(GB(spec->vport_map_subtype, 8, 4), 1, 4); + if (is_32bpp) { + colour = ViewportMapGetColourVegetationTree(tile, tg, td, tc, colour_index, slope); + } else { + colour = ViewportMapGetColourVegetationTree(tile, tg, td, tc, colour_index, slope); + } + return true; + } + case OVMT_HOUSE: + colour = ApplyMask(MKCOLOUR_XXXX(GREY_SCALE(3)), &_smallmap_vehicles_andor[MP_HOUSE]); + colour = COLOUR_FROM_INDEX(colour); + return false; + case OVMT_WATER: + return do_water(false); + + default: + return false; + } +} + template static inline uint32 ViewportMapGetColourVegetation(const TileIndex tile, TileType t, const uint colour_index) { uint32 colour; + + auto set_default_colour = [&](TileType ttype) { + colour = ApplyMask(MKCOLOUR_XXXX(GREY_SCALE(3)), &_smallmap_vehicles_andor[ttype]); + colour = COLOUR_FROM_INDEX(colour); + }; + switch (t) { case MP_CLEAR: { Slope slope = show_slope ? (Slope) (GetTileSlope(tile, nullptr) & 15) : SLOPE_FLAT; @@ -2641,33 +2776,17 @@ static inline uint32 ViewportMapGetColourVegetation(const TileIndex tile, TileTy case MP_TREES: { const TreeGround tg = GetTreeGround(tile); const uint td = GetTreeDensity(tile); + const uint tc = GetTreeCount(tile); Slope slope = show_slope ? (Slope) (GetTileSlope(tile, nullptr) & 15) : SLOPE_FLAT; - if (IsTransparencySet(TO_TREES)) { - ClearGround cg = _treeground_to_clearground[tg]; - if (cg == CLEAR_SNOW && _settings_game.game_creation.landscape == LT_TROPIC) cg = CLEAR_DESERT; - uint32 ground_colour = _vp_map_vegetation_clear_colours[slope][cg][td]; + return ViewportMapGetColourVegetationTree(tile, tg, td, tc, colour_index, slope); + } - if (IsInvisibilitySet(TO_TREES)) { - /* Like ground. */ - return ground_colour; - } - - /* Take ground and make it darker. */ - if (is_32bpp) { - return Blitter_32bppBase::MakeTransparent(ground_colour, 192, 256).data; - } else { - /* 8bpp transparent snow trees give blue. Definitely don't want that. Prefer grey. */ - if (cg == CLEAR_SNOW && td > 1) return GREY_SCALE(13 - GetTreeCount(tile)); - return _pal2trsp_remap_ptr[ground_colour]; - } - } else { - if (tg == TREE_GROUND_SNOW_DESERT || tg == TREE_GROUND_ROUGH_SNOW) { - return _vp_map_vegetation_clear_colours[colour_index ^ slope][_settings_game.game_creation.landscape == LT_TROPIC ? CLEAR_DESERT : CLEAR_SNOW][td]; - } else { - const uint rnd = std::min(GetTreeCount(tile) ^ (((tile & 3) ^ (TileY(tile) & 3)) * td), MAX_TREE_COUNT_BY_LANDSCAPE - 1); - return _vp_map_vegetation_tree_colours[slope][tg][rnd]; - } + case MP_OBJECT: { + set_default_colour(MP_OBJECT); + if (GetObjectHasViewportMapViewOverride(tile)) { + if (ViewportMapGetColourVegetationCustomObject(colour, tile, colour_index, is_32bpp, show_slope)) return colour; } + break; } case MP_WATER: @@ -2676,11 +2795,13 @@ static inline uint32 ViewportMapGetColourVegetation(const TileIndex tile, TileTy if (IsTileType(tile, MP_WATER) && GetWaterTileType(tile) != WATER_TILE_COAST) GET_SLOPE_INDEX(slope_index); return _vp_map_water_colour[slope_index]; } - /* FALL THROUGH */ + set_default_colour(t); + break; default: colour = ApplyMask(MKCOLOUR_XXXX(GREY_SCALE(3)), &_smallmap_vehicles_andor[t]); colour = COLOUR_FROM_INDEX(colour); + set_default_colour(t); break; } @@ -2709,6 +2830,37 @@ static inline uint32 ViewportMapGetColourIndustries(const TileIndex tile, const t2 = IsTileOnWater(tile) ? MP_WATER : MP_CLEAR; } + if (t == MP_OBJECT && GetObjectHasViewportMapViewOverride(tile)) { + ObjectViewportMapType vmtype = OVMT_DEFAULT; + const ObjectSpec *spec = ObjectSpec::GetByTile(tile); + if (spec->ctrl_flags & OBJECT_CTRL_FLAG_VPORT_MAP_TYPE) vmtype = spec->vport_map_type; + if (vmtype == OVMT_CLEAR && spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) { + if (IsTileOnWater(tile) && GetObjectGroundType(tile) != OBJECT_GROUND_SHORE) { + vmtype = OVMT_WATER; + } + } + switch (vmtype) { + case OVMT_DEFAULT: + break; + + case OVMT_TREES: + t2 = MP_TREES; + break; + + case OVMT_HOUSE: + t2 = MP_HOUSE; + break; + + case OVMT_WATER: + t2 = MP_WATER; + break; + + default: + t2 = MP_CLEAR; + break; + } + } + if (is_32bpp && t2 == MP_WATER) { uint slope_index = 0; if (t != MP_INDUSTRY && IsTileType(tile, MP_WATER) && GetWaterTileType(tile) != WATER_TILE_COAST) GET_SLOPE_INDEX(slope_index); ///< Ignore industry on water not shown on map. @@ -2791,9 +2943,38 @@ static inline uint32 ViewportMapGetColourRoutes(const TileIndex tile, TileType t return IS32(PC_DARK_GREY); case MP_HOUSE: - case MP_OBJECT: return IS32(colour_index & 1 ? PC_DARK_RED : GREY_SCALE(3)); + case MP_OBJECT: { + ObjectViewportMapType vmtype = OVMT_DEFAULT; + if (GetObjectHasViewportMapViewOverride(tile)) { + const ObjectSpec *spec = ObjectSpec::GetByTile(tile); + if (spec->ctrl_flags & OBJECT_CTRL_FLAG_VPORT_MAP_TYPE) vmtype = spec->vport_map_type; + if (vmtype == OVMT_CLEAR && spec->ctrl_flags & OBJECT_CTRL_FLAG_USE_LAND_GROUND) { + if (IsTileOnWater(tile) && GetObjectGroundType(tile) != OBJECT_GROUND_SHORE) { + vmtype = OVMT_WATER; + } + } + } + switch (vmtype) { + case OVMT_DEFAULT: + case OVMT_HOUSE: + return IS32(colour_index & 1 ? PC_DARK_RED : GREY_SCALE(3)); + + case OVMT_WATER: + if (is_32bpp) { + return _vp_map_water_colour[0]; + } else { + return PC_WATER; + } + + default: + colour = COLOUR_FROM_INDEX(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[TileHeight(tile)]); + break; + } + break; + } + case MP_STATION: switch (GetStationType(tile)) { case STATION_RAIL: return IS32(PC_VERY_DARK_BROWN);