OpenTTD Source 20250331-master-g3c15e0c889
newgrf_act6.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 <http://www.gnu.org/licenses/>.
6 */
7
10#include "../stdafx.h"
11#include "../debug.h"
12#include "newgrf_bytereader.h"
13#include "newgrf_internal.h"
14
15#include "../safeguards.h"
16
17std::map<GRFLocation, std::pair<SpriteID, uint16_t>> _grm_sprites;
18GRFLineToSpriteOverride _grf_line_to_action6_sprite_override;
19
20/* Action 0x06 */
21static void CfgApply(ByteReader &buf)
22{
23 /* <06> <param-num> <param-size> <offset> ... <FF>
24 *
25 * B param-num Number of parameter to substitute (First = "zero")
26 * Ignored if that parameter was not specified in newgrf.cfg
27 * B param-size How many bytes to replace. If larger than 4, the
28 * bytes of the following parameter are used. In that
29 * case, nothing is applied unless *all* parameters
30 * were specified.
31 * B offset Offset into data from beginning of next sprite
32 * to place where parameter is to be stored. */
33
34 /* Preload the next sprite */
35 SpriteFile &file = *_cur.file;
36 size_t pos = file.GetPos();
37 uint32_t num = file.GetContainerVersion() >= 2 ? file.ReadDword() : file.ReadWord();
38 uint8_t type = file.ReadByte();
39
40 /* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */
41 if (type != 0xFF) {
42 GrfMsg(2, "CfgApply: Ignoring (next sprite is real, unsupported)");
43
44 /* Reset the file position to the start of the next sprite */
45 file.SeekTo(pos, SEEK_SET);
46 return;
47 }
48
49 /* Get (or create) the override for the next sprite. */
50 GRFLocation location(_cur.grfconfig->ident.grfid, _cur.nfo_line + 1);
51 std::vector<uint8_t> &preload_sprite = _grf_line_to_action6_sprite_override[location];
52
53 /* Load new sprite data if it hasn't already been loaded. */
54 if (preload_sprite.empty()) {
55 preload_sprite.resize(num);
56 file.ReadBlock(preload_sprite.data(), num);
57 }
58
59 /* Reset the file position to the start of the next sprite */
60 file.SeekTo(pos, SEEK_SET);
61
62 /* Now perform the Action 0x06 on our data. */
63 for (;;) {
64 uint i;
65 uint param_num;
66 uint param_size;
67 uint offset;
68 bool add_value;
69
70 /* Read the parameter to apply. 0xFF indicates no more data to change. */
71 param_num = buf.ReadByte();
72 if (param_num == 0xFF) break;
73
74 /* Get the size of the parameter to use. If the size covers multiple
75 * double words, sequential parameter values are used. */
76 param_size = buf.ReadByte();
77
78 /* Bit 7 of param_size indicates we should add to the original value
79 * instead of replacing it. */
80 add_value = HasBit(param_size, 7);
81 param_size = GB(param_size, 0, 7);
82
83 /* Where to apply the data to within the pseudo sprite data. */
84 offset = buf.ReadExtendedByte();
85
86 /* If the parameter is a GRF parameter (not an internal variable) check
87 * if it (and all further sequential parameters) has been defined. */
88 if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= std::size(_cur.grffile->param)) {
89 GrfMsg(2, "CfgApply: Ignoring (param {} not set)", (param_num + (param_size - 1) / 4));
90 break;
91 }
92
93 GrfMsg(8, "CfgApply: Applying {} bytes from parameter 0x{:02X} at offset 0x{:04X}", param_size, param_num, offset);
94
95 bool carry = false;
96 for (i = 0; i < param_size && offset + i < num; i++) {
97 uint32_t value = GetParamVal(param_num + i / 4, nullptr);
98 /* Reset carry flag for each iteration of the variable (only really
99 * matters if param_size is greater than 4) */
100 if (i % 4 == 0) carry = false;
101
102 if (add_value) {
103 uint new_value = preload_sprite[offset + i] + GB(value, (i % 4) * 8, 8) + (carry ? 1 : 0);
104 preload_sprite[offset + i] = GB(new_value, 0, 8);
105 /* Check if the addition overflowed */
106 carry = new_value >= 256;
107 } else {
108 preload_sprite[offset + i] = GB(value, (i % 4) * 8, 8);
109 }
110 }
111 }
112}
113
114template <> void GrfActionHandler<0x06>::FileScan(ByteReader &) { }
116template <> void GrfActionHandler<0x06>::LabelScan(ByteReader &) { }
117template <> void GrfActionHandler<0x06>::Init(ByteReader &buf) { CfgApply(buf); }
118template <> void GrfActionHandler<0x06>::Reserve(ByteReader &buf) { CfgApply(buf); }
119template <> void GrfActionHandler<0x06>::Activation(ByteReader &buf) { CfgApply(buf); }
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
Class to read from a NewGRF file.
uint16_t ReadExtendedByte()
Read a single Extended Byte (8 or 16 bits).
uint8_t ReadByte()
Read a single byte (8 bits).
void ReadBlock(void *ptr, size_t size)
Read a block.
size_t GetPos() const
Get position in the file.
void SeekTo(size_t pos, int mode)
Seek in the current file.
uint8_t ReadByte()
Read a byte from the file.
uint32_t ReadDword()
Read a double word (32 bits) from the file (in low endian format).
uint16_t ReadWord()
Read a word (16 bits) from the file (in low endian format).
RandomAccessFile with some extra information specific for sprite files.
uint8_t GetContainerVersion() const
Get the version number of container type used by the file.
NewGRF buffer reader definition.
NewGRF internal processing state.
GRFIdentifier ident
grfid and md5sum to uniquely identify newgrfs
uint32_t grfid
GRF ID (defined by Action 0x08)
GRF action handler.
SpriteFile * file
File of currently processed GRF file.
GRFFile * grffile
Currently processed GRF file.
uint32_t nfo_line
Currently processed pseudo sprite number in the GRF.
GRFConfig * grfconfig
Config of the currently processed GRF file.