Changeset - r18776:45400817a6df
[Not reviewed]
master
0 11 2
truebrain - 13 years ago 2011-12-19 21:05:46
truebrain@openttd.org
(svn r23634) -Add: support language files for GameScript (Rubidium)
13 files changed with 593 insertions and 0 deletions:
0 comments (0 inline, 0 general)
projects/openttd_vs100.vcxproj
Show inline comments
 
@@ -358,6 +358,7 @@
 
    <ClCompile Include="..\src\sprite.cpp" />
 
    <ClCompile Include="..\src\spritecache.cpp" />
 
    <ClCompile Include="..\src\station.cpp" />
 
    <ClCompile Include="..\src\strgen\strgen_base.cpp" />
 
    <ClCompile Include="..\src\string.cpp" />
 
    <ClCompile Include="..\src\strings.cpp" />
 
    <ClCompile Include="..\src\subsidy.cpp" />
 
@@ -560,6 +561,7 @@
 
    <ClInclude Include="..\src\station_type.h" />
 
    <ClInclude Include="..\src\statusbar_gui.h" />
 
    <ClInclude Include="..\src\stdafx.h" />
 
    <ClInclude Include="..\src\strgen\strgen.h" />
 
    <ClInclude Include="..\src\string_func.h" />
 
    <ClInclude Include="..\src\string_type.h" />
 
    <ClInclude Include="..\src\strings_func.h" />
 
@@ -931,6 +933,8 @@
 
    <ClInclude Include="..\src\game\game_instance.hpp" />
 
    <ClCompile Include="..\src\game\game_scanner.cpp" />
 
    <ClInclude Include="..\src\game\game_scanner.hpp" />
 
    <ClCompile Include="..\src\game\game_text.cpp" />
 
    <ClInclude Include="..\src\game\game_text.hpp" />
 
    <ClInclude Include="..\src\script\api\script_accounting.hpp" />
 
    <ClInclude Include="..\src\script\api\script_admin.hpp" />
 
    <ClInclude Include="..\src\script\api\script_airport.hpp" />
projects/openttd_vs100.vcxproj.filters
Show inline comments
 
@@ -303,6 +303,9 @@
 
    <ClCompile Include="..\src\station.cpp">
 
      <Filter>Source Files</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\strgen\strgen_base.cpp">
 
      <Filter>Source Files</Filter>
 
    </ClCompile>
 
    <ClCompile Include="..\src\string.cpp">
 
      <Filter>Source Files</Filter>
 
    </ClCompile>
 
@@ -909,6 +912,9 @@
 
    <ClInclude Include="..\src\stdafx.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\strgen\strgen.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\string_func.h">
 
      <Filter>Header Files</Filter>
 
    </ClInclude>
 
@@ -2022,6 +2028,12 @@
 
    <ClInclude Include="..\src\game\game_scanner.hpp">
 
      <Filter>Game Core</Filter>
 
    </ClInclude>
 
    <ClCompile Include="..\src\game\game_text.cpp">
 
      <Filter>Game Core</Filter>
 
    </ClCompile>
 
    <ClInclude Include="..\src\game\game_text.hpp">
 
      <Filter>Game Core</Filter>
 
    </ClInclude>
 
    <ClInclude Include="..\src\script\api\script_accounting.hpp">
 
      <Filter>Script API</Filter>
 
    </ClInclude>
projects/openttd_vs80.vcproj
Show inline comments
 
@@ -703,6 +703,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\strgen\strgen_base.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\string.cpp"
 
				>
 
			</File>
 
@@ -1515,6 +1519,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\strgen\strgen.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\string_func.h"
 
				>
 
			</File>
 
@@ -3054,6 +3062,14 @@
 
				RelativePath=".\..\src\game\game_scanner.hpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\game\game_text.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\game\game_text.hpp"
 
				>
 
			</File>
 
		</Filter>
 
		<Filter
 
			Name="Script API"
