Changeset - r6873:011bb2269607
[Not reviewed]
master
0 6 0
maedhros - 17 years ago 2007-06-12 13:22:14
maedhros@openttd.org
(svn r10114) -Fix: Only load newgrf error messages if the language matches the current
language. Since only one error can be loaded anyway, if the language didn't
match you'd get "Undefined string". Also since we're only loading one language
there's no need to use AddGRFString any more.
6 files changed with 40 insertions and 16 deletions:
0 comments (0 inline, 0 general)
src/newgrf.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file newgrf.cpp */
 

	
 
#include "stdafx.h"
 

	
 
#include <stdarg.h>
 

	
 
#include "openttd.h"
 
#include "debug.h"
 
#include "gfx.h"
 
#include "fileio.h"
 
#include "functions.h"
 
#include "engine.h"
 
#include "spritecache.h"
 
#include "station.h"
 
#include "sprite.h"
 
#include "newgrf.h"
 
#include "variables.h"
 
#include "string.h"
 
#include "strings.h"
 
#include "table/strings.h"
 
#include "bridge.h"
 
#include "town.h"
 
#include "economy.h"
 
#include "newgrf_engine.h"
 
#include "vehicle.h"
 
#include "newgrf_text.h"
 
#include "table/sprites.h"
 
#include "fontcache.h"
 
#include "date.h"
 
#include "currency.h"
 
#include "landscape.h"
 
#include "sound.h"
 
#include "newgrf_config.h"
 
#include "newgrf_house.h"
 
#include "newgrf_sound.h"
 
#include "newgrf_spritegroup.h"
 
#include "helpers.hpp"
 
#include "table/town_land.h"
 
#include "cargotype.h"
 
#include "industry.h"
 
#include "newgrf_canal.h"
 
#include "newgrf_commons.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
 
SpriteID _signal_base;
 
SpriteID _coast_base;
 

	
 
static GRFFile *_cur_grffile;
 
GRFFile *_first_grffile;
 
static SpriteID _cur_spriteid;
 
static GrfLoadingStage _cur_stage;
 
static uint32 _nfo_line;
 

	
 
static GRFConfig *_cur_grfconfig;
 

	
 
/* Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E */
 
static byte _misc_grf_features = 0;
 

	
 
/* 32 * 8 = 256 flags. Apparently TTDPatch uses this many.. */
 
static uint32 _ttdpatch_flags[8];
 

	
 
/* Used by Action 0x06 to preload a pseudo sprite and modify its content */
 
static byte *_preload_sprite = NULL;
 

	
 
/* Indicates which are the newgrf features currently loaded ingame */
 
uint8 _loaded_newgrf_features;
 

	
 
enum GrfDataType {
 
	GDT_SOUND,
 
};
 

	
 
static byte _grf_data_blocks;
 
static GrfDataType _grf_data_type;
 

	
 

	
 
enum grfspec_feature {
 
	GSF_TRAIN,
 
	GSF_ROAD,
 
	GSF_SHIP,
 
	GSF_AIRCRAFT,
 
	GSF_STATION,
 
	GSF_CANAL,
 
	GSF_BRIDGE,
 
	GSF_TOWNHOUSE,
 
	GSF_GLOBALVAR,
 
	GSF_INDUSTRYTILES,
 
	GSF_INDUSTRIES,
 
	GSF_CARGOS,
 
	GSF_SOUNDFX,
 
};
 

	
 

	
 
typedef void (*SpecialSpriteHandler)(byte *buf, int len);
 

	
 
static const uint _vehcounts[4] = {
 
	/* GSF_TRAIN */    NUM_TRAIN_ENGINES,
 
	/* GSF_ROAD */     NUM_ROAD_ENGINES,
 
	/* GSF_SHIP */     NUM_SHIP_ENGINES,
 
	/* GSF_AIRCRAFT */ NUM_AIRCRAFT_ENGINES
 
};
 

	
 
static const uint _vehshifts[4] = {
 
	/* GSF_TRAIN */    0,
 
	/* GSF_ROAD */     ROAD_ENGINES_INDEX,
 
@@ -3319,261 +3320,254 @@ static void GRFInfo(byte *buf, int len)
 
	 * S name          name of this .grf set
 
	 * S info          string describing the set, and e.g. author and copyright */
 

	
 
	if (!check_length(len, 8, "GRFInfo")) return;
 
	buf++;
 
	uint8 version    = grf_load_byte(&buf);
 
	uint32 grfid     = grf_load_dword(&buf);
 
	const char *name = grf_load_string(&buf, len - 6);
 

	
 
	_cur_grffile->grfid = grfid;
 
	_cur_grffile->grf_version = version;
 
	_cur_grfconfig->status = _cur_stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED;
 

	
 
	/* Do swap the GRFID for displaying purposes since people expect that */
 
	DEBUG(grf, 1, "GRFInfo: Loaded GRFv%d set %08lX - %s", version, BSWAP32(grfid), name);
 
}
 

	
 
/* Action 0x0A */
 
static void SpriteReplace(byte *buf, int len)
 
{
 
	/* <0A> <num-sets> <set1> [<set2> ...]
 
	 * <set>: <num-sprites> <first-sprite>
 
	 *
 
	 * B num-sets      How many sets of sprites to replace.
 
	 * Each set:
 
	 * B num-sprites   How many sprites are in this set
 
	 * W first-sprite  First sprite number to replace */
 

	
 
	buf++; // skip action byte
 
	uint8 num_sets = grf_load_byte(&buf);
 

	
 
	for (uint i = 0; i < num_sets; i++) {
 
		uint8 num_sprites = grf_load_byte(&buf);
 
		uint16 first_sprite = grf_load_word(&buf);
 

	
 
		grfmsg(2, "SpriteReplace: [Set %d] Changing %d sprites, beginning with %d",
 
			i, num_sprites, first_sprite
 
		);
 

	
 
		for (uint j = 0; j < num_sprites; j++) {
 
			LoadNextSprite(first_sprite + j, _file_index); // XXX
 
			_nfo_line++;
 
		}
 
	}
 
}
 

	
 
/* Action 0x0A (SKIP) */
 
static void SkipActA(byte *buf, int len)
 
{
 
	buf++;
 
	uint8 num_sets = grf_load_byte(&buf);
 

	
 
	for (uint i = 0; i < num_sets; i++) {
 
		/* Skip the sprites this replaces */
 
		_skip_sprites += grf_load_byte(&buf);
 
		/* But ignore where they go */
 
		grf_load_word(&buf);
 
	}
 

	
 
	grfmsg(3, "SkipActA: Skipping %d sprites", _skip_sprites);
 
}
 

	
 
/* Action 0x0B */
 
static void GRFLoadError(byte *buf, int len)
 
