mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-09 15:41:15 +00:00
(svn r20255) -Add: allow NewGRFs to specify static info about their user-changeable parameters
This commit is contained in:
parent
4a4f02dc81
commit
d6eab96a22
156
src/newgrf.cpp
156
src/newgrf.cpp
@ -5952,6 +5952,78 @@ static bool ChangeGRFPalette(size_t len, ByteReader *buf)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static GRFParameterInfo *_cur_parameter; ///< The parameter which info is currently changed by the newgrf.
|
||||||
|
|
||||||
|
/** Callback function for 'INFO'->'PARAM'->param_num->'NAME' to set the name of a parameter. */
|
||||||
|
static bool ChangeGRFParamName(byte langid, const char *str)
|
||||||
|
{
|
||||||
|
AddGRFTextToList(&_cur_parameter->name, langid, _cur_grfconfig->ident.grfid, str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Callback function for 'INFO'->'PARAM'->param_num->'DESC' to set the description of a parameter. */
|
||||||
|
static bool ChangeGRFParamDescription(byte langid, const char *str)
|
||||||
|
{
|
||||||
|
AddGRFTextToList(&_cur_parameter->desc, langid, _cur_grfconfig->ident.grfid, str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Callback function for 'INFO'->'PARAM'->param_num->'TYPE' to set the typeof a parameter. */
|
||||||
|
static bool ChangeGRFParamType(size_t len, ByteReader *buf)
|
||||||
|
{
|
||||||
|
if (len != 1) {
|
||||||
|
grfmsg(2, "StaticGRFInfo: expected 1 byte for 'INFO'->'PARA'->'TYPE' but got " PRINTF_SIZE ", ignoring this field", len);
|
||||||
|
buf->Skip(len);
|
||||||
|
} else {
|
||||||
|
GRFParameterType type = (GRFParameterType)buf->ReadByte();
|
||||||
|
if (type < PTYPE_END) {
|
||||||
|
_cur_parameter->type = type;
|
||||||
|
} else {
|
||||||
|
grfmsg(3, "StaticGRFInfo: unknown parameter type %d, ignoring this field", type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Callback function for 'INFO'->'PARAM'->param_num->'LIMI' to set the min/max value of a parameter. */
|
||||||
|
static bool ChangeGRFParamLimits(size_t len, ByteReader *buf)
|
||||||
|
{
|
||||||
|
if (_cur_parameter->type != PTYPE_UINT_ENUM) {
|
||||||
|
grfmsg(2, "StaticGRFInfo: 'INFO'->'PARA'->'LIMI' is only valid for parameters with type uint/enum, ignoring this field");
|
||||||
|
buf->Skip(len);
|
||||||
|
} else if (len != 8) {
|
||||||
|
grfmsg(2, "StaticGRFInfo: expected 8 bytes for 'INFO'->'PARA'->'LIMI' but got " PRINTF_SIZE ", ignoring this field", len);
|
||||||
|
buf->Skip(len);
|
||||||
|
} else {
|
||||||
|
_cur_parameter->min_value = buf->ReadDWord();
|
||||||
|
_cur_parameter->max_value = buf->ReadDWord();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Callback function for 'INFO'->'PARAM'->param_num->'MASK' to set the parameter and bits to use. */
|
||||||
|
static bool ChangeGRFParamMask(size_t len, ByteReader *buf)
|
||||||
|
{
|
||||||
|
if (len < 1 || len > 3) {
|
||||||
|
grfmsg(2, "StaticGRFInfo: expected 1 to 3 bytes for 'INFO'->'PARA'->'MASK' but got " PRINTF_SIZE ", ignoring this field", len);
|
||||||
|
buf->Skip(len);
|
||||||
|
} else {
|
||||||
|
byte param_nr = buf->ReadByte();
|
||||||
|
if (param_nr >= lengthof(_cur_grfconfig->param)) {
|
||||||
|
grfmsg(2, "StaticGRFInfo: invalid parameter number in 'INFO'->'PARA'->'MASK', param %d, ignoring this field", param_nr);
|
||||||
|
buf->Skip(len - 1);
|
||||||
|
} else {
|
||||||
|
_cur_parameter->param_nr = param_nr;
|
||||||
|
if (len >= 2) _cur_parameter->first_bit = min(buf->ReadByte(), 31);
|
||||||
|
if (len >= 3) _cur_parameter->num_bit = min(buf->ReadByte(), 32 - _cur_parameter->first_bit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef bool (*DataHandler)(size_t, ByteReader *); ///< Type of callback function for binary nodes
|
typedef bool (*DataHandler)(size_t, ByteReader *); ///< Type of callback function for binary nodes
|
||||||
typedef bool (*TextHandler)(byte, const char *str); ///< Type of callback function for text nodes
|
typedef bool (*TextHandler)(byte, const char *str); ///< Type of callback function for text nodes
|
||||||
typedef bool (*BranchHandler)(ByteReader *); ///< Type of callback function for branch nodes
|
typedef bool (*BranchHandler)(ByteReader *); ///< Type of callback function for branch nodes
|
||||||
@ -6035,11 +6107,95 @@ struct AllowedSubtags {
|
|||||||
} handler;
|
} handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool SkipUnknownInfo(ByteReader *buf, byte type);
|
||||||
|
static bool HandleNode(byte type, uint32 id, ByteReader *buf, AllowedSubtags *tags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function for 'INFO'->'PARA'->param_num->'VALU' to set the names
|
||||||
|
* of some parameter values (type uint/enum) or the names of some bits
|
||||||
|
* (type bitmask). In both cases the format is the same:
|
||||||
|
* Each subnode should be a text node with the value/bit number as id.
|
||||||
|
*/
|
||||||
|
static bool ChangeGRFParamValueNames(ByteReader *buf)
|
||||||
|
{
|
||||||
|
byte type = buf->ReadByte();
|
||||||
|
while (type != 0) {
|
||||||
|
uint32 id = buf->ReadDWord();
|
||||||
|
if (type != 'T' || id > _cur_parameter->max_value) {
|
||||||
|
grfmsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA'->param_num->'VALU' should have type 't' and the value/bit number as id");
|
||||||
|
if (!SkipUnknownInfo(buf, type)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte langid = buf->ReadByte();
|
||||||
|
const char *name_string = buf->ReadString();
|
||||||
|
|
||||||
|
SmallPair<uint32, GRFText *> *val_name = _cur_parameter->value_names.Find(id);
|
||||||
|
if (val_name != _cur_parameter->value_names.End()) {
|
||||||
|
AddGRFTextToList(&val_name->second, langid, _cur_grfconfig->ident.grfid, name_string);
|
||||||
|
} else {
|
||||||
|
GRFText *list = NULL;
|
||||||
|
AddGRFTextToList(&list, langid, _cur_grfconfig->ident.grfid, name_string);
|
||||||
|
_cur_parameter->value_names.Insert(id, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
type = buf->ReadByte();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AllowedSubtags _tags_parameters[] = {
|
||||||
|
AllowedSubtags('NAME', ChangeGRFParamName),
|
||||||
|
AllowedSubtags('DESC', ChangeGRFParamDescription),
|
||||||
|
AllowedSubtags('TYPE', ChangeGRFParamType),
|
||||||
|
AllowedSubtags('LIMI', ChangeGRFParamLimits),
|
||||||
|
AllowedSubtags('MASK', ChangeGRFParamMask),
|
||||||
|
AllowedSubtags('VALU', ChangeGRFParamValueNames),
|
||||||
|
AllowedSubtags()
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback function for 'INFO'->'PARA' to set extra information about the
|
||||||
|
* parameters. Each subnode of 'INFO'->'PARA' should be a branch node with
|
||||||
|
* the parameter number as id. The first parameter has id 0. The maximum
|
||||||
|
* parameter that can be changed is set by 'INFO'->'NPAR' which defaults to 80.
|
||||||
|
*/
|
||||||
|
static bool HandleParameterInfo(ByteReader *buf)
|
||||||
|
{
|
||||||
|
byte type = buf->ReadByte();
|
||||||
|
while (type != 0) {
|
||||||
|
uint32 id = buf->ReadDWord();
|
||||||
|
if (type != 'C' || id >= _cur_grfconfig->num_valid_params) {
|
||||||
|
grfmsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA' should have type 'C' and their parameter number as id");
|
||||||
|
if (!SkipUnknownInfo(buf, type)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id >= _cur_grfconfig->param_info.Length()) {
|
||||||
|
uint num_to_add = id - _cur_grfconfig->param_info.Length() + 1;
|
||||||
|
GRFParameterInfo **newdata = _cur_grfconfig->param_info.Append(num_to_add);
|
||||||
|
MemSetT<GRFParameterInfo *>(newdata, 0, num_to_add);
|
||||||
|
}
|
||||||
|
if (_cur_grfconfig->param_info[id] == NULL) {
|
||||||
|
_cur_grfconfig->param_info[id] = new GRFParameterInfo(id);
|
||||||
|
}
|
||||||
|
_cur_parameter = _cur_grfconfig->param_info[id];
|
||||||
|
/* Read all parameter-data and process each node. */
|
||||||
|
byte sub_type = buf->ReadByte();
|
||||||
|
while (sub_type != 0) {
|
||||||
|
uint32 sub_id = buf->ReadDWord();
|
||||||
|
if (!HandleNode(sub_type, sub_id, buf, _tags_parameters)) return false;
|
||||||
|
sub_type = buf->ReadByte();
|
||||||
|
}
|
||||||
|
type = buf->ReadByte();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
AllowedSubtags _tags_info[] = {
|
AllowedSubtags _tags_info[] = {
|
||||||
AllowedSubtags('NAME', ChangeGRFName),
|
AllowedSubtags('NAME', ChangeGRFName),
|
||||||
AllowedSubtags('DESC', ChangeGRFDescription),
|
AllowedSubtags('DESC', ChangeGRFDescription),
|
||||||
AllowedSubtags('NPAR', ChangeGRFNumUsedParams),
|
AllowedSubtags('NPAR', ChangeGRFNumUsedParams),
|
||||||
AllowedSubtags('PALS', ChangeGRFPalette),
|
AllowedSubtags('PALS', ChangeGRFPalette),
|
||||||
|
AllowedSubtags('PARA', HandleParameterInfo),
|
||||||
AllowedSubtags()
|
AllowedSubtags()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,6 +51,13 @@ GRFConfig::GRFConfig(const GRFConfig &config) :
|
|||||||
this->name = DuplicateGRFText(config.name);
|
this->name = DuplicateGRFText(config.name);
|
||||||
this->info = DuplicateGRFText(config.info);
|
this->info = DuplicateGRFText(config.info);
|
||||||
if (config.error != NULL) this->error = new GRFError(*config.error);
|
if (config.error != NULL) this->error = new GRFError(*config.error);
|
||||||
|
for (uint i = 0; i < config.param_info.Length(); i++) {
|
||||||
|
if (config.param_info[i] == NULL) {
|
||||||
|
*this->param_info.Append() = NULL;
|
||||||
|
} else {
|
||||||
|
*this->param_info.Append() = new GRFParameterInfo(*config.param_info[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Cleanup a GRFConfig object. */
|
/** Cleanup a GRFConfig object. */
|
||||||
@ -63,6 +70,8 @@ GRFConfig::~GRFConfig()
|
|||||||
delete this->error;
|
delete this->error;
|
||||||
}
|
}
|
||||||
CleanUpGRFText(this->name);
|
CleanUpGRFText(this->name);
|
||||||
|
|
||||||
|
for (uint i = 0; i < this->param_info.Length(); i++) delete this->param_info[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,6 +148,53 @@ GRFError::~GRFError()
|
|||||||
free(this->data);
|
free(this->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new empty GRFParameterInfo object.
|
||||||
|
* @param nr The newgrf parameter that is changed.
|
||||||
|
*/
|
||||||
|
GRFParameterInfo::GRFParameterInfo(uint nr) :
|
||||||
|
name(NULL),
|
||||||
|
desc(NULL),
|
||||||
|
type(PTYPE_UINT_ENUM),
|
||||||
|
min_value(0),
|
||||||
|
max_value(UINT32_MAX),
|
||||||
|
param_nr(nr),
|
||||||
|
first_bit(0),
|
||||||
|
num_bit(32)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new GRFParameterInfo object that is a deep copy of an existing
|
||||||
|
* parameter info object.
|
||||||
|
* @param info The GRFParameterInfo object to make a copy of.
|
||||||
|
*/
|
||||||
|
GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) :
|
||||||
|
name(DuplicateGRFText(info.name)),
|
||||||
|
desc(DuplicateGRFText(info.desc)),
|
||||||
|
type(info.type),
|
||||||
|
min_value(info.min_value),
|
||||||
|
max_value(info.max_value),
|
||||||
|
param_nr(info.param_nr),
|
||||||
|
first_bit(info.first_bit),
|
||||||
|
num_bit(info.num_bit)
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < info.value_names.Length(); i++) {
|
||||||
|
SmallPair<uint32, GRFText *> *data = info.value_names.Get(i);
|
||||||
|
this->value_names.Insert(data->first, DuplicateGRFText(data->second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cleanup all parameter info. */
|
||||||
|
GRFParameterInfo::~GRFParameterInfo()
|
||||||
|
{
|
||||||
|
CleanUpGRFText(this->name);
|
||||||
|
CleanUpGRFText(this->desc);
|
||||||
|
for (uint i = 0; i < this->value_names.Length(); i++) {
|
||||||
|
SmallPair<uint32, GRFText *> *data = this->value_names.Get(i);
|
||||||
|
CleanUpGRFText(data->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the palettes of the graphics from the config file.
|
* Update the palettes of the graphics from the config file.
|
||||||
* This is needed because the config file gets read and parsed
|
* This is needed because the config file gets read and parsed
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "strings_type.h"
|
#include "strings_type.h"
|
||||||
#include "core/alloc_type.hpp"
|
#include "core/alloc_type.hpp"
|
||||||
|
#include "core/smallmap_type.hpp"
|
||||||
|
|
||||||
/** GRF config bit flags */
|
/** GRF config bit flags */
|
||||||
enum GCF_Flags {
|
enum GCF_Flags {
|
||||||
@ -99,6 +100,29 @@ struct GRFError : ZeroedMemoryAllocator {
|
|||||||
uint32 param_value[2]; ///< Values of GRF parameters to show for message and custom_message
|
uint32 param_value[2]; ///< Values of GRF parameters to show for message and custom_message
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** The possible types of a newgrf parameter. */
|
||||||
|
enum GRFParameterType {
|
||||||
|
PTYPE_UINT_ENUM, ///< The parameter allows a range of numbers, each of which can have a special name
|
||||||
|
PTYPE_BOOL, ///< The parameter is either 0 or 1
|
||||||
|
PTYPE_END, ///< Invalid parameter type
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Information about one grf parameter. */
|
||||||
|
struct GRFParameterInfo {
|
||||||
|
GRFParameterInfo(uint nr);
|
||||||
|
GRFParameterInfo(GRFParameterInfo &info);
|
||||||
|
~GRFParameterInfo();
|
||||||
|
struct GRFText *name; ///< The name of this parameter
|
||||||
|
struct GRFText *desc; ///< The description of this parameter
|
||||||
|
GRFParameterType type; ///< The type of this parameter
|
||||||
|
uint32 min_value; ///< The minimal value this parameter can have
|
||||||
|
uint32 max_value; ///< The maximal value of this parameter
|
||||||
|
byte param_nr; ///< GRF parameter to store content in
|
||||||
|
byte first_bit; ///< First bit to use in the GRF parameter
|
||||||
|
byte num_bit; ///< Number of bits to use for this parameter
|
||||||
|
SmallMap<uint32, struct GRFText *, 8> value_names; ///< Names for each value.
|
||||||
|
};
|
||||||
|
|
||||||
/** Information about GRF, used in the game and (part of it) in savegames */
|
/** Information about GRF, used in the game and (part of it) in savegames */
|
||||||
struct GRFConfig : ZeroedMemoryAllocator {
|
struct GRFConfig : ZeroedMemoryAllocator {
|
||||||
GRFConfig(const char *filename = NULL);
|
GRFConfig(const char *filename = NULL);
|
||||||
@ -119,6 +143,7 @@ struct GRFConfig : ZeroedMemoryAllocator {
|
|||||||
uint8 num_params; ///< Number of used parameters
|
uint8 num_params; ///< Number of used parameters
|
||||||
uint8 num_valid_params; ///< NOSAVE: Number of valid parameters (action 0x14)
|
uint8 num_valid_params; ///< NOSAVE: Number of valid parameters (action 0x14)
|
||||||
uint8 palette; ///< GRFPalette, bitset
|
uint8 palette; ///< GRFPalette, bitset
|
||||||
|
SmallVector<GRFParameterInfo *, 4> param_info; ///< NOSAVE: extra information about the parameters
|
||||||
|
|
||||||
struct GRFConfig *next; ///< NOSAVE: Next item in the linked list
|
struct GRFConfig *next; ///< NOSAVE: Next item in the linked list
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user