diff --git a/docs/newgrf-additions-nml.html b/docs/newgrf-additions-nml.html index 665b601cd3..f9b3c549be 100644 --- a/docs/newgrf-additions-nml.html +++ b/docs/newgrf-additions-nml.html @@ -29,6 +29,7 @@

Features with separate pages

Builtin functions

diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index a5836a364a..52c792fd97 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -29,6 +29,7 @@

Features with separate pages


@@ -740,6 +741,7 @@ +
Feature nameDescription
road_stopsCustom road stops (bus stops, lorry stops and road waypoints)
new_landscapeCustom landscape graphics (currently rocky tiles only)
diff --git a/docs/newgrf-newlandscape-nml.html b/docs/newgrf-newlandscape-nml.html new file mode 100644 index 0000000000..d6e058d028 --- /dev/null +++ b/docs/newgrf-newlandscape-nml.html @@ -0,0 +1,126 @@ + + + + + JGR's Patchpack - NewGRF New Landscape Addition to NewGRF Specifications in NML + + + +

NewGRF New Landscape Addition to NewGRF Specifications in JGR's Patchpack in NML

+

This document describes the non-standard addition of the NewGRF new landscape feature to the Official OpenTTD NML Specifications, as implemented in this patchpack, and the associated NML fork

+

This feature allows NewGRF custom graphics using switches and spritesets for landscape tiles. Currently this includes: rock tiles.

+

This feature may not necessarily match implementations of additional landscape graphics features in other patches, branches, etc.
+ This feature as implemented here MAY also be present in other patchpacks.

+ +

The feature identifier is FEAT_NEWLANDSCAPE.
+ There is no permanent storage associated with this feature.

+ +

See the NewGRF additions (NML) document for background information on additions to NML.

+ +

See the associated non-NML document for more details on the NewGRF new landscape feature.

+ +

This feature will be automatically skipped when loaded into a version of OpenTTD which does not support this feature.
+ If this feature is the only significant thing in this GRF, then extended_feature_test("new_landscape") SHOULD be called and some message, error or other form of + signalling to the user used to inform the user that this version of OpenTTD does not support the feature, if the return value is false.
+ Otherwise the GRF could silently do nothing instead of the expected functionality, creating confusion for end users.

+ +

Sections: +

+ +

New Landscape IDs

+

+ The ID field for an item must be set to one of the IDs in the table below (further IDs may be allocated for other purposes in future). + + + +
IDLandscape type
NEW_LANDSCAPE_ID_ROCKSRocky tiles
+

+

+ +

New Landscape Properties

+ + + + + + +
PropertyValue rangeComment
enable_recolour0 or 1 + Enable recolouring of graphics.
+ When enabled, in addition to returning a sprite, register 0x100 may be set to the following using STORE_TEMP: + + + + +
BitsMeaning
0 - 23Recolour sprite to use. Set to 0 for no recolouring.
24 - 31Reserved, set to zero.
+
+ +

New Landscape Variables

+ +

A number of variables are shared between new landscape and stations. These are listed on the stations page.

+ + + + + + + + +
NameValue rangeComment
terrain_typeTILETYPE_XXXXXX = NORMAL | DESERT | RAIN_FOREST | SNOW
tile_slopeSLOPE_XXXSee tile slopes for an overview of possible values
tile_height0..255Height of the lowest corner of the tile
tile_hash0..4294967295Hash value derived from the coordinates of the tile, suitable for pseudo-randomising graphics
landscape_typeNEW_LANDSCAPE_TYPE_XXXLandscape type
XXX = ROCKS
+
+ Variables that require one or more parameters: + + + + + + + + + + +
NameArgumentsValue rangeComment
nearby_tile_slopex, y offset (-8..7)SLOPE_XXXSlope of a nearby tile
nearby_tile_is_same_typex, y offset (-8..7)0 | 1Is nearby tile the same landscape type as this one?
nearby_tile_is_waterx, y offset (-8..7)0 | 1Is nearby tile a water tile?
nearby_tile_terrain_typex, y offset (-8..7)See terrain_type
nearby_tile_water_classx, y offset (-8..7)WATER_CLASS_XXXXXX = [NONE | SEA | CANAL | RIVER]
Note that tiles for which nearby_tile_is_water is 0 may still have a water class, e.g. industry tiles with water beneath them.
nearby_tile_heightx, y offset (-8..7)The minimum height of the given tile in height level units
nearby_tile_classx, y offset (-8..7)tile class
nearby_tile_infox, y offset (-8..7)Above nearby tile variables in one variable (all of variable 0x60)
+ +