{
 
	/* <0B> <severity> <language-id> <message-id> [<message...> 00] [<data...>] 00 [<parnum>]
 
	 *
 
	 * B severity      00: notice, contine 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
 
	};
 

	
 
	static const StringID sevstr[] = {
 
		STR_NEWGRF_ERROR_MSG_INFO,
 
		STR_NEWGRF_ERROR_MSG_WARNING,
 
		STR_NEWGRF_ERROR_MSG_ERROR,
 
		STR_NEWGRF_ERROR_MSG_FATAL
 
	};
 

	
 
	/* AddGRFString expects the string to be referred to by an id in the newgrf
 
	 * file. Errors messages are never referred to however, so invent ids that
 
	 * are unlikely to be reached in a newgrf file so they don't overwrite
 
	 * anything else. */
 
	enum {
 
		MESSAGE_STRING_ID = MAX_UVALUE(StringID) - 1,
 
		MESSAGE_DATA_ID   = MAX_UVALUE(StringID)
 
	};
 

	
 
	if (!check_length(len, 6, "GRFLoadError")) return;
 

	
 
	/* For now we can only show one message per newgrf file. */
 
	if (_cur_grfconfig->error != NULL) return;
 

	
 
	buf++; // Skip the action byte.
 
	byte severity   = grf_load_byte(&buf);
 
	byte lang       = grf_load_byte(&buf);
 
	byte message_id = grf_load_byte(&buf);
 
	len -= 4;
 

	
 
	/* Skip the error if it isn't valid for the current language. */
 
	if (!CheckGrfLangID(lang, _cur_grffile->grf_version)) return;
 

	
 
	/* Skip the error until the activation stage unless bit 7 of the severity
 
	 * is set. */
 
	if (!HASBIT(severity, 7) && _cur_stage == GLS_INIT) {
 
		grfmsg(7, "GRFLoadError: Skipping non-fatal GRFLoadError in stage %d", _cur_stage);
 
		return;
 
	}
 
	CLRBIT(severity, 7);
 

	
 
	if (severity >= lengthof(sevstr)) {
 
		grfmsg(7, "GRFLoadError: Invalid severity id %d. 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. */
 
		_cur_grfconfig->status = GCS_DISABLED;
 

	
 
		_skip_sprites = -1;
 
	}
 

	
 
	if (message_id >= lengthof(msgstr) && message_id != 0xFF) {
 
		grfmsg(7, "GRFLoadError: Invalid message id.");
 
		return;
 
	}
 

	
 
	if (len <= 1) {
 
		grfmsg(7, "GRFLoadError: No message data supplied.");
 
		return;
 
	}
 

	
 
	bool new_scheme = _cur_grffile->grf_version >= 7;
 
	GRFError *error = CallocT<GRFError>(1);
 

	
 
	error->severity = sevstr[severity];
 

	
 
	if (message_id == 0xFF) {
 
		/* This is a custom error message. */
 
		const char *message = grf_load_string(&buf, len);
 
		len -= (strlen(message) + 1);
 

	
 
		error->message = AddGRFString(_cur_grffile->grfid, MESSAGE_STRING_ID, lang, new_scheme, message, STR_UNDEFINED);
 
		error->custom_message = TranslateTTDPatchCodes(message);
 
	} else {
 
		error->message = msgstr[message_id];
 
	}
 

	
 
	if (len > 0) {
 
		const char *data = grf_load_string(&buf, len);
 
		len -= (strlen(data) + 1);
 

	
 
		error->data = AddGRFString(_cur_grffile->grfid, MESSAGE_DATA_ID, lang, new_scheme, data, STR_UNDEFINED);
 
		error->data = TranslateTTDPatchCodes(data);
 
	}
 

	
 
	/* Only two parameter numbers can be used in the string. */
 
	uint i = 0;
 
	for (; i < 2 && len > 0; i++) {
 
		error->param_number[i] = grf_load_byte(&buf);
 
		len--;
 
	}
 
	error->num_params = i;
 

	
 
	_cur_grfconfig->error = error;
 
}
 

	
 
/* Action 0x0C */
 
static void GRFComment(byte *buf, int len)
 
{
 
	/* <0C> [<ignored...>]
 
	 *
 
	 * V ignored       Anything following the 0C is ignored */
 

	
 
	if (len == 1) return;
 

	
 
	int text_len = len - 1;
 
	const char *text = (const char*)(buf + 1);
 
	grfmsg(2, "GRFComment: %.*s", text_len, text);
 
}
 

	
 
/* Action 0x0D (GLS_SAFETYSCAN) */
 
static void SafeParamSet(byte *buf, int len)
 
{
 
	if (!check_length(len, 5, "SafeParamSet")) return;
 
	buf++;
 
	uint8 target = grf_load_byte(&buf);
 

	
 
	/* Only writing GRF parameters is considered safe */
 
	if (target < 0x80) return;
 

	
 
	/* GRM could be unsafe, but as here it can only happen after other GRFs
 
	 * are loaded, it should be okay. If the GRF tried to use the slots it
 
	 * reserved, it would be marked unsafe anyway. GRM for (e.g. bridge)
 
	 * sprites  is considered safe. */
 

	
 
	SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
 

	
 
	/* Skip remainder of GRF */
 
	_skip_sprites = -1;
 
}
 

	
 

	
 
static uint32 GetPatchVariable(uint8 param)
 
{
 
	switch (param) {
 
		/* start year - 1920 */
 
		case 0x0B: return max(_patches.starting_year, ORIGINAL_BASE_YEAR) - ORIGINAL_BASE_YEAR;
 
		/* freight trains weight factor */
 
		case 0x0E: return _patches.freight_trains;
 
		/* empty wagon speed increase */
 
		case 0x0F: return 0;
 
		/* plane speed factor */
 
		case 0x10: return 4;
 
		/* 2CC colormap base sprite */
 
		case 0x11: return SPR_2CCMAP_BASE;
 

	
 
		default:
 
			grfmsg(2, "ParamSet: Unknown Patch variable 0x%02X.", param);
 
			return 0;
 
	}
 
}
 

	
 

	
 
static uint32 PerformGRM(uint32 *grm, uint16 num_ids, uint16 count, uint8 op, uint8 target, const char *type)
 
{
 
	uint start = 0;
 
	uint size  = 0;
 

	
 
	if (op == 6) {
 
		/* Return GRFID of set that reserved ID */
 
		return grm[_cur_grffile->param[target]];
 
	}
 

	
 
	/* With an operation of 2 or 3, we want to reserve a specific block of IDs */
 
	if (op == 2 || op == 3) start = _cur_grffile->param[target];
 

	
 
	for (uint i = start; i < num_ids; i++) {
 
		if (grm[i] == 0) {
 
			size++;
 
		} else {
 
			if (op == 2 || op == 3) break;
 
			start = i + 1;
 
			size = 0;
 
		}
 

	
 
		if (size == count) break;
 
	}
 

	
 
	if (size == count) {
 
@@ -4023,194 +4017,198 @@ static void LoadGRFSound(byte *buf, int 
 
	for (;;) {
 
		uint32 tag  = grf_load_dword(&buf);
 
		uint32 size = grf_load_dword(&buf);
 

	
 
		switch (tag) {
 
			case ' tmf': // 'fmt '
 
				/* Audio format, must be 1 (PCM) */
 
				if (grf_load_word(&buf) != 1) {
 
					grfmsg(1, "LoadGRFSound: Invalid audio format");
 
					return;
 
				}
 
				se->channels = grf_load_word(&buf);
 
				se->rate = grf_load_dword(&buf);
 
				grf_load_dword(&buf);
 
				grf_load_word(&buf);
 
				se->bits_per_sample = grf_load_word(&buf);
 

	
 
				/* Consume any extra bytes */
 
				for (; size > 16; size--) grf_load_byte(&buf);
 
				break;
 

	
 
			case 'atad': // 'data'
 
				se->file_size    = size;
 
				se->file_offset  = FioGetPos() - (len - (buf - buf_start)) + 1;
 
				se->file_offset |= _file_index << 24;
 

	
 
				/* Set default volume and priority */
 
				se->volume = 0x80;
 
				se->priority = 0;
 

	
 
				grfmsg(2, "LoadGRFSound: channels %u, sample rate %u, bits per sample %u, length %u", se->channels, se->rate, se->bits_per_sample, size);
 
				return;
 

	
 
			default:
 
				se->file_size = 0;
 
				return;
 
		}
 
	}
 
}
 

	
 
/* Action 0x12 */
 
static void LoadFontGlyph(byte *buf, int len)
 
{
 
	/* <12> <num_def> <font_size> <num_char> <base_char>
 
	 *
 
	 * B num_def      Number of definitions
 
	 * B font_size    Size of font (0 = normal, 1 = small, 2 = large)
 
	 * B num_char     Number of consecutive glyphs
 
	 * W base_char    First character index */
 

	
 
	buf++; len--;
 
	if (!check_length(len, 1, "LoadFontGlyph")) return;
 

	
 
	uint8 num_def = grf_load_byte(&buf);
 

	
 
	if (!check_length(len, 1 + num_def * 4, "LoadFontGlyph")) return;
 

	
 
	for (uint i = 0; i < num_def; i++) {
 
		FontSize size    = (FontSize)grf_load_byte(&buf);
 
		uint8  num_char  = grf_load_byte(&buf);
 
		uint16 base_char = grf_load_word(&buf);
 

	
 
		grfmsg(7, "LoadFontGlyph: Loading %u glyph(s) at 0x%04X for size %u", num_char, base_char, size);
 

	
 
		for (uint c = 0; c < num_char; c++) {
 
			SetUnicodeGlyph(size, base_char + c, _cur_spriteid);
 
			LoadNextSprite(_cur_spriteid++, _file_index);
 
			_nfo_line++;
 
		}
 
	}
 
}
 

	
 
/* Action 0x13 */
 
static void TranslateGRFStrings(byte *buf, int len)
 
{
 
	/* <13> <grfid> <num-ent> <offset> <text...>
 
	 *
 
	 * 4*B grfid     The GRFID of the file whose texts are to be translated
 
	 * B   num-ent   Number of strings
 
	 * W   offset    First text ID
 
	 * S   text...   Zero-terminated strings */
 

	
 
	buf++; len--;
 
	if (!check_length(len, 7, "TranslateGRFString")) return;
 

	
 
	uint32 grfid = grf_load_dword(&buf);
 
	const GRFConfig *c = GetGRFConfig(grfid);
 
	if (c == NULL || (c->status != GCS_INITIALISED && c->status != GCS_ACTIVATED)) {
 
		grfmsg(7, "TranslateGRFStrings: GRFID 0x%08x unknown, skipping action 13", BSWAP32(grfid));
 
		return;
 
	}
 

	
 
	if (c->status == GCS_INITIALISED) {
 
		/* If the file is not active but will be activated later, give an error
 
		 * and disable this file. */
 
		GRFError *error = CallocT<GRFError>(1);
 

	
 
		char tmp[256];
 
		GetString(tmp, STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE, lastof(tmp));
 
		error->data = strdup(tmp);
 

	
 
		error->message  = STR_NEWGRF_ERROR_LOAD_AFTER;
 
		error->data     = STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE;
 
		error->severity = STR_NEWGRF_ERROR_MSG_FATAL;
 

	
 
		if (_cur_grfconfig->error != NULL) free(_cur_grfconfig->error);
 
		_cur_grfconfig->error = error;
 

	
 
		_cur_grfconfig->status = GCS_DISABLED;
 
		_skip_sprites = -1;
 
		return;
 
	}
 

	
 
	byte num_strings = grf_load_byte(&buf);
 
	uint16 first_id  = grf_load_word(&buf);
 

	
 
	if (!((first_id >= 0xD000 && first_id + num_strings <= 0xD3FF) || (first_id >= 0xDC00 && first_id + num_strings <= 0xDCFF))) {
 
		grfmsg(7, "TranslateGRFStrings: Attempting to set out-of-range string IDs in action 13 (first: 0x%4X, number: 0x%2X)", first_id, num_strings);
 
		return;
 
	}
 

	
 
	len -= 7;
 

	
 
	for (uint i = 0; i < num_strings && len > 0; i++) {
 
		const char *string   = grf_load_string(&buf, len);
 
		size_t string_length = strlen(string) + 1;
 

	
 
		len -= (int)string_length;
 

	
 
		if (string_length == 1) {
 
			grfmsg(7, "TranslateGRFString: Ignoring empty string.");
 
			continue;
 
		}
 

	
 
		/* Since no language id is supplied this string has to be added as a
 
		 * generic string, thus the language id of 0x7F. For this to work
 
		 * new_scheme has to be true as well. A language id of 0x7F will be
 
		 * overridden by a non-generic id, so this will not change anything if
 
		 * a string has been provided specifically for this language. */
 
		AddGRFString(grfid, first_id + i, 0x7F, true, string, STR_UNDEFINED);
 
	}
 
}
 

	
 
/* 'Action 0xFF' */
 
static void GRFDataBlock(byte *buf, int len)
 
{
 
	if (_grf_data_blocks == 0) {
 
		grfmsg(2, "GRFDataBlock: unexpected data block, skipping");
 
		return;
 
	}
 

	
 
	buf++;
 
	uint8 name_len = grf_load_byte(&buf);
 
	const char *name = (const char *)buf;
 
	buf += name_len + 1;
 

	
 
	grfmsg(2, "GRFDataBlock: block name '%s'...", name);
 

	
 
	_grf_data_blocks--;
 

	
 
	switch (_grf_data_type) {
 
		case GDT_SOUND: LoadGRFSound(buf, len - name_len - 2); break;
 
		default: NOT_REACHED(); break;
 
	}
 
}
 

	
 

	
 
/* Used during safety scan on unsafe actions */
 
static void GRFUnsafe(byte *buf, int len)
 
{
 
	SETBIT(_cur_grfconfig->flags, GCF_UNSAFE);
 

	
 
	/* Skip remainder of GRF */
 
	_skip_sprites = -1;
 
}
 

	
 

	
 
static void InitializeGRFSpecial()
 
{
 
	_ttdpatch_flags[0] =  ((_patches.always_small_airport ? 1 : 0) << 0x0C)  // keepsmallairport
 
	                   |                                        (1 << 0x0D)  // newairports
 
	                   |                                        (1 << 0x0E)  // largestations
 
	                   |           ((_patches.longbridges ? 1 : 0) << 0x0F)  // longbridges
 
	                   |                                        (0 << 0x10)  // loadtime
 
	                   |                                        (1 << 0x12)  // presignals
 
	                   |                                        (1 << 0x13)  // extpresignals
 
	                   | ((_patches.never_expire_vehicles ? 1 : 0) << 0x16)  // enginespersist
 
	                   |                                        (1 << 0x1B)  // multihead
 
	                   |                                        (1 << 0x1D)  // lowmemory
 
	                   |                                        (1 << 0x1E); // generalfixes
 

	
 
	_ttdpatch_flags[1] =                                        (0 << 0x07)  // moreairports - based on units of noise
 
	                   |        ((_patches.mammoth_trains ? 1 : 0) << 0x08)  // mammothtrains
 
	                   |                                        (1 << 0x09)  // trainrefit
 
	                   |                                        (0 << 0x0B)  // subsidiaries
 
	                   |       ((_patches.gradual_loading ? 1 : 0) << 0x0C)  // gradualloading
 
	                   |                                        (1 << 0x12)  // unifiedmaglevmode - set bit 0 mode. Not revelant to OTTD
 
	                   |                                        (1 << 0x13)  // unifiedmaglevmode - set bit 1 mode
 
	                   |                                        (1 << 0x14)  // bridgespeedlimits
 
@@ -4309,192 +4307,194 @@ static void ResetCustomStations()
 
		free(file->stations);
 
		file->stations = NULL;
 
	}
 
}
 

	
 
static void ResetCustomHouses()
 
{
 
	GRFFile *file;
 
	uint i;
 

	
 
	for (file = _first_grffile; file != NULL; file = file->next) {
 
		if (file->housespec == NULL) continue;
 
		for (i = 0; i < HOUSE_MAX; i++) {
 
			free(file->housespec[i]);
 
		}
 

	
 
		free(file->housespec);
 
		file->housespec = NULL;
 
	}
 
}
 

	
 
static void ResetCustomIndustries()
 
{
 
	GRFFile *file;
 

	
 
	for (file = _first_grffile; file != NULL; file = file->next) {
 
		uint i;
 
		/* We are verifiying both tiles and industries specs loaded from the grf file
 
		 * First, let's deal with industryspec */
 
		if (file->industryspec != NULL) {
 

	
 
			for (i = 0; i < NUM_INDUSTRYTYPES; i++) {
 
				IndustrySpec *ind = file->industryspec[i];
 

	
 
				if (ind != NULL) {
 
					/* We need to remove the sounds array */
 
					if (HASBIT(ind->cleanup_flag, CLEAN_RANDOMSOUNDS)) {
 
						free((void*)ind->random_sounds);
 
					}
 

	
 
					/* We need to remove the tiles layouts */
 
					if (HASBIT(ind->cleanup_flag, CLEAN_TILELSAYOUT) && ind->table != NULL) {
 
						for (int j = 0; j < ind->num_table; j++) {
 
							/* remove the individual layouts */
 
							if (ind->table[j] != NULL) {
 
								free((IndustryTileTable*)ind->table[j]);
 
							}
 
						}
 
						/* remove the layouts pointers */
 
						free((IndustryTileTable**)ind->table);
 
						ind->table = NULL;
 
					}
 

	
 
					free(ind);
 
					ind = NULL;
 
				}
 
			}
 

	
 
			free(file->industryspec);
 
			file->industryspec = NULL;
 
		}
 

	
 
		if (file->indtspec != NULL) {
 
			for (i = 0; i < NUM_INDUSTRYTILES; i++) {
 
				if (file->indtspec[i] != NULL) {
 
					free(file->indtspec[i]);
 
					file->indtspec[i] = NULL;
 
				}
 
			}
 

	
 
			free(file->indtspec);
 
			file->indtspec = NULL;
 
		}
 
	}
 
}
 

	
 
static void ResetNewGRF()
 
{
 
	GRFFile *next;
 

	
 
	for (GRFFile *f = _first_grffile; f != NULL; f = next) {
 
		next = f->next;
 

	
 
		free(f->filename);
 
		free(f->cargo_list);
 
		free(f);
 
	}
 

	
 
	_first_grffile = NULL;
 
	_cur_grffile   = NULL;
 
}
 

	
 
static void ResetNewGRFErrors()
 
{
 
	for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
 
		if (!HASBIT(c->flags, GCF_COPY) && c->error != NULL) {
 
			free(c->error->custom_message);
 
			free(c->error->data);
 
			free(c->error);
 
			c->error = NULL;
 
		}
 
	}
 
}
 

	
 
/**
 
 * Reset all NewGRF loaded data
 
 * TODO
 
 */
 
static void ResetNewGRFData()
 
{
 
	CleanUpStrings();
 

	
 
	/* Copy/reset original engine info data */
 
	memcpy(&_engine_info, &orig_engine_info, sizeof(orig_engine_info));
 
	memcpy(&_rail_vehicle_info, &orig_rail_vehicle_info, sizeof(orig_rail_vehicle_info));
 
	memcpy(&_ship_vehicle_info, &orig_ship_vehicle_info, sizeof(orig_ship_vehicle_info));
 
	memcpy(&_aircraft_vehicle_info, &orig_aircraft_vehicle_info, sizeof(orig_aircraft_vehicle_info));
 
	memcpy(&_road_vehicle_info, &orig_road_vehicle_info, sizeof(orig_road_vehicle_info));
 

	
 
	/* Copy/reset original bridge info data
 
	 * First, free sprite table data */
 
	for (uint i = 0; i < MAX_BRIDGES; i++) {
 
		if (_bridge[i].sprite_table != NULL) {
 
			for (uint j = 0; j < 7; j++) free(_bridge[i].sprite_table[j]);
 
			free(_bridge[i].sprite_table);
 
		}
 
	}
 
	memcpy(&_bridge, &orig_bridge, sizeof(_bridge));
 

	
 
	/* Reset refit/cargo class data */
 
	memset(&cargo_allowed, 0, sizeof(cargo_allowed));
 
	memset(&cargo_disallowed, 0, sizeof(cargo_disallowed));
 

	
 
	/* Reset GRM reservations */
 
	memset(&_grm_engines, 0, sizeof(_grm_engines));
 
	memset(&_grm_cargos, 0, sizeof(_grm_cargos));
 

	
 
	/* Unload sprite group data */
 
	UnloadWagonOverrides();
 
	UnloadRotorOverrideSprites();
 
	UnloadCustomEngineSprites();
 
	UnloadCustomEngineNames();
 
	ResetEngineListOrder();
 

	
 
	/* Reset price base data */
 
	ResetPriceBaseMultipliers();
 

	
 
	/* Reset the curencies array */
 
	ResetCurrencies();
 

	
 
	/* Reset the house array */
 
	ResetCustomHouses();
 
	ResetHouses();
 

	
 
	/* Reset the industries structures*/
 
	ResetCustomIndustries();
 
	ResetIndustries();
 

	
 
	/* Reset station classes */
 
	ResetStationClasses();
 
	ResetCustomStations();
 

	
 
	/* Reset canal sprite groups */
 
	memset(_canal_sg, 0, sizeof(_canal_sg));
 

	
 
	/* Reset the snowline table. */
 
	ClearSnowLine();
 

	
 
	/* Reset NewGRF files */
 
	ResetNewGRF();
 

	
 
	/* Reset NewGRF errors. */
 
	ResetNewGRFErrors();
 

	
 
	/* Add engine type to engine data. This is needed for the refit precalculation. */
 
	AddTypeToEngines();
 

	
 
	/* Set up the default cargo types */
 
	SetupCargoForClimate(_opt.landscape);
 

	
 
	/* Reset misc GRF features and train list display variables */
 
	_misc_grf_features = 0;
 
	_traininfo_vehicle_pitch = 0;
 
	_traininfo_vehicle_width = 29;
 

	
 
	_loaded_newgrf_features = 0;
 

	
 
	_signal_base = 0;
 
	_coast_base = 0;
 

	
 
	InitializeSoundPool();
 
	InitializeSpriteGroupPool();
 
}
 

	
src/newgrf_config.cpp
Show inline comments
 
@@ -4,229 +4,236 @@
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "functions.h"
 
#include "macros.h"
 
#include "debug.h"
 
#include "variables.h"
 
#include "string.h"
 
#include "saveload.h"
 
#include "md5.h"
 
#include "network/network_data.h"
 
#include "newgrf.h"
 
#include "newgrf_config.h"
 
#include "helpers.hpp"
 

	
 
#include "fileio.h"
 
#include "fios.h"
 
#include <sys/stat.h>
 

	
 
#ifdef WIN32
 
# include <io.h>
 
#endif /* WIN32 */
 

	
 

	
 
GRFConfig *_all_grfs;
 
GRFConfig *_grfconfig;
 
GRFConfig *_grfconfig_newgame;
 
GRFConfig *_grfconfig_static;
 

	
 

	
 
/* Calculate the MD5 Sum for a GRF */
 
static bool CalcGRFMD5Sum(GRFConfig *config)
 
{
 
	FILE *f;
 
	md5_state_t md5state;
 
	md5_byte_t buffer[1024];
 
	size_t len;
 

	
 
	/* open the file */
 
	f = FioFOpenFile(config->full_path);
 
	if (f == NULL) return false;
 

	
 
	/* calculate md5sum */
 
	md5_init(&md5state);
 
	while ((len = fread(buffer, 1, sizeof(buffer), f)) != 0) {
 
		md5_append(&md5state, buffer, len);
 
	}
 
	md5_finish(&md5state, config->md5sum);
 

	
 
	fclose(f);
 

	
 
	return true;
 
}
 

	
 

	
 
/* Find the GRFID and calculate the md5sum */
 
bool FillGRFDetails(GRFConfig *config, bool is_static)
 
{
 
	if (!FioCheckFileExists(config->full_path)) {
 
		config->status = GCS_NOT_FOUND;
 
		return false;
 
	}
 

	
 
	if (config->filename == NULL) {
 
		const char *t = strrchr(config->full_path, PATHSEPCHAR);
 
		config->filename = strdup(t != NULL ? t + 1 : config->full_path);
 
	}
 

	
 
	/* Find and load the Action 8 information */
 
	/* 62 is the last file slot before sample.cat.
 
	 * Should perhaps be some "don't care" value */
 
	LoadNewGRFFile(config, 62, GLS_FILESCAN);
 

	
 
	/* Skip if the grfid is 0 (not read) or 0xFFFFFFFF (ttdp system grf) */
 
	if (config->grfid == 0 || config->grfid == 0xFFFFFFFF) return false;
 

	
 
	if (is_static) {
 
		/* Perform a 'safety scan' for static GRFs */
 
		LoadNewGRFFile(config, 62, GLS_SAFETYSCAN);
 

	
 
		/* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */
 
		if (HASBIT(config->flags, GCF_UNSAFE)) return false;
 
	}
 

	
 
	return CalcGRFMD5Sum(config);
 
}
 

	
 

	
 
void ClearGRFConfig(GRFConfig **config)
 
{
 
	/* GCF_COPY as in NOT strdupped/alloced the filename, name and info */
 
	if (!HASBIT((*config)->flags, GCF_COPY)) {
 
		free((*config)->filename);
 
		free((*config)->full_path);
 
		free((*config)->name);
 
		free((*config)->info);
 

	
 
		if ((*config)->error != NULL) {
 
			free((*config)->error->custom_message);
 
			free((*config)->error->data);
 
		free((*config)->error);
 
	}
 
	}
 
	free(*config);
 
	*config = NULL;
 
}
 

	
 

	
 
/* Clear a GRF Config list */
 
void ClearGRFConfigList(GRFConfig **config)
 
{
 
	GRFConfig *c, *next;
 
	for (c = *config; c != NULL; c = next) {
 
		next = c->next;
 
		ClearGRFConfig(&c);
 
	}
 
	*config = NULL;
 
}
 

	
 

	
 
/** Copy a GRF Config list
 
 * @param dst pointer to destination list
 
 * @param src pointer to source list values
 
 * @return pointer to the last value added to the destination list */
 
GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src)
 