projects/openttd_vs90.vcproj
Show inline comments
 
@@ -700,6 +700,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\strgen\strgen_base.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\string.cpp"
 
				>
 
			</File>
 
@@ -1512,6 +1516,10 @@
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\strgen\strgen.h"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\string_func.h"
 
				>
 
			</File>
 
@@ -3051,6 +3059,14 @@
 
				RelativePath=".\..\src\game\game_scanner.hpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\game\game_text.cpp"
 
				>
 
			</File>
 
			<File
 
				RelativePath=".\..\src\game\game_text.hpp"
 
				>
 
			</File>
 
		</Filter>
 
		<Filter
 
			Name="Script API"
source.list
Show inline comments
 
@@ -68,6 +68,7 @@ sound.cpp
 
sprite.cpp
 
spritecache.cpp
 
station.cpp
 
strgen/strgen_base.cpp
 
string.cpp
 
strings.cpp
 
subsidy.cpp
 
@@ -293,6 +294,7 @@ station_gui.h
 
station_type.h
 
statusbar_gui.h
 
stdafx.h
 
strgen/strgen.h
 
string_func.h
 
string_type.h
 
strings_func.h
 
@@ -707,6 +709,8 @@ game/game_instance.cpp
 
game/game_instance.hpp
 
game/game_scanner.cpp
 
game/game_scanner.hpp
 
game/game_text.cpp
 
game/game_text.hpp
 

	
 
# Script API
 
script/api/script_accounting.hpp
src/core/smallvec_type.hpp
Show inline comments
 
@@ -326,6 +326,37 @@ public:
 
	}
 
};
 

	
 
/**
 
 * Simple vector template class, with automatic delete.
 
 *
 
 * @note There are no asserts in the class so you have
 
 *       to care about that you grab an item which is
 
 *       inside the list.
 
 *
 
 * @param T The type of the items stored, must be a pointer
 
 * @param S The steps of allocation
 
 */
 
template <typename T, uint S>
 
class AutoDeleteSmallVector : public SmallVector<T, S> {
 
public:
 
	~AutoDeleteSmallVector()
 
	{
 
		this->Clear();
 
	}
 

	
 
	/**
 
	 * Remove all items from the list.
 
	 */
 
	FORCEINLINE void Clear()
 
	{
 
		for (uint i = 0; i < this->items; i++) {
 
			delete this->data[i];
 
		}
 

	
 
		this->items = 0;
 
	}
 
};
 

	
 
typedef AutoFreeSmallVector<char*, 4> StringList; ///< Type for a list of strings.
 

	
 
#endif /* SMALLVEC_TYPE_HPP */
src/game/game.hpp
Show inline comments
 
@@ -91,6 +91,11 @@ public:
 
	 */
 
	static class GameInstance *GetInstance() { return Game::instance; }
 

	
 
	/**
 
	 * Get the current active mainscript.
 
	 */
 
	static const char *GetMainScript();
 

	
 
#if defined(ENABLE_NETWORK)
 
	/** Wrapper function for GameScanner::HasGame */
 
	static bool HasGame(const struct ContentInfo *ci, bool md5sum);
src/game/game_core.cpp
Show inline comments
 
@@ -22,6 +22,7 @@
 
#include "game_scanner.hpp"
 
#include "game_config.hpp"
 
#include "game_instance.hpp"
 
#include "game_info.hpp"
 

	
 
/* static */ uint Game::frame_counter = 0;
 
/* static */ GameInfo *Game::info = NULL;
 
@@ -29,6 +30,11 @@
 
/* static */ GameScannerInfo *Game::scanner_info = NULL;
 
/* static */ GameScannerLibrary *Game::scanner_library = NULL;
 

	
 
/* static */ const char *Game::GetMainScript()
 
{
 
		return Game::info->GetMainScript();
 
}
 

	
 
/* static */ void Game::GameLoop()
 
