OpenTTD Source 20260711-master-g3fb3006dff
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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_gps.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_gps.grfconfig->ident.grfid, _cur_gps.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 /* Read the parameter to apply. 0xFF indicates no more data to change. */
65 uint param_num = buf.ReadByte();
66 if (param_num == 0xFF) break;
67
68 /* Get the size of the parameter to use. If the size covers multiple
69 * double words, sequential parameter values are used. */
70 uint param_size = buf.ReadByte();
71
72 /* Bit 7 of param_size indicates we should add to the original value
73 * instead of replacing it. */
74 bool add_value = HasBit(param_size, 7);
75 param_size = GB(param_size, 0, 7);
76
77 /* Where to apply the data to within the pseudo sprite data. */
78 uint offset = buf.ReadExtendedByte();
79
80 /* If the parameter is a GRF parameter (not an internal variable) check
81 * if it (and all further sequential parameters) has been defined. */
82 if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= std::size(_cur_gps.grffile->param)) {
83 GrfMsg(2, "CfgApply: Ignoring (param {} not set)", (param_num + (param_size - 1) / 4));
84 break;
85 }
86
87 GrfMsg(8, "CfgApply: Applying {} bytes from parameter 0x{:02X} at offset 0x{:04X}", param_size, param_num, offset);
88
89 bool carry = false;
90 for (uint i = 0; i < param_size && offset + i < num; i++) {
91 uint32_t value = GetParamVal(param_num + i / 4, nullptr);
92 /* Reset carry flag for each iteration of the variable (only really
93 * matters if param_size is greater than 4) */
94 if (i % 4 == 0) carry = false;
95
96 if (add_value) {
97 uint new_value = preload_sprite[offset + i] + GB(value, (i % 4) * 8, 8) + (carry ? 1 : 0);
98 preload_sprite[offset + i] = GB(new_value, 0, 8);
99 /* Check if the addition overflowed */
100 carry = new_value >= 256;
101 } else {
102 preload_sprite[offset + i] = GB(value, (i % 4) * 8, 8);
103 }
104 }
105 }
106}
107
115template <> void GrfActionHandler<0x06>::Init(ByteReader &buf) { CfgApply(buf); }
117template <> void GrfActionHandler<0x06>::Reserve(ByteReader &buf) { CfgApply(buf); }
119template <> void GrfActionHandler<0x06>::Activation(ByteReader &buf) { CfgApply(buf); }
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
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.
Functions related to debugging.
NewGRF buffer reader definition.
NewGRF internal processing state.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
A location within a NewGRF, like file:line but in the context of NewGRFs.
static void FileScan(ByteReader &buf)
Implementation of the GrfLoadingStage::FileScan stage of this action.
static void SafetyScan(ByteReader &buf)
Implementation of the GrfLoadingStage::SafetyScan stage of this action.
static void Reserve(ByteReader &buf)
Implementation of the GrfLoadingStage::Reserve stage of this action.
static void Activation(ByteReader &buf)
Implementation of the GrfLoadingStage::Activation stage of this action.
static void Init(ByteReader &buf)
Implementation of the GrfLoadingStage::Init stage of this action.
static void LabelScan(ByteReader &buf)
Implementation of the GrfLoadingStage::LabelScan stage of this action.