{
 
	/* Clear destination as it will be overwritten */
 
	ClearGRFConfigList(dst);
 
	for (; src != NULL; src = src->next) {
 
		GRFConfig *c = CallocT<GRFConfig>(1);
 
		*c = *src;
 
		if (src->filename  != NULL) c->filename  = strdup(src->filename);
 
		if (src->full_path != NULL) c->full_path = strdup(src->full_path);
 
		if (src->name      != NULL) c->name      = strdup(src->name);
 
		if (src->info      != NULL) c->info      = strdup(src->info);
 
		if (src->error     != NULL) {
 
			c->error = CallocT<GRFError>(1);
 
			memcpy(c->error, src->error, sizeof(GRFError));
 
			if (src->error->data != NULL) c->error->data = strdup(src->error->data);
 
			if (src->error->custom_message != NULL) c->error->custom_message = strdup(src->error->custom_message);
 
		}
 

	
 
		*dst = c;
 
		dst = &c->next;
 
	}
 

	
 
	return dst;
 
}
 

	
 
/**
 
 * Removes duplicates from lists of GRFConfigs. These duplicates
 
 * are introduced when the _grfconfig_static GRFs are appended
 
 * to the _grfconfig on a newgame or savegame. As the parameters
 
 * of the static GRFs could be different that the parameters of
 
 * the ones used non-statically. This can result in desyncs in
 
 * multiplayers, so the duplicate static GRFs have to be removed.
 
 *
 
 * This function _assumes_ that all static GRFs are placed after
 
 * the non-static GRFs.
 
 *
 
 * @param list the list to remove the duplicates from
 
 */
 
