OpenTTD Source 20250331-master-g3c15e0c889
newgrf_acta.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 "../spritecache.h"
13#include "newgrf_bytereader.h"
14#include "newgrf_internal.h"
15
16#include "../table/sprites.h"
17
18#include "../safeguards.h"
19
26static bool IsGRMReservedSprite(SpriteID first_sprite, uint16_t num_sprites)
27{
28 for (const auto &grm_sprite : _grm_sprites) {
29 if (grm_sprite.first.grfid != _cur.grffile->grfid) continue;
30 if (grm_sprite.second.first <= first_sprite && grm_sprite.second.first + grm_sprite.second.second >= first_sprite + num_sprites) return true;
31 }
32 return false;
33}
34
35/* Action 0x0A */
36static void SpriteReplace(ByteReader &buf)
37{
38 /* <0A> <num-sets> <set1> [<set2> ...]
39 * <set>: <num-sprites> <first-sprite>
40 *
41 * B num-sets How many sets of sprites to replace.
42 * Each set:
43 * B num-sprites How many sprites are in this set
44 * W first-sprite First sprite number to replace */
45
46 uint8_t num_sets = buf.ReadByte();
47
48 for (uint i = 0; i < num_sets; i++) {
49 uint8_t num_sprites = buf.ReadByte();
50 uint16_t first_sprite = buf.ReadWord();
51
52 GrfMsg(2, "SpriteReplace: [Set {}] Changing {} sprites, beginning with {}",
53 i, num_sprites, first_sprite
54 );
55
56 if (first_sprite + num_sprites >= SPR_OPENTTD_BASE) {
57 /* Outside allowed range, check for GRM sprite reservations. */
58 if (!IsGRMReservedSprite(first_sprite, num_sprites)) {
59 GrfMsg(0, "SpriteReplace: [Set {}] Changing {} sprites, beginning with {}, above limit of {} and not within reserved range, ignoring.",
60 i, num_sprites, first_sprite, SPR_OPENTTD_BASE);
61
62 /* Load the sprites at the current location so they will do nothing instead of appearing to work. */
63 first_sprite = _cur.spriteid;
64 _cur.spriteid += num_sprites;
65 }
66 }
67
68 for (uint j = 0; j < num_sprites; j++) {
69 SpriteID load_index = first_sprite + j;
70 _cur.nfo_line++;
71 LoadNextSprite(load_index, *_cur.file, _cur.nfo_line); // XXX
72
73 /* Shore sprites now located at different addresses.
74 * So detect when the old ones get replaced. */
75 if (IsInsideMM(load_index, SPR_ORIGINALSHORE_START, SPR_ORIGINALSHORE_END + 1)) {
77 }
78 }
79 }
80}
81
82/* Action 0x0A (SKIP) */
83static void SkipActA(ByteReader &buf)
84{
85 uint8_t num_sets = buf.ReadByte();
86
87 for (uint i = 0; i < num_sets; i++) {
88 /* Skip the sprites this replaces */
89 _cur.skip_sprites += buf.ReadByte();
90 /* But ignore where they go */
91 buf.ReadWord();
92 }
93
94 GrfMsg(3, "SkipActA: Skipping {} sprites", _cur.skip_sprites);
95}
96
97template <> void GrfActionHandler<0x0A>::FileScan(ByteReader &buf) { SkipActA(buf); }
98template <> void GrfActionHandler<0x0A>::SafetyScan(ByteReader &buf) { SkipActA(buf); }
99template <> void GrfActionHandler<0x0A>::LabelScan(ByteReader &buf) { SkipActA(buf); }
100template <> void GrfActionHandler<0x0A>::Init(ByteReader &buf) { SkipActA(buf); }
101template <> void GrfActionHandler<0x0A>::Reserve(ByteReader &buf) { SkipActA(buf); }
102template <> void GrfActionHandler<0x0A>::Activation(ByteReader &buf) { SpriteReplace(buf); }
Class to read from a NewGRF file.
uint16_t ReadWord()
Read a single Word (16 bits).
uint8_t ReadByte()
Read a single byte (8 bits).
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
GRFLoadedFeatures _loaded_newgrf_features
Indicates which are the newgrf features currently loaded ingame.
Definition newgrf.cpp:72
@ SHORE_REPLACE_ACTION_A
Shore sprites were replaced by ActionA (using grass tiles for the corner-shores).
Definition newgrf.h:173
@ SHORE_REPLACE_ACTION_5
Shore sprites were replaced by Action5.
Definition newgrf.h:172
static bool IsGRMReservedSprite(SpriteID first_sprite, uint16_t num_sprites)
Check if a sprite ID range is within the GRM reversed range for the currently loading NewGRF.
NewGRF buffer reader definition.
NewGRF internal processing state.
bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id)
Load a real or recolour sprite.
static const SpriteID SPR_OPENTTD_BASE
Extra graphic spritenumbers.
Definition sprites.h:56
ShoreReplacement shore
In which way shore sprites were replaced.
Definition newgrf.h:186
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.
SpriteID spriteid
First available SpriteID for loading realsprites.
int skip_sprites
Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file)