{
 
	if (_networking && !_network_server) return;
src/game/game_instance.cpp
Show inline comments
 
@@ -19,6 +19,7 @@
 
#include "game_config.hpp"
 
#include "game_info.hpp"
 
#include "game_instance.hpp"
 
#include "game_text.hpp"
 
#include "game.hpp"
 

	
 
/* Convert all Game related classes to Squirrel data.
 
@@ -180,6 +181,7 @@ void GameInstance::RegisterAPI()
 
	SQGSWaypointList_Vehicle_Register(this->engine);
 
	SQGSWindow_Register(this->engine);
 

	
 
	RegisterGameTranslation(this->engine);
 
}
 

	
 
int GameInstance::GetSetting(const char *name)
src/game/game_text.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/*
 
 * 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 <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file game_text.cpp Implementation of handling translated strings. */
 

	
 
#include "../stdafx.h"
 
#include "../language.h"
 
#include "../strgen/strgen.h"
 
#include "../debug.h"
 
#include "../fileio_func.h"
 
#include "../script/squirrel_class.hpp"
 
#include "../strings_func.h"
 
#include "game_text.hpp"
 
#include "game.hpp"
 

	
 
#include "table/strings.h"
 

	
 
#include <exception>
 
#include <stdarg.h>
 

	
 
void CDECL strgen_warning(const char *s, ...)
 
{
 
	char buf[1024];
 
	va_list va;
 
	va_start(va, s);
 
	vsnprintf(buf, lengthof(buf), s, va);
 
	va_end(va);
 
	DEBUG(script, 0, "%s:%d: warning: %s", _file, _cur_line, buf);
 
	_warnings++;
 
}
 

	
 
void CDECL strgen_error(const char *s, ...)
 
{
 
	char buf[1024];
 
	va_list va;
 
	va_start(va, s);
 
	vsnprintf(buf, lengthof(buf), s, va);
 
	va_end(va);
 
	DEBUG(script, 0, "%s:%d: error: %s", _file, _cur_line, buf);
 
	_errors++;
 
}
 

	
 
void NORETURN CDECL strgen_fatal(const char *s, ...)
 
{
 
	char buf[1024];
 
	va_list va;
 
	va_start(va, s);
 
	vsnprintf(buf, lengthof(buf), s, va);
 
	va_end(va);
 
	DEBUG(script, 0, "%s:%d: FATAL: %s", _file, _cur_line, buf);
 
	throw std::exception();
 
}
 

	
 
/**
 
 * Create a new container for language strings.
 
 * @param language The language name.
 
 */
 
LanguageStrings::LanguageStrings(const char *language)
 
{
 
	const char *p = strrchr(language, PATHSEPCHAR);
 
	if (p == NULL) {
 
		p = language;
 
	} else {
 
		p++;
 
	}
 

	
 
	const char *e = strchr(p, '.');
 
	this->language = e == NULL ? strdup(p) : strndup(p, e - p);
 
}
 

	
 
/** Free everything. */
 
LanguageStrings::~LanguageStrings()
 
{
 
	free(this->language);
 
}
 

	
 
/**
 
 * Read all the raw language strings from the given file.
 
 * @param file The file to read from.
 
 * @return The raw strings, or NULL upon error.
 
 */
 
LanguageStrings *ReadRawLanguageStrings(const char *file)
 
{
 
	LanguageStrings *ret = NULL;
 
	try {
 
		size_t to_read;
 
		FILE *fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read);
 
		if (fh == NULL) {
 
			return NULL;
 
		}
 

	
 
		ret = new LanguageStrings(file);
 

	
 
		char buffer[2048];
 
		while (to_read != 0 && fgets(buffer, sizeof(buffer), fh) != NULL) {
 
			size_t len = strlen(buffer);
 

	
 
			/* Remove trailing spaces/newlines from the string. */
 
			size_t i = len;
 
			while (i > 0 && (buffer[i - 1] == '\r' || buffer[i - 1] == '\n' || buffer[i - 1] == ' ')) i--;
 
			buffer[i] = '\0';
 

	
 
			*ret->lines.Append() = strndup(buffer, to_read);
 

	
 
			if (len > to_read) {
 
				to_read = 0;
 
			} else {
 
				to_read -= len;
 
			}
 
		}
 

	
 
		return ret;
 
	} catch (...) {
 
		delete ret;
 
		return NULL;
 
	}
 
}
 

	
 

	
 