static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list)
 
{
 
	GRFConfig *prev;
 
	GRFConfig *cur;
 

	
 
	if (list == NULL) return;
 

	
 
	for (prev = list, cur = list->next; cur != NULL; prev = cur, cur = cur->next) {
 
		if (cur->grfid != list->grfid) continue;
 

	
 
		prev->next = cur->next;
 
		ClearGRFConfig(&cur);
 
		cur = prev; // Just go back one so it continues as normal later on
 
	}
 

	
 
	RemoveDuplicatesFromGRFConfigList(list->next);
 
}
 

	
 
/**
 
 * Appends the static GRFs to a list of GRFs
 
 * @param dst the head of the list to add to
 
 */
 
void AppendStaticGRFConfigs(GRFConfig **dst)
 
{
 
	GRFConfig **tail = dst;
 
	while (*tail != NULL) tail = &(*tail)->next;
 

	
 
	CopyGRFConfigList(tail, _grfconfig_static);
 
	RemoveDuplicatesFromGRFConfigList(*dst);
 
}
 

	
 
/** Appends an element to a list of GRFs
 
 * @param dst the head of the list to add to
 
 * @param el the new tail to be */
 
void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el)
 
{
 
	GRFConfig **tail = dst;
 
	while (*tail != NULL) tail = &(*tail)->next;
 
	*tail = el;
 

	
 
	RemoveDuplicatesFromGRFConfigList(*dst);
 
}
 

	
 

	
 
