OpenTTD Source 20250331-master-g3c15e0c889
newgrf_act11.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_house.h"
13#include "../newgrf_sound.h"
14#include "../spritecache.h"
15#include "newgrf_bytereader.h"
16#include "newgrf_internal.h"
17
18#include "../safeguards.h"
19
24static void ImportGRFSound(SoundEntry *sound)
25{
26 const GRFFile *file;
27 uint32_t grfid = _cur.file->ReadDword();
28 SoundID sound_id = _cur.file->ReadWord();
29
30 file = GetFileByGRFID(grfid);
31 if (file == nullptr || file->sound_offset == 0) {
32 GrfMsg(1, "ImportGRFSound: Source file not available");
33 return;
34 }
35
36 if (sound_id >= file->num_sounds) {
37 GrfMsg(1, "ImportGRFSound: Sound effect {} is invalid", sound_id);
38 return;
39 }
40
41 GrfMsg(2, "ImportGRFSound: Copying sound {} ({}) from file {:x}", sound_id, file->sound_offset + sound_id, grfid);
42
43 *sound = *GetSound(file->sound_offset + sound_id);
44
45 /* Reset volume and priority, which TTDPatch doesn't copy */
46 sound->volume = SOUND_EFFECT_MAX_VOLUME;
47 sound->priority = 0;
48}
49
55static void LoadGRFSound(size_t offs, SoundEntry *sound)
56{
57 /* Set default volume and priority */
58 sound->volume = SOUND_EFFECT_MAX_VOLUME;
59 sound->priority = 0;
60
61 if (offs != SIZE_MAX) {
62 /* Sound is present in the NewGRF. */
63 sound->file = _cur.file;
64 sound->file_offset = offs;
65 sound->source = SoundSource::NewGRF;
67 }
68}
69
70/* Action 0x11 */
71static void GRFSound(ByteReader &buf)
72{
73 /* <11> <num>
74 *
75 * W num Number of sound files that follow */
76
77 uint16_t num = buf.ReadWord();
78 if (num == 0) return;
79
80 SoundEntry *sound;
81 if (_cur.grffile->sound_offset == 0) {
82 _cur.grffile->sound_offset = GetNumSounds();
83 _cur.grffile->num_sounds = num;
84 sound = AllocateSound(num);
85 } else {
86 sound = GetSound(_cur.grffile->sound_offset);
87 }
88
89 SpriteFile &file = *_cur.file;
90 uint8_t grf_container_version = file.GetContainerVersion();
91 for (int i = 0; i < num; i++) {
92 _cur.nfo_line++;
93
94 /* Check whether the index is in range. This might happen if multiple action 11 are present.
95 * While this is invalid, we do not check for this. But we should prevent it from causing bigger trouble */
96 bool invalid = i >= _cur.grffile->num_sounds;
97
98 size_t offs = file.GetPos();
99
100 uint32_t len = grf_container_version >= 2 ? file.ReadDword() : file.ReadWord();
101 uint8_t type = file.ReadByte();
102
103 if (grf_container_version >= 2 && type == 0xFD) {
104 /* Reference to sprite section. */
105 if (invalid) {
106 GrfMsg(1, "GRFSound: Sound index out of range (multiple Action 11?)");
107 file.SkipBytes(len);
108 } else if (len != 4) {
109 GrfMsg(1, "GRFSound: Invalid sprite section import");
110 file.SkipBytes(len);
111 } else {
112 uint32_t id = file.ReadDword();
113 if (_cur.stage == GLS_INIT) LoadGRFSound(GetGRFSpriteOffset(id), sound + i);
114 }
115 continue;
116 }
117
118 if (type != 0xFF) {
119 GrfMsg(1, "GRFSound: Unexpected RealSprite found, skipping");
120 file.SkipBytes(7);
121 SkipSpriteData(*_cur.file, type, len - 8);
122 continue;
123 }
124
125 if (invalid) {
126 GrfMsg(1, "GRFSound: Sound index out of range (multiple Action 11?)");
127 file.SkipBytes(len);
128 }
129
130 uint8_t action = file.ReadByte();
131 switch (action) {
132 case 0xFF:
133 /* Allocate sound only in init stage. */
134 if (_cur.stage == GLS_INIT) {
135 if (grf_container_version >= 2) {
136 GrfMsg(1, "GRFSound: Inline sounds are not supported for container version >= 2");
137 } else {
138 LoadGRFSound(offs, sound + i);
139 }
140 }
141 file.SkipBytes(len - 1); // already read <action>
142 break;
143
144 case 0xFE:
145 if (_cur.stage == GLS_ACTIVATION) {
146 /* XXX 'Action 0xFE' isn't really specified. It is only mentioned for
147 * importing sounds, so this is probably all wrong... */
148 if (file.ReadByte() != 0) GrfMsg(1, "GRFSound: Import type mismatch");
149 ImportGRFSound(sound + i);
150 } else {
151 file.SkipBytes(len - 1); // already read <action>
152 }
153 break;
154
155 default:
156 GrfMsg(1, "GRFSound: Unexpected Action {:x} found, skipping", action);
157 file.SkipBytes(len - 1); // already read <action>
158 break;
159 }
160 }
161}
162
163/* Action 0x11 (SKIP) */
164static void SkipAct11(ByteReader &buf)
165{
166 /* <11> <num>
167 *
168 * W num Number of sound files that follow */
169
170 _cur.skip_sprites = buf.ReadWord();
171
172 GrfMsg(3, "SkipAct11: Skipping {} sprites", _cur.skip_sprites);
173}
174
175template <> void GrfActionHandler<0x11>::FileScan(ByteReader &buf) { SkipAct11(buf); }
176template <> void GrfActionHandler<0x11>::SafetyScan(ByteReader &buf) { GRFUnsafe(buf); }
177template <> void GrfActionHandler<0x11>::LabelScan(ByteReader &buf) { SkipAct11(buf); }
178template <> void GrfActionHandler<0x11>::Init(ByteReader &buf) { SkipAct11(buf); }
179template <> void GrfActionHandler<0x11>::Reserve(ByteReader &buf) { SkipAct11(buf); }
180template <> void GrfActionHandler<0x11>::Activation(ByteReader &buf) { GRFSound(buf); }
Class to read from a NewGRF file.
uint16_t ReadWord()
Read a single Word (16 bits).
size_t GetPos() const
Get position in the 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).
void SkipBytes(size_t n)
Skip n bytes ahead in the file.
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.
void GRFUnsafe(ByteReader &)
Set the current NewGRF as unsafe for static use.
Definition newgrf.cpp:365
GRFFile * GetFileByGRFID(uint32_t grfid)
Obtain a NewGRF file by its grfID.
Definition newgrf.cpp:98
static void LoadGRFSound(size_t offs, SoundEntry *sound)
Load a sound from a file.
static void ImportGRFSound(SoundEntry *sound)
Process a sound import from another GRF file.
NewGRF buffer reader definition.
NewGRF internal processing state.
SoundEntry * AllocateSound(uint num)
Allocate sound slots.
size_t GetGRFSpriteOffset(uint32_t id)
Get the file offset for a specific sprite in the sprite section of a GRF.
bool SkipSpriteData(SpriteFile &file, uint8_t type, uint16_t num)
Skip the given amount of sprite graphics data.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:113
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.
GrfLoadingStage stage
Current loading stage.
int skip_sprites
Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file)
uint8_t grf_container_ver
NewGRF container version if the sound is from a NewGRF.
Definition sound_type.h:30