Syntax example

+

+

+grf {
+	...
+}
+
+if (!extended_feature_test("new_landscape")) {
+	error(FATAL, string(STR_UNSUPPORTED_VERSION));
+}
+
+
+spriteset spriteset_rocks {
+	/* 19 tile sprites in the standard order */
+}
+
+switch (FEAT_NEWLANDSCAPE, SELF, switch_rocks, ...) {
+	...
+}
+
+item (FEAT_NEWLANDSCAPE, item_rocks, NEW_LANDSCAPE_ID_ROCKS)  {
+	property {
+		enable_recolour: 0;
+	}
+	graphics {
+		default: switch_rocks;
+	}
+}
+		
+

+ + diff --git a/docs/newgrf-newlandscape.html b/docs/newgrf-newlandscape.html new file mode 100644 index 0000000000..8362461d75 --- /dev/null +++ b/docs/newgrf-newlandscape.html @@ -0,0 +1,124 @@ + + + + + JGR's Patchpack - NewGRF New Landscape Addition to NewGRF Specifications + + + +

NewGRF New Landscape Addition to NewGRF Specifications in JGR's Patchpack

+

This document describes the non-standard addition of the NewGRF new landscape feature to the Official OpenTTD NewGRF Specifications, as implemented in this patchpack.

+

This feature allows NewGRF custom graphics using Action 1/2/3 for landscape tiles. Currently this includes: rock tiles.

+

This feature may not necessarily match implementations of additional landscape graphics features in other patches, branches, etc.
+ This feature as implemented here MAY also be present in other patchpacks.

+

See the NewGRF additions document for background information on additions to the NewGRF specifications.

+

The functionality listed below is also supported in a fork of NML, see the associated NML new landscape and NML additions documents for more details.

+

NewGRFs which use this feature SHOULD use the feature testing mechanism to check whether the new landscape feature and/or feature ID mapping is supported.

+

NewGRFs which use this feature MUST use the feature ID mapping mechanism to map the non-standard NewGRF road stop feature to a local feature ID.

+

This feature is indicated by the feature name: new_landscape, version 1.
+ The feature name to use for feature ID mapping is new_landscape.
+ Features/properties/variables which require a higher version will indicate the required version. Unless indicated otherwise these will fall back to doing nothing on versions which do not support them.

+ +

IDs:

+ The ID field for Actions 0 and 3 must be set to one of the IDs in the table below (further IDs may be allocated for other purposes in future). + + + +
IDLandscape type
0Rocky tiles
+

+ +

Actions:

+

+ +

Action 0 - New Landscape

+ +

See the Action 0 Specification for background information.

+ + Properties: + + + +
Mappable nameSize in bytesDescription
newlandscape_enable_recolour1Enable recolour
+ +

Enable recolouring for new landscape graphics (mappable property: newlandscape_enable_recolour)

+

When enabled, in addition to returning a sprite, register 0x100 may be set to the following: + + + + +
BitsMeaning
0 - 23Recolour sprite to use. Set to 0 for no recolouring.
24 - 31Reserved, set to zero.

+

The property length is 1 byte. 0 is disabled (default). 1 is enabled.

+ +

Action 2 - New Landscape

+ +

See the Action 2 Specification for background information.

+ +

New landscape does not use the special sprite layout format.

+
+ +

Variational Action 2 - New Landscape

+ +

See the Variational Action 2 Specification for background information.

+ + Variables: + + + + + + + + +
NumberMappable nameDescription
40newlandscape_terrain_typeTerrain type
41newlandscape_tile_slopeTile Slope
42newlandscape_tile_heightTile Height
43newlandscape_tile_hashTile Hash
44newlandscape_landscape_typeLandscape Type
60newlandscape_land_info_nearby_tilesLand info of nearby tiles
+ +