/* Reset the current GRF Config to either blank or newgame settings */
 
void ResetGRFConfig(bool defaults)
 
{
 
	GRFConfig **c = &_grfconfig;
 

	
 
	if (defaults) {
 
		c = CopyGRFConfigList(c, _grfconfig_newgame);
 
	} else {
 
		ClearGRFConfigList(c);
 
	}
 

	
 
	AppendStaticGRFConfigs(&_grfconfig);
 
}
 

	
 

	
 
/** Check if all GRFs in the GRF config from a savegame can be loaded.
 
 * @return will return any of the following 3 values:<br>
 
 * <ul>
 
 * <li> GLC_ALL_GOOD: No problems occured, all GRF files were found and loaded
 
 * <li> GLC_COMPATIBLE: For one or more GRF's no exact match was found, but a
 
 *     compatible GRF with the same grfid was found and used instead
 
 * <li> GLC_NOT_FOUND: For one or more GRF's no match was found at all
 
 * </ul> */
 
GRFListCompatibility IsGoodGRFConfigList()
 
{
 
	GRFListCompatibility res = GLC_ALL_GOOD;
 

	
 
	for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
 
		const GRFConfig *f = FindGRFConfig(c->grfid, c->md5sum);
 
		if (f == NULL) {
src/newgrf_config.h
Show inline comments
 
/* $Id$ */
 

	
 
/** @file newgrf_config.h */
 

	
 
#ifndef NEWGRF_CONFIG_H
 
#define NEWGRF_CONFIG_H
 

	
 
#include "openttd.h"
 

	
 
/* GRF config bit flags */
 
enum GCF_Flags {
 
	GCF_SYSTEM,    ///< GRF file is an openttd-internal system grf
 
	GCF_UNSAFE,    ///< GRF file is unsafe for static usage
 
	GCF_STATIC,    ///< GRF file is used statically (can be used in any MP game)
 
	GCF_COMPATIBLE,///< GRF file does not exactly match the requested GRF (different MD5SUM), but grfid matches)
 
	GCF_COPY,      ///< The data is copied from a grf in _all_grfs
 
};
 

	
 
enum GRFStatus {
 
	GCS_UNKNOWN,      ///< The status of this grf file is unknown
 
	GCS_DISABLED,     ///< GRF file is disabled
 
	GCS_NOT_FOUND,    ///< GRF file was not found in the local cache
 
	GCS_INITIALISED,  ///< GRF file has been initialised
 
	GCS_ACTIVATED     ///< GRF file has been activated
 
};
 

	
 
enum GRFListCompatibility{
 
	GLC_ALL_GOOD,
 
	GLC_COMPATIBLE,
 
	GLC_NOT_FOUND
 
};
 

	
 
struct GRFIdentifier {
 
	uint32 grfid;
 
	uint8 md5sum[16];
 
};
 

	
 
struct GRFError {
 
	char *custom_message;
 
	char *data;
 
	StringID message;
 
	StringID data;
 
	StringID severity;
 
	uint8 num_params;
 
	uint8 param_number[2];
 
};
 

	
 
struct GRFConfig : public GRFIdentifier {
 
	char *filename;
 
	char *full_path;
 
	char *name;
 
	char *info;
 
	GRFError *error;
 

	
 
	uint8 flags;
 
	GRFStatus status;
 
	uint32 param[0x80];
 
	uint8 num_params;
 

	
 
	struct GRFConfig *next;
 
};
 

	
 
/* First item in list of all scanned NewGRFs */
 
extern GRFConfig *_all_grfs;
 

	
 
/* First item in list of current GRF set up */
 
extern GRFConfig *_grfconfig;
 

	
 
/* First item in list of default GRF set up */
 
extern GRFConfig *_grfconfig_newgame;
 

	
 
/* First item in list of static GRF set up */
 
extern GRFConfig *_grfconfig_static;
 

	
 
void ScanNewGRFFiles();
 
const GRFConfig *FindGRFConfig(uint32 grfid, const uint8 *md5sum = NULL);
 
GRFConfig *GetGRFConfig(uint32 grfid);
 
GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src);
 
void AppendStaticGRFConfigs(GRFConfig **dst);
 
void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el);
 