/** A reader that simply reads using fopen. */
 
struct StringListReader : StringReader {
 
	const char * const *p;   ///< The current location of the iteration.
 
	const char * const *end; ///< The end of the iteration.
 

	
 
	/**
 
	 * Create the reader.
 
	 * @param data        The data to fill during reading.
 
	 * @param file        The file we are reading.
 
	 * @param master      Are we reading the master file?
 
	 * @param translation Are we reading a translation?
 
	 */
 
	StringListReader(StringData &data, const LanguageStrings *strings, bool master, bool translation) :
 
			StringReader(data, strings->language, master, translation), p(strings->lines.Begin()), end(strings->lines.End())
 
	{
 
	}
 

	
 
	/* virtual */ char *ReadLine(char *buffer, size_t size)
 
	{
 
		if (this->p == this->end) return NULL;
 

	
 
		strncpy(buffer, *this->p, size);
 
		this->p++;
 

	
 
		return buffer;
 
	}
 

	
 
	/* virtual */ void HandlePragma(char *str)
 
	{
 
		strgen_fatal("unknown pragma '%s'", str);
 
	}
 
};
 

	
 
/** Class for writing an encoded language. */
 
struct TranslationWriter : LanguageWriter {
 
	StringList *strings; ///< The encoded strings.
 

	
 
	/**
 
	 * Writer for the encoded data.
 
	 * @param strings The string table to add the strings to.
 
	 */
 
	TranslationWriter(StringList *strings) : strings(strings)
 
	{
 
	}
 

	
 
	void WriteHeader(const LanguagePackHeader *header)
 
	{
 
		/* We don't use the header. */
 
	}
 

	
 
	void Finalise()
 
	{
 
		/* Nothing to do. */
 
	}
 

	
 
	void WriteLength(uint length)
 
	{
 
		/* We don't write the length. */
 
	}
 

	
 
	void Write(const byte *buffer, size_t length)
 
	{
 
		*this->strings->Append() = strndup((const char*)buffer, length);
 
	}
 
};
 

	
 
/** Class for writing the string IDs. */
 
struct StringNameWriter : HeaderWriter {
 
	StringList *strings; ///< The string names.
 

	
 
	/**
 
	 * Writer for the string names.
 
	 * @param strings The string table to add the strings to.
 
	 */
 
	StringNameWriter(StringList *strings) : strings(strings)
 
	{
 
	}
 

	
 
	void WriteStringID(const char *name, int stringid)
 
	{
 
		if (stringid == (int)this->strings->Length()) *this->strings->Append() = strdup(name);
 
	}
 

	
 
	void Finalise(const StringData &data)
 
	{
 
		/* Nothing to do. */
 
	}
 
};
 

	
 
static void GetBasePath(char *buffer, size_t length)
 
{
 
	strecpy(buffer, Game::GetMainScript(), buffer + length);
 
	char *s = strrchr(buffer, PATHSEPCHAR);
 
	if (s != NULL) {
 
		/* Keep the PATHSEPCHAR there, remove the rest */
 
		s++;
 
		*s = '\0';
 
	}
 

	
 
	/* Tars dislike opening files with '/' on Windows.. so convert it to '\\' */
 
#if (PATHSEPCHAR != '/')
 
	for (char *n = buffer; *n != '\0'; n++) if (*n == '/') *n = PATHSEPCHAR;
 
#endif
 
}
 

	
 
