|
@@ -27,48 +27,49 @@
|
|
|
#include "newgrf.h"
|
|
|
#include "newgrf_cargo.h"
|
|
|
#include "newgrf_house.h"
|
|
|
#include "newgrf_sound.h"
|
|
|
#include "newgrf_station.h"
|
|
|
#include "industry.h"
|
|
|
#include "newgrf_canal.h"
|
|
|
#include "newgrf_commons.h"
|
|
|
#include "newgrf_townname.h"
|
|
|
#include "newgrf_industries.h"
|
|
|
#include "newgrf_airporttiles.h"
|
|
|
#include "newgrf_airport.h"
|
|
|
#include "rev.h"
|
|
|
#include "fios.h"
|
|
|
#include "rail.h"
|
|
|
#include "strings_func.h"
|
|
|
#include "date_func.h"
|
|
|
#include "string_func.h"
|
|
|
#include "network/network.h"
|
|
|
#include <map>
|
|
|
#include "core/alloc_type.hpp"
|
|
|
#include "core/mem_func.hpp"
|
|
|
#include "smallmap_gui.h"
|
|
|
#include "genworld.h"
|
|
|
#include "gui.h"
|
|
|
|
|
|
#include "table/strings.h"
|
|
|
#include "table/build_industry.h"
|
|
|
|
|
|
/* TTDPatch extended GRF format codec
|
|
|
* (c) Petr Baudis 2004 (GPL'd)
|
|
|
* Changes by Florian octo Forster are (c) by the OpenTTD development team.
|
|
|
*
|
|
|
* Contains portions of documentation by TTDPatch team.
|
|
|
* Thanks especially to Josef Drexler for the documentation as well as a lot
|
|
|
* of help at #tycoon. Also thanks to Michael Blunck for is GRF files which
|
|
|
* served as subject to the initial testing of this codec. */
|
|
|
|
|
|
|
|
|
static int _skip_sprites; // XXX
|
|
|
static uint _file_index; // XXX
|
|
|
|
|
|
static SmallVector<GRFFile *, 16> _grf_files;
|
|
|
|
|
|
static GRFFile *_cur_grffile;
|
|
|
static SpriteID _cur_spriteid;
|
|
|
static GrfLoadingStage _cur_stage;
|
|
|
static uint32 _nfo_line;
|
|
|
|
|
@@ -4328,174 +4329,207 @@ static void FeatureNewName(ByteReader *b
|
|
|
* @param max_sprites the maximum number of sprites that can be loaded in this action 5.
|
|
|
* @param name used for error warnings.
|
|
|
* @return the number of sprites that is going to be skipped
|
|
|
*/
|
|
|
static uint16 SanitizeSpriteOffset(uint16& num, uint16 offset, int max_sprites, const char *name)
|
|
|
{
|
|
|
|
|
|
if (offset >= max_sprites) {
|
|
|
grfmsg(1, "GraphicsNew: %s sprite offset must be less than %i, skipping", name, max_sprites);
|
|
|
uint orig_num = num;
|
|
|
num = 0;
|
|
|
return orig_num;
|
|
|
}
|
|
|
|
|
|
if (offset + num > max_sprites) {
|
|
|
grfmsg(4, "GraphicsNew: %s sprite overflow, truncating...", name);
|
|
|
uint orig_num = num;
|
|
|
num = max(max_sprites - offset, 0);
|
|
|
return orig_num - num;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
|
|
|
/** The type of action 5 type. */
|
|
|
enum Action5BlockType {
|
|
|
A5BLOCK_FIXED, ///< Only allow replacing a whole block of sprites. (TTDP compatible)
|
|
|
A5BLOCK_ALLOW_OFFSET, ///< Allow replacing any subset by specifiing an offset.
|
|
|
A5BLOCK_INVALID, ///< unknown/not-implemented type
|
|
|
};
|
|
|
/** Information about a single action 5 type. */
|
|
|
struct Action5Type {
|
|
|
Action5BlockType block_type; ///< How is this Action5 type processed?
|
|
|
SpriteID sprite_base; ///< Load the sprites starting from this sprite.
|
|
|
uint16 min_sprites; ///< If the Action5 contains less sprites, the whole block will be ignored.
|
|
|
uint16 max_sprites; ///< If the Action5 contains more sprites, only the first max_sprites sprites will be used.
|
|
|
const char *name; ///< Name for error messages.
|
|
|
};
|
|
|
|
|
|
/** The information about action 5 types. */
|
|
|
static const Action5Type _action5_types[] = {
|
|
|
/* Note: min_sprites should not be changed. Therefore these constants are directly here and not in sprites.h */
|
|
|
/* 0x00 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x00" },
|
|
|
/* 0x01 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x01" },
|
|
|
/* 0x02 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x02" },
|
|
|
/* 0x03 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x03" },
|
|
|
/* 0x04 */ { A5BLOCK_FIXED, SPR_SIGNALS_BASE, 48, PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT, "Signal graphics" },
|
|
|
/* 0x05 */ { A5BLOCK_FIXED, SPR_ELRAIL_BASE, 48, ELRAIL_SPRITE_COUNT, "Catenary graphics" },
|
|
|
/* 0x06 */ { A5BLOCK_FIXED, SPR_SLOPES_BASE, 74, NORMAL_AND_HALFTILE_FOUNDATION_SPRITE_COUNT, "Foundation graphics" },
|
|
|
/* 0x07 */ { A5BLOCK_INVALID, 0, 75, 0, "TTDP GUI graphics" }, // Not used by OTTD.
|
|
|
/* 0x08 */ { A5BLOCK_FIXED, SPR_CANALS_BASE, 65, CANALS_SPRITE_COUNT, "Canal graphics" },
|
|
|
/* 0x09 */ { A5BLOCK_FIXED, SPR_ONEWAY_BASE, 6, ONEWAY_SPRITE_COUNT, "One way road graphics" },
|
|
|
/* 0x0A */ { A5BLOCK_FIXED, SPR_2CCMAP_BASE, 256, TWOCCMAP_SPRITE_COUNT, "2CC colour maps" },
|
|
|
/* 0x0B */ { A5BLOCK_FIXED, SPR_TRAMWAY_BASE, 113, TRAMWAY_SPRITE_COUNT, "Tramway graphics" },
|
|
|
/* 0x0C */ { A5BLOCK_INVALID, 0, 133, 0, "Snowy temperate tree" }, // Not yet used by OTTD.
|
|
|
/* 0x0D */ { A5BLOCK_FIXED, SPR_SHORE_BASE, 16, SPR_SHORE_SPRITE_COUNT, "Shore graphics" },
|
|
|
/* 0x0E */ { A5BLOCK_INVALID, 0, 0, 0, "New Signals graphics" }, // Not yet used by OTTD.
|
|
|
/* 0x0F */ { A5BLOCK_FIXED, SPR_TRACKS_FOR_SLOPES_BASE, 12, TRACKS_FOR_SLOPES_SPRITE_COUNT, "Sloped rail track" },
|
|
|
/* 0x10 */ { A5BLOCK_FIXED, SPR_AIRPORTX_BASE, 15, AIRPORTX_SPRITE_COUNT, "Airport graphics" },
|
|
|
/* 0x11 */ { A5BLOCK_FIXED, SPR_ROADSTOP_BASE, 8, ROADSTOP_SPRITE_COUNT, "Road stop graphics" },
|
|
|
/* 0x12 */ { A5BLOCK_FIXED, SPR_AQUEDUCT_BASE, 8, AQUEDUCT_SPRITE_COUNT, "Aqueduct graphics" },
|
|
|
/* 0x13 */ { A5BLOCK_FIXED, SPR_AUTORAIL_BASE, 55, AUTORAIL_SPRITE_COUNT, "Autorail graphics" },
|
|
|
/* 0x14 */ { A5BLOCK_ALLOW_OFFSET, SPR_FLAGS_BASE, 1, FLAGS_SPRITE_COUNT, "Flag graphics" },
|
|
|
/* 0x15 */ { A5BLOCK_ALLOW_OFFSET, SPR_OPENTTD_BASE, 1, OPENTTD_SPRITE_COUNT, "OpenTTD GUI graphics" },
|
|
|
/* 0x16 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORT_PREVIEW_BASE, 1, SPR_AIRPORT_PREVIEW_COUNT, "Airport preview graphics" },
|
|
|
};
|
|
|
|
|
|
/* Action 0x05 */
|
|
|
static void GraphicsNew(ByteReader *buf)
|
|
|
{
|
|
|
/* <05> <graphics-type> <num-sprites> <other data...>
|
|
|
*
|
|
|
* B graphics-type What set of graphics the sprites define.
|
|
|
* E num-sprites How many sprites are in this set?
|
|
|
* V other data Graphics type specific data. Currently unused. */
|
|
|
/* TODO */
|
|
|
|
|
|
enum Action5BlockType {
|
|
|
A5BLOCK_FIXED, ///< Only allow replacing a whole block of sprites. (TTDP compatible)
|
|
|
A5BLOCK_ALLOW_OFFSET, ///< Allow replacing any subset by specifiing an offset.
|
|
|
A5BLOCK_INVALID, ///< unknown/not-implemented type
|
|
|
};
|
|
|
struct Action5Type {
|
|
|
Action5BlockType block_type; ///< How is this Action5 type processed?
|
|
|
SpriteID sprite_base; ///< Load the sprites starting from this sprite.
|
|
|
uint16 min_sprites; ///< If the Action5 contains less sprites, the whole block will be ignored.
|
|
|
uint16 max_sprites; ///< If the Action5 contains more sprites, only the first max_sprites sprites will be used.
|
|
|
const char *name; ///< Name for error messages.
|
|
|
};
|
|
|
|
|
|
static const Action5Type action5_types[] = {
|
|
|
/* Note: min_sprites should not be changed. Therefore these constants are directly here and not in sprites.h */
|
|
|
/* 0x00 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x00" },
|
|
|
/* 0x01 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x01" },
|
|
|
/* 0x02 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x02" },
|
|
|
/* 0x03 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x03" },
|
|
|
/* 0x04 */ { A5BLOCK_FIXED, SPR_SIGNALS_BASE, 48, PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT, "Signal graphics" },
|
|
|
/* 0x05 */ { A5BLOCK_FIXED, SPR_ELRAIL_BASE, 48, ELRAIL_SPRITE_COUNT, "Catenary graphics" },
|
|
|
/* 0x06 */ { A5BLOCK_FIXED, SPR_SLOPES_BASE, 74, NORMAL_AND_HALFTILE_FOUNDATION_SPRITE_COUNT, "Foundation graphics" },
|
|
|
/* 0x07 */ { A5BLOCK_INVALID, 0, 75, 0, "TTDP GUI graphics" }, // Not used by OTTD.
|
|
|
/* 0x08 */ { A5BLOCK_FIXED, SPR_CANALS_BASE, 65, CANALS_SPRITE_COUNT, "Canal graphics" },
|
|
|
/* 0x09 */ { A5BLOCK_FIXED, SPR_ONEWAY_BASE, 6, ONEWAY_SPRITE_COUNT, "One way road graphics" },
|
|
|
/* 0x0A */ { A5BLOCK_FIXED, SPR_2CCMAP_BASE, 256, TWOCCMAP_SPRITE_COUNT, "2CC colour maps" },
|
|
|
/* 0x0B */ { A5BLOCK_FIXED, SPR_TRAMWAY_BASE, 113, TRAMWAY_SPRITE_COUNT, "Tramway graphics" },
|
|
|
/* 0x0C */ { A5BLOCK_INVALID, 0, 133, 0, "Snowy temperate tree" }, // Not yet used by OTTD.
|
|
|
/* 0x0D */ { A5BLOCK_FIXED, SPR_SHORE_BASE, 16, SPR_SHORE_SPRITE_COUNT, "Shore graphics" },
|
|
|
/* 0x0E */ { A5BLOCK_INVALID, 0, 0, 0, "New Signals graphics" }, // Not yet used by OTTD.
|
|
|
/* 0x0F */ { A5BLOCK_FIXED, SPR_TRACKS_FOR_SLOPES_BASE, 12, TRACKS_FOR_SLOPES_SPRITE_COUNT, "Sloped rail track" },
|
|
|
/* 0x10 */ { A5BLOCK_FIXED, SPR_AIRPORTX_BASE, 15, AIRPORTX_SPRITE_COUNT, "Airport graphics" },
|
|
|
/* 0x11 */ { A5BLOCK_FIXED, SPR_ROADSTOP_BASE, 8, ROADSTOP_SPRITE_COUNT, "Road stop graphics" },
|
|
|
/* 0x12 */ { A5BLOCK_FIXED, SPR_AQUEDUCT_BASE, 8, AQUEDUCT_SPRITE_COUNT, "Aqueduct graphics" },
|
|
|
/* 0x13 */ { A5BLOCK_FIXED, SPR_AUTORAIL_BASE, 55, AUTORAIL_SPRITE_COUNT, "Autorail graphics" },
|
|
|
/* 0x14 */ { A5BLOCK_ALLOW_OFFSET, SPR_FLAGS_BASE, 1, FLAGS_SPRITE_COUNT, "Flag graphics" },
|
|
|
/* 0x15 */ { A5BLOCK_ALLOW_OFFSET, SPR_OPENTTD_BASE, 1, OPENTTD_SPRITE_COUNT, "OpenTTD GUI graphics" },
|
|
|
/* 0x16 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORT_PREVIEW_BASE, 1, SPR_AIRPORT_PREVIEW_COUNT, "Airport preview graphics" },
|
|
|
};
|
|
|
|
|
|
uint8 type = buf->ReadByte();
|
|
|
uint16 num = buf->ReadExtendedByte();
|
|
|
uint16 offset = HasBit(type, 7) ? buf->ReadExtendedByte() : 0;
|
|
|
ClrBit(type, 7); // Clear the high bit as that only indicates whether there is an offset.
|
|
|
|
|
|
if ((type == 0x0D) && (num == 10) && _cur_grffile->is_ottdfile) {
|
|
|
/* Special not-TTDP-compatible case used in openttd(d/w).grf
|
|
|
/* Special not-TTDP-compatible case used in openttd.grf
|
|
|
* Missing shore sprites and initialisation of SPR_SHORE_BASE */
|
|
|
grfmsg(2, "GraphicsNew: Loading 10 missing shore sprites from openttd(d/w).grf.");
|
|
|
grfmsg(2, "GraphicsNew: Loading 10 missing shore sprites from extra grf.");
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 0, _file_index, _nfo_line++); // SLOPE_STEEP_S
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 5, _file_index, _nfo_line++); // SLOPE_STEEP_W
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 7, _file_index, _nfo_line++); // SLOPE_WSE
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 10, _file_index, _nfo_line++); // SLOPE_STEEP_N
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 11, _file_index, _nfo_line++); // SLOPE_NWS
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 13, _file_index, _nfo_line++); // SLOPE_ENW
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 14, _file_index, _nfo_line++); // SLOPE_SEN
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 15, _file_index, _nfo_line++); // SLOPE_STEEP_E
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 16, _file_index, _nfo_line++); // SLOPE_EW
|
|
|
LoadNextSprite(SPR_SHORE_BASE + 17, _file_index, _nfo_line++); // SLOPE_NS
|
|
|
if (_loaded_newgrf_features.shore == SHORE_REPLACE_NONE) _loaded_newgrf_features.shore = SHORE_REPLACE_ONLY_NEW;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
/* Supported type? */
|
|
|
if ((type >= lengthof(action5_types)) || (action5_types[type].block_type == A5BLOCK_INVALID)) {
|
|
|
if ((type >= lengthof(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) {
|
|
|
grfmsg(2, "GraphicsNew: Custom graphics (type 0x%02X) sprite block of length %u (unimplemented, ignoring)", type, num);
|
|
|
_skip_sprites = num;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
const Action5Type *action5_type = &action5_types[type];
|
|
|
const Action5Type *action5_type = &_action5_types[type];
|
|
|
|
|
|
/* Ignore offset if not allowed */
|
|
|
if ((action5_type->block_type != A5BLOCK_ALLOW_OFFSET) && (offset != 0)) {
|
|
|
grfmsg(1, "GraphicsNew: %s (type 0x%02X) do not allow an <offset> field. Ignoring offset.", action5_type->name, type);
|
|
|
offset = 0;
|
|
|
}
|
|
|
|
|
|
/* Ignore action5 if too few sprites are specified. (for TTDP compatibility)
|
|
|
* This does not make sense, if <offset> is allowed */
|
|
|
if ((action5_type->block_type == A5BLOCK_FIXED) && (num < action5_type->min_sprites)) {
|
|
|
grfmsg(1, "GraphicsNew: %s (type 0x%02X) count must be at least %d. Only %d were specified. Skipping.", action5_type->name, type, action5_type->min_sprites, num);
|
|
|
_skip_sprites = num;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
/* Load at most max_sprites sprites. Skip remaining sprites. (for compatibility with TTDP and future extentions) */
|
|
|
uint16 skip_num = SanitizeSpriteOffset(num, offset, action5_type->max_sprites, action5_type->name);
|
|
|
SpriteID replace = action5_type->sprite_base + offset;
|
|
|
|
|
|
/* Load <num> sprites starting from <replace>, then skip <skip_num> sprites. */
|
|
|
grfmsg(2, "GraphicsNew: Replacing sprites %d to %d of %s (type 0x%02X) at SpriteID 0x%04X", offset, offset + num - 1, action5_type->name, type, replace);
|
|
|
|
|
|
for (; num > 0; num--) {
|
|
|
_nfo_line++;
|
|
|
LoadNextSprite(replace == 0 ? _cur_spriteid++ : replace++, _file_index, _nfo_line);
|
|
|
}
|
|
|
|
|
|
if (type == 0x0D) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_5;
|
|
|
|
|
|
_skip_sprites = skip_num;
|
|
|
}
|
|
|
|
|
|
/* Action 0x05 (SKIP) */
|
|
|
static void SkipAct5(ByteReader *buf)
|
|
|
{
|
|
|
/* Ignore type byte */
|
|
|
buf->ReadByte();
|
|
|
|
|
|
/* Skip the sprites of this action */
|
|
|
_skip_sprites = buf->ReadExtendedByte();
|
|
|
|
|
|
grfmsg(3, "SkipAct5: Skipping %d sprites", _skip_sprites);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Check whether we are (obviously) missing some of the extra
|
|
|
* (Action 0x05) sprites that we like to use.
|
|
|
* When missing sprites are found a warning will be shown.
|
|
|
*/
|
|
|
void CheckForMissingSprites()
|
|
|
{
|
|
|
/* Don't break out quickly, but allow to check the other
|
|
|
* sprites as well, so we can give the best information. */
|
|
|
bool missing = false;
|
|
|
for (uint8 i = 0; i < lengthof(_action5_types); i++) {
|
|
|
const Action5Type *type = &_action5_types[i];
|
|
|
if (type->block_type == A5BLOCK_INVALID) continue;
|
|
|
|
|
|
for (uint j = 0; j < type->max_sprites; j++) {
|
|
|
if (!SpriteExists(type->sprite_base + j)) {
|
|
|
DEBUG(grf, 0, "%s sprites are missing", type->name);
|
|
|
missing = true;
|
|
|
/* No need to log more of the same. */
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (missing) {
|
|
|
ShowErrorMessage(STR_NEWGRF_ERROR_MISSING_SPRITES, INVALID_STRING_ID, WL_CRITICAL);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reads a variable common to VarAction2 and Action7/9/D.
|
|
|
*
|
|
|
* Returns VarAction2 variable 'param' resp. Action7/9/D variable '0x80 + param'.
|
|
|
* If a variable is not accessible from all four actions, it is handled in the action specific functions.
|
|
|
*
|
|
|
* @param param variable number (as for VarAction2, for Action7/9/D you have to subtract 0x80 first).
|
|
|
* @param value returns the value of the variable.
|
|
|
* @return true iff the variable is known and the value is returned in 'value'.
|
|
|
*/
|
|
|
bool GetGlobalVariable(byte param, uint32 *value)
|
|
|
{
|
|
|
switch (param) {
|
|
|
case 0x00: // current date
|
|
|
*value = max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);
|
|
|
return true;
|
|
|
|
|
|
case 0x01: // current year
|
|
|
*value = Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
|
|
|
return true;
|
|
|
|
|
|
case 0x02: { // detailed date information: month of year (bit 0-7), day of month (bit 8-12), leap year (bit 15), day of year (bit 16-24)
|
|
|
YearMonthDay ymd;
|
|
|
ConvertDateToYMD(_date, &ymd);
|
|
|
Date start_of_year = ConvertYMDToDate(ymd.year, 0, 1);
|