void ClearGRFConfig(GRFConfig **config);
 
void ClearGRFConfigList(GRFConfig **config);
 
void ResetGRFConfig(bool defaults);
 
GRFListCompatibility IsGoodGRFConfigList();
 
bool FillGRFDetails(GRFConfig *config, bool is_static);
 
char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last);
 

	
 
/* In newgrf_gui.cpp */
 
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config);
 

	
 
#ifdef ENABLE_NETWORK
 
/* For communication about GRFs over the network */
 
#define UNKNOWN_GRF_NAME_PLACEHOLDER "<Unknown>"
 
char *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create);
 
#endif /* ENABLE_NETWORK */
 

	
 
#endif /* NEWGRF_CONFIG_H */
src/newgrf_gui.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file newgrf_gui.cpp */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "functions.h"
 
#include "variables.h"
 
#include "gfx.h"
 
#include "gui.h"
 
#include "window.h"
 
#include "table/strings.h"
 
#include "table/sprites.h"
 
#include "newgrf.h"
 
#include "newgrf_config.h"
 
#include "strings.h"
 
#include "helpers.hpp"
 

	
 

	
 
/** Parse an integerlist string and set each found value
 
 * @param p the string to be parsed. Each element in the list is seperated by a
 
 * comma or a space character
 
 * @param items pointer to the integerlist-array that will be filled with values
 
 * @param maxitems the maximum number of elements the integerlist-array has
 
 * @return returns the number of items found, or -1 on an error */
 