Tile terrain type (40, or mappable variable: newlandscape_terrain_type)

+

This has the same value as bits 0 - 7 of object (feature F) variable 41. + + + + + + +
ValueMeaning
0Normal
1Desert
2Rainforest
4On or above snowline
+

+ +

Tile slope (41, or mappable variable: newlandscape_tile_slope)

+

This has the same value as bits 0 - 7 of industry tile (feature 9) variable 60 for this tile.

+ +

Tile height (42, or mappable variable: newlandscape_tile_height)

+

The height of the lowest corner of the tile (in units of 1).

+ +

Tile hash (43, or mappable variable: newlandscape_tile_hash)

+

Hash value derived from the coordinates of the tile, suitable for pseudo-randomising graphics.

+ +

Land info of nearby tile (60, or mappable variable: newlandscape_land_info_nearby_tiles)

+

This has the same value as industry tile (feature 9) variable 60.

+ +
+ +

Action 3 - New Landscape

+ +

See the Action 3 Specification for background information.

+ +

Note that this is not a generic callback, the sprite group must be assigned to an ID in the IDs table. + + + +
Action 3 IDExpected number of spritesLandscape type
019Rocky tiles
+ Cargo type definitions are not used. Only the default set ID is used. +

+

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

+ + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d9ddd72664..e10edcfadf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -272,6 +272,8 @@ add_files( newgrf_industrytiles.cpp newgrf_industrytiles.h newgrf_industrytiles_analysis.h + newgrf_newlandscape.cpp + newgrf_newlandscape.h newgrf_newsignals.cpp newgrf_newsignals.h newgrf_object.cpp diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp index 77fcfecf1f..5fd17aaaec 100644 --- a/src/clear_cmd.cpp +++ b/src/clear_cmd.cpp @@ -16,6 +16,7 @@ #include "water.h" #include "core/random_func.hpp" #include "newgrf_generic.h" +#include "newgrf_newlandscape.h" #include "table/strings.h" #include "table/sprites.h" @@ -73,6 +74,29 @@ SpriteID GetSpriteIDForRocks(const Slope slope, const uint tile_hash) return ((HasGrfMiscBit(GMB_SECOND_ROCKY_TILE_SET) && (tile_hash & 1)) ? SPR_FLAT_ROCKY_LAND_2 : SPR_FLAT_ROCKY_LAND_1) + SlopeToSpriteOffset(slope); } +inline SpriteID GetSpriteIDForRocksUsingOffset(const uint slope_to_sprite_offset, const uint x, const uint y) +{ + return ((HasGrfMiscBit(GMB_SECOND_ROCKY_TILE_SET) && (TileHash(x, y) & 1)) ? SPR_FLAT_ROCKY_LAND_2 : SPR_FLAT_ROCKY_LAND_1) + slope_to_sprite_offset; +} + +void DrawCustomSpriteIDForRocks(const TileInfo *ti) +{ + uint8 slope_to_sprite_offset = SlopeToSpriteOffset(ti->tileh); + + for (const GRFFile *grf : _new_landscape_rocks_grfs) { + NewLandscapeResolverObject object(grf, ti, NEW_LANDSCAPE_ROCKS); + + const SpriteGroup *group = object.Resolve(); + if (group != nullptr && group->GetNumResults() > slope_to_sprite_offset) { + PaletteID pal = HasBit(grf->new_landscape_ctrl_flags, NLCF_ROCKS_RECOLOUR_ENABLED) ? GB(GetRegister(0x100), 0, 24) : PAL_NONE; + DrawGroundSprite(group->GetResult() + slope_to_sprite_offset, pal); + return; + } + } + + DrawGroundSprite(GetSpriteIDForRocksUsingOffset(slope_to_sprite_offset, ti->x, ti->y), PAL_NONE); +} + SpriteID GetSpriteIDForFields(const Slope slope, const uint field_type) { return _clear_land_sprites_farmland[field_type] + SlopeToSpriteOffset(slope); @@ -135,7 +159,9 @@ static void DrawTile_Clear(TileInfo *ti, DrawTileProcParams params) break; case CLEAR_ROCKS: - if (!params.no_ground_tiles) DrawGroundSprite(GetSpriteIDForRocks(ti->tileh, TileHash(ti->x, ti->y)), PAL_NONE); + if (!params.no_ground_tiles) { + DrawCustomSpriteIDForRocks(ti); + } break; case CLEAR_FIELDS: diff --git a/src/newgrf.cpp b/src/newgrf.cpp index c17c5349e2..453aa336f4 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -35,6 +35,7 @@ #include "newgrf_airport.h" #include "newgrf_object.h" #include "newgrf_newsignals.h" +#include "newgrf_newlandscape.h" #include "newgrf_extension.h" #include "rev.h" #include "fios.h" @@ -5168,6 +5169,38 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const return ret; } +/** + * Define properties for new landscape + * @param id Landscape type. + * @param numinfo Number of subsequent IDs to change the property for. + * @param prop The property to change. + * @param buf The property value. + * @return ChangeInfoResult. + */ +static ChangeInfoResult NewLandscapeChangeInfo(uint id, int numinfo, int prop, const GRFFilePropertyRemapEntry *mapping_entry, ByteReader *buf) +{ + /* Properties which are handled per item */ + ChangeInfoResult ret = CIR_SUCCESS; + for (int i = 0; i < numinfo; i++) { + switch (prop) { + case A0RPI_NEWLANDSCAPE_ENABLE_RECOLOUR: { + if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break; + bool enabled = (buf->ReadByte() != 0 ? 1 : 0); + if (id == NLA3ID_CUSTOM_ROCKS) { + SB(_cur.grffile->new_landscape_ctrl_flags, NLCF_ROCKS_RECOLOUR_ENABLED, 1, enabled); + } + break; + } + + default: + ret = HandleAction0PropertyDefault(buf, prop); + break; + } + } + + return ret; +} + static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, GrfSpecFeature feature, int property) { switch (cir) { @@ -5248,6 +5281,7 @@ static const char *_feature_names[] = { "ROADTYPES", "TRAMTYPES", "ROADSTOPS", + "NEWLANDSCAPE", }; static_assert(lengthof(_feature_names) == GSF_END); @@ -5353,6 +5387,7 @@ static void FeatureChangeInfo(ByteReader *buf) /* GSF_ROADTYPES */ RoadTypeChangeInfo, /* GSF_TRAMTYPES */ TramTypeChangeInfo, /* GSF_ROADSTOPS */ RoadStopChangeInfo, + /* GSF_NEWLANDSCAPE */ NewLandscapeChangeInfo, }; static_assert(GSF_END == lengthof(handler)); static_assert(lengthof(handler) == lengthof(_cur.grffile->action0_property_remaps), "Action 0 feature list length mismatch"); @@ -8060,6 +8095,7 @@ static void NewSpriteGroup(ByteReader *buf) case GSF_ROADTYPES: case GSF_TRAMTYPES: case GSF_SIGNALS: + case GSF_NEWLANDSCAPE: { byte num_loaded = type; byte num_loading = buf->ReadByte(); @@ -8861,6 +8897,39 @@ static void RoadStopMapSpriteGroup(ByteReader *buf, uint8 idcount) } } +static void NewLandscapeMapSpriteGroup(ByteReader *buf, uint8 idcount) +{ + uint8 *ids = AllocaM(uint8, idcount); + for (uint i = 0; i < idcount; i++) { + ids[i] = buf->ReadByte(); + } + + /* Skip the cargo type section, we only care about the default group */ + uint8 cidcount = buf->ReadByte(); + buf->Skip(cidcount * 3); + + uint16 groupid = buf->ReadWord(); + if (!IsValidGroupID(groupid, "NewLandscapeMapSpriteGroup")) return; + + for (uint i = 0; i < idcount; i++) { + uint8 id = ids[i]; + + switch (id) { + case NLA3ID_CUSTOM_ROCKS: + _cur.grffile->new_rocks_group = GetGroupByID(groupid); + if (!HasBit(_cur.grffile->new_landscape_ctrl_flags, NLCF_ROCKS_SET)) { + SetBit(_cur.grffile->new_landscape_ctrl_flags, NLCF_ROCKS_SET); + _new_landscape_rocks_grfs.push_back(_cur.grffile); + } + break; + + default: + grfmsg(1, "NewLandscapeMapSpriteGroup: ID not implemented: %d", id); + break; + } + } +} + /* Action 0x03 */ static void FeatureMapSpriteGroup(ByteReader *buf) { @@ -8969,6 +9038,10 @@ static void FeatureMapSpriteGroup(ByteReader *buf) RoadStopMapSpriteGroup(buf, idcount); return; + case GSF_NEWLANDSCAPE: + NewLandscapeMapSpriteGroup(buf, idcount); + return; + default: grfmsg(1, "FeatureMapSpriteGroup: Unsupported feature %s, skipping", GetFeatureString(feature_ref)); return; @@ -12229,6 +12302,7 @@ static void ResetNewGRF() _grf_files.clear(); _cur.grffile = nullptr; _new_signals_grfs.clear(); + _new_landscape_rocks_grfs.clear(); } /** Clear all NewGRF errors */ @@ -12415,6 +12489,9 @@ GRFFile::GRFFile(const GRFConfig *config) this->new_signal_ctrl_flags = 0; this->new_signal_extra_aspects = 0; + this->new_rocks_group = nullptr; + this->new_landscape_ctrl_flags = 0; + /* Mark price_base_multipliers as 'not set' */ for (Price i = PR_BEGIN; i < PR_END; i++) { this->price_base_multipliers[i] = INVALID_PRICE_MODIFIER; diff --git a/src/newgrf.h b/src/newgrf.h index 39743e924a..12bdd0fc0c 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -89,6 +89,7 @@ enum GrfSpecFeature : uint8 { GSF_TRAMTYPES, GSF_ROADSTOPS, + GSF_NEWLANDSCAPE, GSF_END, GSF_REAL_FEATURE_END = GSF_ROADSTOPS, @@ -278,11 +279,22 @@ enum { NEW_SIGNALS_MAX_EXTRA_ASPECT = 6, }; -/** New signal control flags. */ +/** New signal action 3 IDs. */ enum NewSignalAction3ID { NSA3ID_CUSTOM_SIGNALS = 0, ///< Action 3 ID for custom signal sprites }; +/** New landscape control flags. */ +enum NewLandscapeCtrlFlags { + NLCF_ROCKS_SET = 0, ///< Custom landscape rocks sprites group set. + NLCF_ROCKS_RECOLOUR_ENABLED = 1, ///< Recolour sprites enabled for rocks +}; + +/** New landscape action 3 IDs. */ +enum NewLandscapeAction3ID { + NLA3ID_CUSTOM_ROCKS = 0, ///< Action 3 ID for custom landscape sprites +}; + /** GRFFile control flags. */ enum GRFFileCtrlFlags { GFCF_HAVE_FEATURE_ID_REMAP = 0, ///< This GRF has one or more feature ID mappings @@ -346,6 +358,9 @@ struct GRFFile : ZeroedMemoryAllocator { byte new_signal_ctrl_flags; ///< Ctrl flags for new signals byte new_signal_extra_aspects; ///< Number of extra aspects for new signals + const SpriteGroup *new_rocks_group; ///< New landscape rocks group + byte new_landscape_ctrl_flags; ///< Ctrl flags for new landscape + byte ctrl_flags; ///< General GRF control flags btree::btree_map string_map; ///< Map of local GRF string ID to string ID diff --git a/src/newgrf_extension.cpp b/src/newgrf_extension.cpp index 7608da281f..45512b69fa 100644 --- a/src/newgrf_extension.cpp +++ b/src/newgrf_extension.cpp @@ -52,12 +52,14 @@ extern const GRFFeatureInfo _grf_feature_list[] = { GRFFeatureInfo("action0_object_flood_resistant", 1), GRFFeatureInfo("action0_object_viewport_map_tile_type", 1), GRFFeatureInfo("road_stops", 2), + GRFFeatureInfo("new_landscape", 1), GRFFeatureInfo(), }; /** Action14 remappable feature list */ extern const GRFFeatureMapDefinition _grf_remappable_features[] = { GRFFeatureMapDefinition(GSF_ROADSTOPS, "road_stops"), + GRFFeatureMapDefinition(GSF_NEWLANDSCAPE, "new_landscape"), GRFFeatureMapDefinition(), }; @@ -105,6 +107,7 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = { GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_MIN_BRIDGE_HEIGHT, "roadstop_min_bridge_height"), GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_DISALLOWED_BRIDGE_PILLARS, "roadstop_disallowed_bridge_pillars"), GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_COST_MULTIPLIERS, "roadstop_cost_multipliers"), + GRFPropertyMapDefinition(GSF_NEWLANDSCAPE, A0RPI_NEWLANDSCAPE_ENABLE_RECOLOUR, "newlandscape_enable_recolour"), GRFPropertyMapDefinition(), }; @@ -128,6 +131,12 @@ extern const GRFVariableMapDefinition _grf_action2_remappable_variables[] = { GRFVariableMapDefinition(GSF_ROADSTOPS, 0x6A, "roadstop_road_stop_grfid_nearby_tiles"), GRFVariableMapDefinition(GSF_RAILTYPES, A2VRI_RAILTYPE_SIGNAL_RESTRICTION_INFO, "railtype_signal_restriction_info"), GRFVariableMapDefinition(GSF_SIGNALS, A2VRI_SIGNALS_SIGNAL_RESTRICTION_INFO, "signals_signal_restriction_info"), + GRFVariableMapDefinition(GSF_NEWLANDSCAPE, 0x40, "newlandscape_terrain_type"), + GRFVariableMapDefinition(GSF_NEWLANDSCAPE, 0x41, "newlandscape_tile_slope"), + GRFVariableMapDefinition(GSF_NEWLANDSCAPE, 0x42, "newlandscape_tile_height"), + GRFVariableMapDefinition(GSF_NEWLANDSCAPE, 0x43, "newlandscape_tile_hash"), + GRFVariableMapDefinition(GSF_NEWLANDSCAPE, 0x44, "newlandscape_landscape_type"), + GRFVariableMapDefinition(GSF_NEWLANDSCAPE, 0x60, "newlandscape_land_info_nearby_tiles"), GRFVariableMapDefinition(), }; diff --git a/src/newgrf_extension.h b/src/newgrf_extension.h index 2b282b3e83..88a6f3d518 100644 --- a/src/newgrf_extension.h +++ b/src/newgrf_extension.h @@ -54,6 +54,7 @@ enum Action0RemapPropertyIds { A0RPI_ROADSTOP_MIN_BRIDGE_HEIGHT, A0RPI_ROADSTOP_DISALLOWED_BRIDGE_PILLARS, A0RPI_ROADSTOP_COST_MULTIPLIERS, + A0RPI_NEWLANDSCAPE_ENABLE_RECOLOUR, }; diff --git a/src/newgrf_newlandscape.cpp b/src/newgrf_newlandscape.cpp new file mode 100644 index 0000000000..8d8e7e8029 --- /dev/null +++ b/src/newgrf_newlandscape.cpp @@ -0,0 +1,102 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_newlandscape.cpp NewGRF handling of new landscape. */ + +#include "stdafx.h" +#include "debug.h" +#include "newgrf_newlandscape.h" +#include "newgrf_extension.h" +#include "map_func.h" +#include "clear_map.h" +#include "core/hash_func.hpp" + +#include "safeguards.h" + +std::vector _new_landscape_rocks_grfs; + +/* virtual */ uint32 NewLandscapeScopeResolver::GetVariable(uint16 variable, uint32 parameter, GetVariableExtra *extra) const +{ + if (unlikely(this->ti->tile == INVALID_TILE)) { + switch (variable) { + case 0x40: return 0; + case 0x41: return 0; + case 0x42: return 0; + case 0x43: return 0; + case 0x44: return this->landscape_type; + case 0x60: return 0; + } + } + + switch (variable) { + case 0x40: + return GetTerrainType(this->ti->tile, TCX_NORMAL); + + case 0x41: + return this->ti->tileh; + + case 0x42: + return this->ti->z / TILE_HEIGHT; + + case 0x43: + /* Knuth hash */ + return SimpleHash32(this->ti->tile); + + case 0x44: + return this->landscape_type; + + case 0x60: { + TileIndex tile = this->ti->tile; + if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required + uint32 result = 0; + if (extra->mask & ~0x100) result |= GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8, extra->mask); + if (extra->mask & 0x100) { + switch (this->landscape_type) { + case NEW_LANDSCAPE_ROCKS: + if (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_ROCKS)) result |= 0x100; + break; + } + } + return result; + } + } + + DEBUG(grf, 1, "Unhandled new landscape tile variable 0x%X", variable); + + extra->available = false; + return UINT_MAX; +} + +/* virtual */ const SpriteGroup *NewLandscapeResolverObject::ResolveReal(const RealSpriteGroup *group) const +{ + if (!group->loading.empty()) return group->loading[0]; + if (!group->loaded.empty()) return group->loaded[0]; + return nullptr; +} + +GrfSpecFeature NewLandscapeResolverObject::GetFeature() const +{ + return GSF_NEWLANDSCAPE; +} + +NewLandscapeResolverObject::NewLandscapeResolverObject(const GRFFile *grffile, const TileInfo *ti, NewLandscapeType landscape_type, uint32 param1, uint32 param2) + : ResolverObject(grffile, CBID_NO_CALLBACK, param1, param2), newlandscape_scope(*this, ti, landscape_type) +{ + if (grffile != nullptr) { + switch (landscape_type) { + case NEW_LANDSCAPE_ROCKS: + this->root_spritegroup = grffile->new_rocks_group; + break; + + default: + this->root_spritegroup = nullptr; + break; + } + } else { + this->root_spritegroup = nullptr; + } +} diff --git a/src/newgrf_newlandscape.h b/src/newgrf_newlandscape.h new file mode 100644 index 0000000000..307b88986e --- /dev/null +++ b/src/newgrf_newlandscape.h @@ -0,0 +1,55 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_newlandscape.h NewGRF handling of new landscape. */ + +#ifndef NEWGRF_NEWLANDSCAPE_H +#define NEWGRF_NEWLANDSCAPE_H + +#include "newgrf_commons.h" +#include "newgrf_spritegroup.h" + +extern std::vector _new_landscape_rocks_grfs; + +enum NewLandscapeType : uint8 { + NEW_LANDSCAPE_ROCKS, +}; + +struct TileInfo; + +/** Resolver for the new landscape scope. */ +struct NewLandscapeScopeResolver : public ScopeResolver { + const TileInfo *ti; + NewLandscapeType landscape_type; + + NewLandscapeScopeResolver(ResolverObject &ro, const TileInfo *ti, NewLandscapeType landscape_type) + : ScopeResolver(ro), ti(ti), landscape_type(landscape_type) + { + } + + uint32 GetVariable(uint16 variable, uint32 parameter, GetVariableExtra *extra) const override; +}; + +struct NewLandscapeResolverObject : public ResolverObject { + NewLandscapeScopeResolver newlandscape_scope; + + NewLandscapeResolverObject(const GRFFile *grffile, const TileInfo *ti, NewLandscapeType landscape_type, uint32 param1 = 0, uint32 param2 = 0); + + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override + { + switch (scope) { + case VSG_SCOPE_SELF: return &this->newlandscape_scope; + default: return ResolverObject::GetScope(scope, relative); + } + } + + const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; + + GrfSpecFeature GetFeature() const override; +}; + +#endif /* NEWGRF_NEWLANDSCAPE_H */ diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 028d078ec9..b4b2fe1f0b 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -1534,6 +1534,7 @@ static const NIFeature * const _nifeatures[] = { &_nif_roadtype, // GSF_ROADTYPES &_nif_roadtype, // GSF_TRAMTYPES &_nif_roadstop, // GSF_ROADSTOPS + nullptr, // GSF_NEWLANDSCAPE &_nif_town, // GSF_FAKE_TOWNS &_nif_station_struct, // GSF_FAKE_STATION_STRUCT };