/**
 
 * Scanner to find language files in a GameScript directory.
 
 */
 
class LanguageScanner : protected FileScanner {
 
private:
 
	GameStrings *gs;
 
	char *exclude;
 

	
 
public:
 
	/** Initialise */
 
	LanguageScanner(GameStrings *gs, const char *exclude) : gs(gs), exclude(strdup(exclude)) {}
 
	~LanguageScanner() { free(exclude); }
 

	
 
	/**
 
	 * Scan.
 
	 */
 
	void Scan(const char *directory)
 
	{
 
		this->FileScanner::Scan(".txt", directory, false);
 
	}
 

	
 
	/* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
 
	{
 
		if (strcmp(filename, exclude) == 0) return true;
 

	
 
		*gs->raw_strings.Append() = ReadRawLanguageStrings(filename);
 
		return true;
 
	}
 
};
 

	
 
/**
 
 * Load all translations that we know of.
 
 * @return Container with all (compiled) translations.
 
 */
 
GameStrings *LoadTranslations()
 
{
 
	GameStrings *gs = new GameStrings();
 
	try {
 
		char filename[512];
 
		GetBasePath(filename, sizeof(filename));
 
		char *e = filename + strlen(filename);
 

	
 
		seprintf(e, filename + sizeof(filename), "lang" PATHSEP "english.txt");
 
		if (!FioCheckFileExists(filename, GAME_DIR)) throw std::exception();
 
		*gs->raw_strings.Append() = ReadRawLanguageStrings(filename);
 

	
 
		/* Scan for other language files */
 
		LanguageScanner scanner(gs, filename);
 
		strecpy(e, "lang" PATHSEP, filename + sizeof(filename));
 
		scanner.Scan(filename);
 

	
 
		gs->Compile();
 
		return gs;
 
	} catch (...) {
 
		delete gs;
 
		return NULL;
 
	}
 
}
 

	
 
/** Compile the language. */
 
void GameStrings::Compile()
 
{
 
	StringData data(1);
 
	StringListReader master_reader(data, this->raw_strings[0], true, false);
 
	master_reader.ParseFile();
 
	if (_errors != 0) throw std::exception();
 

	
 
	this->version = data.Version();
 

	
 
	StringNameWriter id_writer(&this->string_names);
 
	id_writer.WriteHeader(data);
 

	
 
	for (LanguageStrings **p = this->raw_strings.Begin(); p != this->raw_strings.End(); p++) {
 
		data.FreeTranslation();
 
		StringListReader translation_reader(data, *p, false, strcmp((*p)->language, "english") != 0);
 
		translation_reader.ParseFile();
 
		if (_errors != 0) throw std::exception();
 

	
 
		LanguageStrings *compiled = *this->compiled_strings.Append() = new LanguageStrings((*p)->language);
 
		TranslationWriter writer(&compiled->lines);
 
		writer.WriteLang(data);
 
	}
 
}
 

	
 
/** The currently loaded game strings. */
 
GameStrings *_current_data = NULL;
 

	
 
/**
 
 * Get the string pointer of a particular game string.
 
 * @param id The ID of the game string.
 
 * @return The encoded string.
 
 */
 
const char *GetGameStringPtr(uint id)
 
{
 
	if (id >= _current_data->cur_language->lines.Length()) return GetStringPtr(STR_UNDEFINED);
 
	return _current_data->cur_language->lines[id];
 
}
 

	
 
/**
 
 * Register the current translation to the Squirrel engine.
 
 * @param engine The engine to update/
 
 */
 
void RegisterGameTranslation(Squirrel *engine)
 
{
 
	delete _current_data;
 
	_current_data = LoadTranslations();
 
	if (_current_data == NULL) return;
 

	
 
	HSQUIRRELVM vm = engine->GetVM();
 
	sq_pushroottable(vm);
 
	sq_pushstring(vm, _SC("GSText"), -1);
 
	if (SQ_FAILED(sq_get(vm, -2))) return;
 

	
 
	int idx = 0;
 
	for (const char * const *p = _current_data->string_names.Begin(); p != _current_data->string_names.End(); p++, idx++) {
 
		sq_pushstring(vm, OTTD2SQ(*p), -1);
 
		sq_pushinteger(vm, idx);
 
		sq_rawset(vm, -3);
 
	}
 

	
 
	sq_pop(vm, 2);
 

	
 
	ReconsiderGameScriptLanguage();
 
}
 

	
 
/**
 
 * Reconsider the game script language, so we use the right one.
 
 */
 
void ReconsiderGameScriptLanguage()
 
{
 
	if (_current_data == NULL) return;
 

	
 
	char temp[MAX_PATH];
 
	strecpy(temp, _current_language->file, temp + sizeof(temp));
 

	
 
	/* Remove the extension */
 
	char *l = strrchr(temp, '.');
 
	assert(l != NULL);
 
	*l = '\0';
 

	
 
	/* Skip the path */
 
	char *language = strrchr(temp, PATHSEPCHAR);
 
	assert(language != NULL);
 
	language++;
 

	
 
	for (LanguageStrings **p = _current_data->compiled_strings.Begin(); p != _current_data->compiled_strings.End(); p++) {
 
		if (strcmp((*p)->language, language) == 0) {
 
			_current_data->cur_language = *p;
 
			return;
 
		}
 
	}
 

	
 
	_current_data->cur_language = _current_data->compiled_strings[0];
 
}
src/game/game_text.hpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/*
 
 * 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 <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file game_text.hpp Base functions regarding game texts. */
 

	
 
#ifndef GAME_TEXT_HPP
 
#define GAME_TEXT_HPP
 

	
 
#include "../core/smallvec_type.hpp"
 

	
 
/** The tab we place our strings in. */
 
static const uint GAME_TEXT_TAB = 18;
 

	
 
const char *GetGameStringPtr(uint id);
 
void RegisterGameTranslation(class Squirrel *engine);
 
void ReconsiderGameScriptLanguage();
 

	
 
/** Container for the raw (unencoded) language strings of a language. */
 
struct LanguageStrings {
 
