/* * This file is part of OpenTTD. * 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. * 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. * 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 . */ /** @file newgrf_actb.cpp NewGRF Action 0x0B handler. */ #include "../stdafx.h" #include "../debug.h" #include "newgrf_bytereader.h" #include "newgrf_internal.h" #include "table/strings.h" #include "../safeguards.h" /* Action 0x0B */ static void GRFLoadError(ByteReader &buf) { /* <0B> [ 00] [] 00 [] * * B severity 00: notice, continue loading grf file * 01: warning, continue loading grf file * 02: error, but continue loading grf file, and attempt * loading grf again when loading or starting next game * 03: error, abort loading and prevent loading again in * the future (only when restarting the patch) * B language-id see action 4, use 1F for built-in error messages * B message-id message to show, see below * S message for custom messages (message-id FF), text of the message * not present for built-in messages. * V data additional data for built-in (or custom) messages * B parnum parameter numbers to be shown in the message (maximum of 2) */ static const StringID msgstr[] = { STR_NEWGRF_ERROR_VERSION_NUMBER, STR_NEWGRF_ERROR_DOS_OR_WINDOWS, STR_NEWGRF_ERROR_UNSET_SWITCH, STR_NEWGRF_ERROR_INVALID_PARAMETER, STR_NEWGRF_ERROR_LOAD_BEFORE, STR_NEWGRF_ERROR_LOAD_AFTER, STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER, }; static const StringID sevstr[] = { STR_NEWGRF_ERROR_MSG_INFO, STR_NEWGRF_ERROR_MSG_WARNING, STR_NEWGRF_ERROR_MSG_ERROR, STR_NEWGRF_ERROR_MSG_FATAL }; uint8_t severity = buf.ReadByte(); uint8_t lang = buf.ReadByte(); uint8_t message_id = buf.ReadByte(); /* Skip the error if it isn't valid for the current language. */ if (!CheckGrfLangID(lang, _cur_gps.grffile->grf_version)) return; /* Skip the error until the activation stage unless bit 7 of the severity * is set. */ if (!HasBit(severity, 7) && _cur_gps.stage == GLS_INIT) { GrfMsg(7, "GRFLoadError: Skipping non-fatal GRFLoadError in stage {}", _cur_gps.stage); return; } ClrBit(severity, 7); if (severity >= lengthof(sevstr)) { GrfMsg(7, "GRFLoadError: Invalid severity id {}. Setting to 2 (non-fatal error).", severity); severity = 2; } else if (severity == 3) { /* This is a fatal error, so make sure the GRF is deactivated and no * more of it gets loaded. */ DisableGrf(); } if (message_id >= lengthof(msgstr) && message_id != 0xFF) { GrfMsg(7, "GRFLoadError: Invalid message id."); return; } if (buf.Remaining() <= 1) { GrfMsg(7, "GRFLoadError: No message data supplied."); return; } /* An error may be emitted multiple times in different loading stages. Re-use if so. */ auto it = std::ranges::find(_cur_gps.grfconfig->errors, _cur_gps.nfo_line, &GRFError::nfo_line); if (it == std::end(_cur_gps.grfconfig->errors)) { it = _cur_gps.grfconfig->errors.emplace(it, sevstr[severity], _cur_gps.nfo_line); } GRFError &error = *it; if (message_id == 0xFF) { /* This is a custom error message. */ if (buf.HasData()) { std::string_view message = buf.ReadString(); error.custom_message = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, lang, true, message, SCC_RAW_STRING_POINTER); } else { GrfMsg(7, "GRFLoadError: No custom message supplied."); error.custom_message.clear(); } } else { error.message = msgstr[message_id]; } if (buf.HasData()) { std::string_view data = buf.ReadString(); error.data = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, lang, true, data); } else { GrfMsg(7, "GRFLoadError: No message data supplied."); error.data.clear(); } /* Only two parameter numbers can be used in the string. */ for (uint i = 0; i < error.param_value.size() && buf.HasData(); i++) { uint param_number = buf.ReadByte(); error.param_value[i] = _cur_gps.grffile->GetParam(param_number); } } template <> void GrfActionHandler<0x0B>::FileScan(ByteReader &) { } template <> void GrfActionHandler<0x0B>::SafetyScan(ByteReader &) { } template <> void GrfActionHandler<0x0B>::LabelScan(ByteReader &) { } template <> void GrfActionHandler<0x0B>::Init(ByteReader &buf) { GRFLoadError(buf); } template <> void GrfActionHandler<0x0B>::Reserve(ByteReader &buf) { GRFLoadError(buf); } template <> void GrfActionHandler<0x0B>::Activation(ByteReader &buf) { GRFLoadError(buf); }