static int parse_intlist(const char *p, int *items, int maxitems)
 
{
 
	int n = 0, v;
 
	char *end;
 

	
 
	for (;;) {
 
		v = strtol(p, &end, 0);
 
		if (p == end || n == maxitems) return -1;
 
		p = end;
 
		items[n++] = v;
 
		if (*p == '\0') break;
 
		if (*p != ',' && *p != ' ') return -1;
 
		p++;
 
	}
 

	
 
	return n;
 
}
 

	
 

	
 
static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint w, uint bottom, bool show_params)
 
{
 
	char buff[256];
 

	
 
	if (c->error != NULL) {
 
		SetDParamStr(0, c->filename);
 
		SetDParam(1, c->error->data);
 
		SetDParamStr(1, c->error->data);
 
		for (uint i = 0; i < c->error->num_params; i++) {
 
			uint32 param = 0;
 
			byte param_number = c->error->param_number[i];
 

	
 
			if (param_number < c->num_params) param = c->param[param_number];
 

	
 
			SetDParam(2 + i, param);
 
		}
 

	
 
		char message[512];
 
		GetString(message, c->error->message, lastof(message));
 
		GetString(message, c->error->custom_message != NULL ? BindCString(c->error->custom_message) : c->error->message, lastof(message));
 

	
 
		SetDParamStr(0, message);
 
		y += DrawStringMultiLine(x, y, c->error->severity, w, bottom - y);
 
	}
 

	
 
	/* Draw filename or not if it is not known (GRF sent over internet) */
 
	if (c->filename != NULL) {
 
		SetDParamStr(0, c->filename);
 
		y += DrawStringMultiLine(x, y, STR_NEWGRF_FILENAME, w, bottom - y);
 
	}
 

	
 
	/* Prepare and draw GRF ID */
 
	snprintf(buff, lengthof(buff), "%08X", BSWAP32(c->grfid));
 
	SetDParamStr(0, buff);
 
	y += DrawStringMultiLine(x, y, STR_NEWGRF_GRF_ID, w, bottom - y);
 

	
 
	/* Prepare and draw MD5 sum */
 
	md5sumToString(buff, lastof(buff), c->md5sum);
 
	SetDParamStr(0, buff);
 
	y += DrawStringMultiLine(x, y, STR_NEWGRF_MD5SUM, w, bottom - y);
 

	
 
	/* Show GRF parameter list */
 
	if (show_params) {
 
		if (c->num_params > 0) {
 
			GRFBuildParamList(buff, c, lastof(buff));
 
			SetDParamStr(0, buff);
 
		} else {
 
			SetDParam(0, STR_01A9_NONE);
 
		}
 
		y += DrawStringMultiLine(x, y, STR_NEWGRF_PARAMETER, w, bottom - y);
 
	}
 

	
 
	/* Show flags */
 
	if (c->status == GCS_NOT_FOUND)        y += DrawStringMultiLine(x, y, STR_NEWGRF_NOT_FOUND, w, bottom - y);
 
	if (c->status == GCS_DISABLED)         y += DrawStringMultiLine(x, y, STR_NEWGRF_DISABLED, w, bottom - y);
 
	if (HASBIT(c->flags, GCF_COMPATIBLE)) y += DrawStringMultiLine(x, y, STR_NEWGRF_COMPATIBLE_LOADED, w, bottom - y);
 

	
 
	/* Draw GRF info if it exists */
 
	if (c->info != NULL && !StrEmpty(c->info)) {
 
		SetDParamStr(0, c->info);
 
		y += DrawStringMultiLine(x, y, STR_02BD, w, bottom - y);
 
	} else {
 
		y += DrawStringMultiLine(x, y, STR_NEWGRF_NO_INFO, w, bottom - y);
 
	}
 
}
 

	
 

	
 
/* Dialogue for adding NewGRF files to the selection */
 
struct newgrf_add_d {
 
	GRFConfig **list;
 
	const GRFConfig *sel;
 
};
 

	
 

	
 
static void NewGRFAddDlgWndProc(Window *w, WindowEvent *e)
 