	const char *language; ///< Name of the language (base filename).
 
	StringList lines;     ///< The lines of the file to pass into the parser/encoder.
 

	
 
	LanguageStrings(const char *language);
 
	~LanguageStrings();
 
};
 

	
 
/** Container for all the game strings. */
 
struct GameStrings {
 
	uint version;                  ///< The version of the language strings.
 
	LanguageStrings *cur_language; ///< The current (compiled) language.
 

	
 
	AutoDeleteSmallVector<LanguageStrings *, 4> raw_strings;      ///< The raw strings per language, first must be English/the master language!.
 
	AutoDeleteSmallVector<LanguageStrings *, 4> compiled_strings; ///< The compiled strings per language, first must be English/the master language!.
 
	StringList string_names;                                      ///< The names of the compiled strings.
 

	
 
	void Compile();
 
};
 

	
 
#endif /* GAME_TEXT_HPP */
src/saveload/game_sl.cpp
Show inline comments
 
@@ -19,6 +19,7 @@
 
#include "../game/game_config.hpp"
 
#include "../network/network.h"
 
#include "../game/game_instance.hpp"
 
#include "../game/game_text.hpp"
 

	
 
static char _game_saveload_name[64];
 
static int  _game_saveload_version;
 
@@ -111,6 +112,67 @@ static void Save_GSDT()
 
	SlAutolength((AutolengthProc *)SaveReal_GSDT, NULL);
 
}
 

	
 
extern GameStrings *_current_data;
 

	
 
static const char *_game_saveload_string;
 
static uint _game_saveload_strings;
 

	
 
