OpenTTD Source: src/newgrf/newgrf_act5.cpp Source File

OpenTTD Source 15.0-RC2

newgrf_act5.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#include "../stdafx.h"
11#include "../debug.h"
12#include "../gfx_type.h"
13#include "../newgrf_act5.h"
14#include "../spritecache.h"
15#include "newgrf_bytereader.h"
16#include "newgrf_internal.h"
17
18#include "../table/sprites.h"
19
20#include "../safeguards.h"
21
30 static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_sprites, std::string_view name)
31{
32
33 if (offset >= max_sprites) {
34 GrfMsg(1, "GraphicsNew: {} sprite offset must be less than {}, skipping", name, max_sprites);
35 uint orig_num = num;
36 num = 0;
37 return orig_num;
38 }
39
40 if (offset + num > max_sprites) {
41 GrfMsg(4, "GraphicsNew: {} sprite overflow, truncating...", name);
42 uint orig_num = num;
43 num = std::max(max_sprites - offset, 0);
44 return orig_num - num;
45 }
46
47 return 0;
48}
49
50
52 static constexpr auto _action5_types = std::to_array<Action5Type>({
53 /* Note: min_sprites should not be changed. Therefore these constants are directly here and not in sprites.h */
54 /* 0x00 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x00" },
55 /* 0x01 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x01" },
56 /* 0x02 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x02" },
57 /* 0x03 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x03" },
58 /* 0x04 */ { A5BLOCK_ALLOW_OFFSET, SPR_SIGNALS_BASE, 1, PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT, "Signal graphics" },
59 /* 0x05 */ { A5BLOCK_ALLOW_OFFSET, SPR_ELRAIL_BASE, 1, ELRAIL_SPRITE_COUNT, "Rail catenary graphics" },
60 /* 0x06 */ { A5BLOCK_ALLOW_OFFSET, SPR_SLOPES_BASE, 1, NORMAL_AND_HALFTILE_FOUNDATION_SPRITE_COUNT, "Foundation graphics" },
61 /* 0x07 */ { A5BLOCK_INVALID, 0, 75, 0, "TTDP GUI graphics" }, // Not used by OTTD.
62 /* 0x08 */ { A5BLOCK_ALLOW_OFFSET, SPR_CANALS_BASE, 1, CANALS_SPRITE_COUNT, "Canal graphics" },
63 /* 0x09 */ { A5BLOCK_ALLOW_OFFSET, SPR_ONEWAY_BASE, 1, ONEWAY_SPRITE_COUNT, "One way road graphics" },
64 /* 0x0A */ { A5BLOCK_ALLOW_OFFSET, SPR_2CCMAP_BASE, 1, TWOCCMAP_SPRITE_COUNT, "2CC colour maps" },
65 /* 0x0B */ { A5BLOCK_ALLOW_OFFSET, SPR_TRAMWAY_BASE, 1, TRAMWAY_SPRITE_COUNT, "Tramway graphics" },
66 /* 0x0C */ { A5BLOCK_INVALID, 0, 133, 0, "Snowy temperate tree" }, // Not yet used by OTTD.
67 /* 0x0D */ { A5BLOCK_FIXED, SPR_SHORE_BASE, 16, SHORE_SPRITE_COUNT, "Shore graphics" },
68 /* 0x0E */ { A5BLOCK_INVALID, 0, 0, 0, "New Signals graphics" }, // Not yet used by OTTD.
69 /* 0x0F */ { A5BLOCK_ALLOW_OFFSET, SPR_TRACKS_FOR_SLOPES_BASE, 1, TRACKS_FOR_SLOPES_SPRITE_COUNT, "Sloped rail track" },
70 /* 0x10 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORTX_BASE, 1, AIRPORTX_SPRITE_COUNT, "Airport graphics" },
71 /* 0x11 */ { A5BLOCK_ALLOW_OFFSET, SPR_ROADSTOP_BASE, 1, ROADSTOP_SPRITE_COUNT, "Road stop graphics" },
72 /* 0x12 */ { A5BLOCK_ALLOW_OFFSET, SPR_AQUEDUCT_BASE, 1, AQUEDUCT_SPRITE_COUNT, "Aqueduct graphics" },
73 /* 0x13 */ { A5BLOCK_ALLOW_OFFSET, SPR_AUTORAIL_BASE, 1, AUTORAIL_SPRITE_COUNT, "Autorail graphics" },
74 /* 0x14 */ { A5BLOCK_INVALID, 0, 1, 0, "Flag graphics" }, // deprecated, no longer used.
75 /* 0x15 */ { A5BLOCK_ALLOW_OFFSET, SPR_OPENTTD_BASE, 1, OPENTTD_SPRITE_COUNT, "OpenTTD GUI graphics" },
76 /* 0x16 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORT_PREVIEW_BASE, 1, AIRPORT_PREVIEW_SPRITE_COUNT, "Airport preview graphics" },
77 /* 0x17 */ { A5BLOCK_ALLOW_OFFSET, SPR_RAILTYPE_TUNNEL_BASE, 1, RAILTYPE_TUNNEL_BASE_COUNT, "Railtype tunnel base" },
78 /* 0x18 */ { A5BLOCK_ALLOW_OFFSET, SPR_PALETTE_BASE, 1, PALETTE_SPRITE_COUNT, "Palette" },
79 /* 0x19 */ { A5BLOCK_ALLOW_OFFSET, SPR_ROAD_WAYPOINTS_BASE, 1, ROAD_WAYPOINTS_SPRITE_COUNT, "Road waypoints" },
80 /* 0x1A */ { A5BLOCK_ALLOW_OFFSET, SPR_OVERLAY_ROCKS_BASE, 1, OVERLAY_ROCKS_SPRITE_COUNT, "Overlay rocks" },
81 /* 0x1B */ { A5BLOCK_ALLOW_OFFSET, SPR_BRIDGE_DECKS_BASE, 1, BRIDGE_DECKS_SPRITE_COUNT, "Bridge decks" },
82});
83
88std::span<const Action5Type> GetAction5Types()
89{
90 return _action5_types;
91}
92
93/* Action 0x05 */
94static void GraphicsNew(ByteReader &buf)
95{
96 /* <05> <graphics-type> <num-sprites> <other data...>
97 *
98 * B graphics-type What set of graphics the sprites define.
99 * E num-sprites How many sprites are in this set?
100 * V other data Graphics type specific data. Currently unused. */
101
102 uint8_t type = buf.ReadByte();
103 uint16_t num = buf.ReadExtendedByte();
104 uint16_t offset = HasBit(type, 7) ? buf.ReadExtendedByte() : 0;
105 ClrBit(type, 7); // Clear the high bit as that only indicates whether there is an offset.
106
107 if ((type == 0x0D) && (num == 10) && _cur_gps.grfconfig->flags.Test(GRFConfigFlag::System)) {
108 /* Special not-TTDP-compatible case used in openttd.grf
109 * Missing shore sprites and initialisation of SPR_SHORE_BASE */
110 GrfMsg(2, "GraphicsNew: Loading 10 missing shore sprites from extra grf.");
111 LoadNextSprite(SPR_SHORE_BASE + 0, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_STEEP_S
112 LoadNextSprite(SPR_SHORE_BASE + 5, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_STEEP_W
113 LoadNextSprite(SPR_SHORE_BASE + 7, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_WSE
114 LoadNextSprite(SPR_SHORE_BASE + 10, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_STEEP_N
115 LoadNextSprite(SPR_SHORE_BASE + 11, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_NWS
116 LoadNextSprite(SPR_SHORE_BASE + 13, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_ENW
117 LoadNextSprite(SPR_SHORE_BASE + 14, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_SEN
118 LoadNextSprite(SPR_SHORE_BASE + 15, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_STEEP_E
119 LoadNextSprite(SPR_SHORE_BASE + 16, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_EW
120 LoadNextSprite(SPR_SHORE_BASE + 17, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_NS
121 if (_loaded_newgrf_features.shore == SHORE_REPLACE_NONE) _loaded_newgrf_features.shore = SHORE_REPLACE_ONLY_NEW;
122 return;
123 }
124
125 /* Supported type? */
126 if ((type >= std::size(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) {
127 GrfMsg(2, "GraphicsNew: Custom graphics (type 0x{:02X}) sprite block of length {} (unimplemented, ignoring)", type, num);
128 _cur_gps.skip_sprites = num;
129 return;
130 }
131
132 const Action5Type *action5_type = &_action5_types[type];
133
134 /* Contrary to TTDP we allow always to specify too few sprites as we allow always an offset,
135 * except for the long version of the shore type:
136 * Ignore offset if not allowed */
137 if ((action5_type->block_type != A5BLOCK_ALLOW_OFFSET) && (offset != 0)) {
138 GrfMsg(1, "GraphicsNew: {} (type 0x{:02X}) do not allow an <offset> field. Ignoring offset.", action5_type->name, type);
139 offset = 0;
140 }
141
142 /* Ignore action5 if too few sprites are specified. (for TTDP compatibility)
143 * This does not make sense, if <offset> is allowed */
144 if ((action5_type->block_type == A5BLOCK_FIXED) && (num < action5_type->min_sprites)) {
145 GrfMsg(1, "GraphicsNew: {} (type 0x{:02X}) count must be at least {}. Only {} were specified. Skipping.", action5_type->name, type, action5_type->min_sprites, num);
146 _cur_gps.skip_sprites = num;
147 return;
148 }
149
150 /* Load at most max_sprites sprites. Skip remaining sprites. (for compatibility with TTDP and future extensions) */
151 uint16_t skip_num = SanitizeSpriteOffset(num, offset, action5_type->max_sprites, action5_type->name);
152 SpriteID replace = action5_type->sprite_base + offset;
153
154 /* Load <num> sprites starting from <replace>, then skip <skip_num> sprites. */
155 GrfMsg(2, "GraphicsNew: Replacing sprites {} to {} of {} (type 0x{:02X}) at SpriteID 0x{:04X}", offset, offset + num - 1, action5_type->name, type, replace);
156
157 if (type == 0x0D) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_5;
158
159 if (type == 0x0B) {
160 static const SpriteID depot_with_track_offset = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_TRAMWAY_BASE;
161 static const SpriteID depot_no_track_offset = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_TRAMWAY_BASE;
162 if (offset <= depot_with_track_offset && offset + num > depot_with_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_WITH_TRACK;
163 if (offset <= depot_no_track_offset && offset + num > depot_no_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NO_TRACK;
164 }
165
166 /* If the baseset or grf only provides sprites for flat tiles (pre #10282), duplicate those for use on slopes. */
167 bool dup_oneway_sprites = ((type == 0x09) && (offset + num <= ONEWAY_SLOPE_N_OFFSET));
168
169 for (; num > 0; num--) {
170 _cur_gps.nfo_line++;
171 SpriteID load_index = (replace == 0 ? _cur_gps.spriteid++ : replace++);
172 LoadNextSprite(load_index, *_cur_gps.file, _cur_gps.nfo_line);
173 if (dup_oneway_sprites) {
174 DupSprite(load_index, load_index + ONEWAY_SLOPE_N_OFFSET);
175 DupSprite(load_index, load_index + ONEWAY_SLOPE_S_OFFSET);
176 }
177 }
178
179 _cur_gps.skip_sprites = skip_num;
180}
181
182/* Action 0x05 (SKIP) */
183static void SkipAct5(ByteReader &buf)
184{
185 /* Ignore type byte */
186 buf.ReadByte();
187
188 /* Skip the sprites of this action */
189 _cur_gps.skip_sprites = buf.ReadExtendedByte();
190
191 GrfMsg(3, "SkipAct5: Skipping {} sprites", _cur_gps.skip_sprites);
192}
193
194template <> void GrfActionHandler<0x05>::FileScan(ByteReader &buf) { SkipAct5(buf); }
195template <> void GrfActionHandler<0x05>::SafetyScan(ByteReader &buf) { SkipAct5(buf); }
196template <> void GrfActionHandler<0x05>::LabelScan(ByteReader &buf) { SkipAct5(buf); }
197template <> void GrfActionHandler<0x05>::Init(ByteReader &buf) { SkipAct5(buf); }
198template <> void GrfActionHandler<0x05>::Reserve(ByteReader &buf) { SkipAct5(buf); }
199template <> void GrfActionHandler<0x05>::Activation(ByteReader &buf) { GraphicsNew(buf); }
HasBit
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
Definition bitmath_func.hpp:103
ClrBit
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Definition bitmath_func.hpp:139
BaseBitSet::Test
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Definition base_bitset_type.hpp:141
ByteReader
Class to read from a NewGRF file.
Definition newgrf_bytereader.h:18
ByteReader::ReadExtendedByte
uint16_t ReadExtendedByte()
Read a single Extended Byte (8 or 16 bits).
Definition newgrf_bytereader.h:56
ByteReader::ReadByte
uint8_t ReadByte()
Read a single byte (8 bits).
Definition newgrf_bytereader.h:34
SpriteID
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
_loaded_newgrf_features
GRFLoadedFeatures _loaded_newgrf_features
Indicates which are the newgrf features currently loaded ingame.
Definition newgrf.cpp:74
SHORE_REPLACE_NONE
@ SHORE_REPLACE_NONE
No shore sprites were replaced.
Definition newgrf.h:175
SHORE_REPLACE_ONLY_NEW
@ SHORE_REPLACE_ONLY_NEW
Only corner-shores were loaded by Action5 (openttd(w/d).grf only).
Definition newgrf.h:178
SHORE_REPLACE_ACTION_5
@ SHORE_REPLACE_ACTION_5
Shore sprites were replaced by Action5.
Definition newgrf.h:176
TRAMWAY_REPLACE_DEPOT_WITH_TRACK
@ TRAMWAY_REPLACE_DEPOT_WITH_TRACK
Electrified depot graphics with tram track were loaded.
Definition newgrf.h:183
TRAMWAY_REPLACE_DEPOT_NO_TRACK
@ TRAMWAY_REPLACE_DEPOT_NO_TRACK
Electrified depot graphics without tram track were loaded.
Definition newgrf.h:184
GetAction5Types
std::span< const Action5Type > GetAction5Types()
Get list of all action 5 types.
Definition newgrf_act5.cpp:88
_action5_types
static constexpr auto _action5_types
The information about action 5 types.
Definition newgrf_act5.cpp:52
SanitizeSpriteOffset
static uint16_t SanitizeSpriteOffset(uint16_t &num, uint16_t offset, int max_sprites, std::string_view name)
Sanitize incoming sprite offsets for Action 5 graphics replacements.
Definition newgrf_act5.cpp:30
A5BLOCK_ALLOW_OFFSET
@ A5BLOCK_ALLOW_OFFSET
Allow replacing any subset by specifying an offset.
Definition newgrf_act5.h:18
A5BLOCK_INVALID
@ A5BLOCK_INVALID
unknown/not-implemented type
Definition newgrf_act5.h:19
A5BLOCK_FIXED
@ A5BLOCK_FIXED
Only allow replacing a whole block of sprites. (TTDP compatible)
Definition newgrf_act5.h:17
newgrf_bytereader.h
NewGRF buffer reader definition.
System
@ System
GRF file is an openttd-internal system grf.
Definition newgrf_config.h:21
newgrf_internal.h
NewGRF internal processing state.
LoadNextSprite
bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id)
Load a real or recolour sprite.
Definition spritecache.cpp:614
SPR_BRIDGE_DECKS_BASE
static constexpr SpriteID SPR_BRIDGE_DECKS_BASE
Bridge deck sprites.
Definition sprites.h:325
SPR_OVERLAY_ROCKS_BASE
static constexpr SpriteID SPR_OVERLAY_ROCKS_BASE
Overlay rocks sprites.
Definition sprites.h:321
SPR_AQUEDUCT_BASE
static const SpriteID SPR_AQUEDUCT_BASE
Sprites for the Aqueduct.
Definition sprites.h:188
SPR_OPENTTD_BASE
static const SpriteID SPR_OPENTTD_BASE
Extra graphic spritenumbers.
Definition sprites.h:56
SPR_TRACKS_FOR_SLOPES_BASE
static const SpriteID SPR_TRACKS_FOR_SLOPES_BASE
Sprites for 'highlighting' tracks on sloped land.
Definition sprites.h:200
SPR_ROAD_WAYPOINTS_BASE
static const SpriteID SPR_ROAD_WAYPOINTS_BASE
Road waypoint sprites.
Definition sprites.h:313
SPR_RAILTYPE_TUNNEL_BASE
static const SpriteID SPR_RAILTYPE_TUNNEL_BASE
Tunnel sprites with grass only for custom railtype tunnel.
Definition sprites.h:301
SPR_TRAMWAY_BASE
static const SpriteID SPR_TRAMWAY_BASE
Tramway sprites.
Definition sprites.h:274
SPR_AIRPORT_PREVIEW_BASE
static const SpriteID SPR_AIRPORT_PREVIEW_BASE
Airport preview sprites.
Definition sprites.h:250
SPR_ONEWAY_BASE
static const SpriteID SPR_ONEWAY_BASE
One way road sprites.
Definition sprites.h:295
SPR_SHORE_BASE
static const SpriteID SPR_SHORE_BASE
shore tiles - action 05-0D
Definition sprites.h:226
Action5Type
Information about a single action 5 type.
Definition newgrf_act5.h:23
Action5Type::block_type
Action5BlockType block_type
How is this Action5 type processed?
Definition newgrf_act5.h:24
Action5Type::max_sprites
uint16_t max_sprites
If the Action5 contains more sprites, only the first max_sprites sprites will be used.
Definition newgrf_act5.h:27
Action5Type::min_sprites
uint16_t min_sprites
If the Action5 contains less sprites, the whole block will be ignored.
Definition newgrf_act5.h:26
Action5Type::sprite_base
SpriteID sprite_base
Load the sprites starting from this sprite.
Definition newgrf_act5.h:25
Action5Type::name
const std::string_view name
Name for error messages.
Definition newgrf_act5.h:28
GRFConfig::flags
GRFConfigFlags flags
NOSAVE: GCF_Flags, bitset.
Definition newgrf_config.h:178
GRFLoadedFeatures::shore
ShoreReplacement shore
In which way shore sprites were replaced.
Definition newgrf.h:190
GRFLoadedFeatures::tram
TramReplacement tram
In which way tram depots were replaced.
Definition newgrf.h:191
GrfActionHandler
GRF action handler.
Definition newgrf_internal.h:37
GrfProcessingState::file
SpriteFile * file
File of currently processed GRF file.
Definition newgrf_internal.h:66
GrfProcessingState::nfo_line
uint32_t nfo_line
Currently processed pseudo sprite number in the GRF.
Definition newgrf_internal.h:69
GrfProcessingState::spriteid
SpriteID spriteid
First available SpriteID for loading realsprites.
Definition newgrf_internal.h:63
GrfProcessingState::grfconfig
GRFConfig * grfconfig
Config of the currently processed GRF file.
Definition newgrf_internal.h:68
GrfProcessingState::skip_sprites
int skip_sprites
Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file)
Definition newgrf_internal.h:72