{
 
	switch (e->event) {
 
		case WE_PAINT: {
 
			const GRFConfig *c;
 
			int y;
 
			int n = 0;
 

	
 
			/* Count the number of GRFs */
 
			for (c = _all_grfs; c != NULL; c = c->next) n++;
 

	
 
			w->vscroll.cap = (w->widget[3].bottom - w->widget[3].top) / 10;
 
			SetVScrollCount(w, n);
 

	
 
			SetWindowWidgetDisabledState(w, 6, WP(w, newgrf_add_d).sel == NULL);
 
			DrawWindowWidgets(w);
 

	
 
			GfxFillRect(w->widget[3].left + 1, w->widget[3].top + 1, w->widget[3].right, w->widget[3].bottom, 0xD7);
 

	
 
			n = 0;
 
			y = w->widget[3].top + 1;
 

	
 
			for (c = _all_grfs; c != NULL; c = c->next) {
 
				if (n >= w->vscroll.pos && n < w->vscroll.pos + w->vscroll.cap) {
 
					bool h = c == WP(w, newgrf_add_d).sel;
 
					const char *text = (c->name != NULL && !StrEmpty(c->name)) ? c->name : c->filename;
 

	
 
					/* Draw selection background */
 
					if (h) GfxFillRect(3, y, w->width - 15, y + 9, 156);
 
					DoDrawStringTruncated(text, 4, y, h ? 0xC : 0x6, w->width - 18);
 
					y += 10;
 
				}
 
				n++;
 
			}
 

	
 
			if (WP(w, newgrf_add_d).sel != NULL) {
 
				const Widget *wi = &w->widget[5];
 
				ShowNewGRFInfo(WP(w, newgrf_add_d).sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, wi->bottom, false);
 
			}
 
			break;
 
		}
 

	
src/newgrf_text.cpp
Show inline comments
 
@@ -352,118 +352,132 @@ StringID AddGRFString(uint32 grfid, uint
 
			if (text->langid != langid_to_add) continue;
 
			newtext->next = text->next;
 
			*ptext = newtext;
 
			delete text;
 
			replaced = true;
 
			break;
 
		}
 

	
 
		/* If a string wasn't replaced, then we must append the new string */
 
		if (!replaced) *ptext = newtext;
 
	}
 

	
 
	grfmsg(3, "Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s'", id, grfid, stringid, newtext->langid, newtext->text);
 

	
 
	return (GRFTAB << TABSIZE) + id;
 
}
 

	
 
/* Used to remember the grfid that the last retrieved string came from */
 
static uint32 _last_grfid = 0;
 

	
 
/**
 
 * Returns the index for this stringid associated with its grfID
 
 */
 
StringID GetGRFStringID(uint32 grfid, uint16 stringid)
 
{
 
	uint id;
 

	
 
	/* grfid is zero when we're being called via an include */
 
	if (grfid == 0) grfid = _last_grfid;
 

	
 
	for (id = 0; id < _num_grf_texts; id++) {
 
		if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) {
 
			return (GRFTAB << TABSIZE) + id;
 
		}
 
	}
 

	
 
	return STR_UNDEFINED;
 
}
 

	
 

	
 
char *GetGRFString(char *buff, uint16 stringid, const char* last)
 
{
 
	const GRFText *default_text = NULL;
 
	const GRFText *search_text;
 

	
 
	assert(_grf_text[stringid].grfid != 0);
 

	
 
	/* Remember this grfid in case the string has included text */
 
	_last_grfid = _grf_text[stringid].grfid;
 

	
 
	/*Search the list of lang-strings of this stringid for current lang */
 
	for (search_text = _grf_text[stringid].textholder; search_text != NULL; search_text = search_text->next) {
 
		if (search_text->langid == _currentLangID) {
 
			return strecpy(buff, search_text->text, last);
 
		}
 

	
 
		/* If the current string is English or American, set it as the
 
		 * fallback language if the specific language isn't available. */
 
		if (search_text->langid == GRFLX_UNSPECIFIED || (default_text == NULL && (search_text->langid == GRFLX_ENGLISH || search_text->langid == GRFLX_AMERICAN))) {
 
			default_text = search_text;
 
		}
 
	}
 

	
 
	/* If there is a fallback string, return that */
 
	if (default_text != NULL) return strecpy(buff, default_text->text, last);
 

	
 
	/* Use the default string ID if the fallback string isn't available */
 
	return GetString(buff, _grf_text[stringid].def_string, last);
 
}
 

	
 
/**
 
 * Equivalence Setter function between game and newgrf langID.
 
 * This function will adjust _currentLangID as to what is the LangID
 
 * of the current language set by the user.
 
 * The array iso_codes will be used to find that match.
 
 * If not found, it will have to be standard english
 
 * This function is called after the user changed language,
 
 * from strings.cpp:ReadLanguagePack
 
 * @param iso_name iso code of current selection
 
 */
 
void SetCurrentGrfLangID(const char *iso_name)
 
{
 
	/* Use English by default, if we can't match up the iso_code. */
 
	byte ret = GRFLX_ENGLISH;
 
	byte i;
 

	
 
	for (i=0; i < lengthof(iso_codes); i++) {
 
		if (strncmp(iso_codes[i].code, iso_name, strlen(iso_codes[i].code)) == 0) {
 
			/* We found a match, so let's use it. */
 
			ret = i;
 
			break;
 
		}
 
	}
 
	_currentLangID = ret;
 
}
 

	
 
bool CheckGrfLangID(byte lang_id, byte grf_version)
 
{
 
	if (grf_version < 7) {
 
		switch (_currentLangID) {
 
			case GRFLX_GERMAN:  return (lang_id & GRFLB_GERMAN)  != 0;
 
			case GRFLX_FRENCH:  return (lang_id & GRFLB_FRENCH)  != 0;
 
			case GRFLX_SPANISH: return (lang_id & GRFLB_SPANISH) != 0;
 
			default:            return (lang_id & (GRFLB_ENGLISH | GRFLB_AMERICAN)) != 0;
 
		}
 
	}
 

	
 
	return (lang_id == _currentLangID || lang_id == GRFLX_UNSPECIFIED);
 
}
 

	
 
/**
 
 * House cleaning.
 
 * Remove all strings and reset the text counter.
 
 */
 
void CleanUpStrings()
 
{
 
	uint id;
 

	
 
	for (id = 0; id < _num_grf_texts; id++) {
 
		GRFText *grftext = _grf_text[id].textholder;
 
		while (grftext != NULL) {
 
			GRFText *grftext2 = grftext->next;
 
			delete grftext;
 
			grftext = grftext2;
 
		}
 
		_grf_text[id].grfid      = 0;
 
		_grf_text[id].stringid   = 0;
 
		_grf_text[id].textholder = NULL;
 
	}
 

	
 
	_num_grf_texts = 0;
 
}
src/newgrf_text.h
Show inline comments
 
/* $Id$ */
 
#ifndef NEWGRF_TEXT_H
 
#define NEWGRF_TEXT_H
 

	
 
/** @file newgrf_text.h
 
 * Header of Action 04 "universal holder" structure and functions
 
 */
 

	
 
StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid, bool new_scheme, const char *text_to_add, StringID def_string);
 
StringID GetGRFStringID(uint32 grfid, uint16 stringid);
 
char *GetGRFString(char *buff, uint16 stringid, const char* last);
 
void CleanUpStrings();
 
void SetCurrentGrfLangID(const char *iso_name);
 
char *TranslateTTDPatchCodes(const char *str);
 

	
 
bool CheckGrfLangID(byte lang_id, byte grf_version);
 

	
 
#endif /* NEWGRF_TEXT_H */
0 comments (0 inline, 0 general)