static const SaveLoad _game_language_header[] = {
 
	SLEG_STR(_game_saveload_string, SLE_STR),
 
	SLEG_VAR(_game_saveload_strings, SLE_UINT32),
 
	 SLE_END()
 
};
 

	
 
static const SaveLoad _game_language_string[] = {
 
	SLEG_STR(_game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL),
 
	 SLE_END()
 
};
 

	
 
static void SaveReal_GSTR(LanguageStrings *ls)
 
{
 
	_game_saveload_string  = ls->language;
 
	_game_saveload_strings = ls->lines.Length();
 

	
 
	SlObject(NULL, _game_language_header);
 
	for (uint i = 0; i < _game_saveload_strings; i++) {
 
		_game_saveload_string = ls->lines[i];
 
		SlObject(NULL, _game_language_string);
 
	}
 
}
 

	
 
static void Load_GSTR()
 
{
 
	delete _current_data;
 
	_current_data = new GameStrings();
 

	
 
	while (SlIterateArray() != -1) {
 
		_game_saveload_string = NULL;
 
		SlObject(NULL, _game_language_header);
 

	
 
		LanguageStrings *ls = new LanguageStrings(_game_saveload_string);
 
		for (uint i = 0; i < _game_saveload_strings; i++) {
 
			SlObject(NULL, _game_language_string);
 
			*ls->lines.Append() = strdup(_game_saveload_string);
 
		}
 

	
 
		*_current_data->raw_strings.Append() = ls;
 
	}
 

	
 
	_current_data->Compile();
 
	ReconsiderGameScriptLanguage();
 
}
 

	
 
static void Save_GSTR()
 
{
 
	if (_current_data == NULL) return;
 

	
 
	for (uint i = 0; i < _current_data->raw_strings.Length(); i++) {
 
		SlSetArrayIndex(i);
 
		SlAutolength((AutolengthProc *)SaveReal_GSTR, _current_data->raw_strings[i]);
 
	}
 
}
 

	
 
extern const ChunkHandler _game_chunk_handlers[] = {
 
	{ 'GSTR', Save_GSTR, Load_GSTR, NULL, NULL, CH_ARRAY },
 
	{ 'GSDT', Save_GSDT, Load_GSDT, NULL, NULL, CH_ARRAY | CH_LAST},
 
};
src/strings.cpp
Show inline comments
 
@@ -38,6 +38,7 @@
 
#include "smallmap_gui.h"
 
#include "window_func.h"
 
#include "debug.h"
 
#include "game/game_text.hpp"
 
#include <stack>
 

	
 
#include "table/strings.h"
 
@@ -140,6 +141,7 @@ static bool _keep_gender_data = false;  
 
const char *GetStringPtr(StringID string)
 
{
 
	switch (GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)) {
 
		case GAME_TEXT_TAB: return GetGameStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
 
		/* GetGRFStringPtr doesn't handle 0xD4xx ids, we need to convert those to 0xD0xx. */
 
		case 26: return GetStringPtr(GetGRFStringID(0, 0xD000 + GB(string, TAB_SIZE_OFFSET, 10)));
 
		case 28: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
 
@@ -182,6 +184,9 @@ char *GetStringWithArgs(char *buffr, Str
 
			/* Old table for custom names. This is no longer used */
 
			error("Incorrect conversion of custom name string.");
 

	
 
		case GAME_TEXT_TAB:
 
			return FormatString(buffr, GetGameStringPtr(index), args, last, case_index);
 

	
 
		case 26:
 
			/* Include string within newgrf text (format code 81) */
 
			if (HasBit(index, 10)) {
 
@@ -1611,6 +1616,7 @@ bool ReadLanguagePack(const LanguageMeta
 
#endif /* WITH_ICU */
 

	
 
	/* Some lists need to be sorted again after a language change. */
 
	ReconsiderGameScriptLanguage();
 
	InitializeSortedCargoSpecs();
 
	SortIndustryTypes();
 
	BuildIndustriesLegend();
0 comments (0 inline, 0 general)