mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 06:15:04 +00:00
(svn r23634) -Add: support language files for GameScript (Rubidium)
This commit is contained in:
parent
9b6b2cabc1
commit
2ae87e7213
@ -358,6 +358,7 @@
|
|||||||
<ClCompile Include="..\src\sprite.cpp" />
|
<ClCompile Include="..\src\sprite.cpp" />
|
||||||
<ClCompile Include="..\src\spritecache.cpp" />
|
<ClCompile Include="..\src\spritecache.cpp" />
|
||||||
<ClCompile Include="..\src\station.cpp" />
|
<ClCompile Include="..\src\station.cpp" />
|
||||||
|
<ClCompile Include="..\src\strgen\strgen_base.cpp" />
|
||||||
<ClCompile Include="..\src\string.cpp" />
|
<ClCompile Include="..\src\string.cpp" />
|
||||||
<ClCompile Include="..\src\strings.cpp" />
|
<ClCompile Include="..\src\strings.cpp" />
|
||||||
<ClCompile Include="..\src\subsidy.cpp" />
|
<ClCompile Include="..\src\subsidy.cpp" />
|
||||||
@ -560,6 +561,7 @@
|
|||||||
<ClInclude Include="..\src\station_type.h" />
|
<ClInclude Include="..\src\station_type.h" />
|
||||||
<ClInclude Include="..\src\statusbar_gui.h" />
|
<ClInclude Include="..\src\statusbar_gui.h" />
|
||||||
<ClInclude Include="..\src\stdafx.h" />
|
<ClInclude Include="..\src\stdafx.h" />
|
||||||
|
<ClInclude Include="..\src\strgen\strgen.h" />
|
||||||
<ClInclude Include="..\src\string_func.h" />
|
<ClInclude Include="..\src\string_func.h" />
|
||||||
<ClInclude Include="..\src\string_type.h" />
|
<ClInclude Include="..\src\string_type.h" />
|
||||||
<ClInclude Include="..\src\strings_func.h" />
|
<ClInclude Include="..\src\strings_func.h" />
|
||||||
@ -931,6 +933,8 @@
|
|||||||
<ClInclude Include="..\src\game\game_instance.hpp" />
|
<ClInclude Include="..\src\game\game_instance.hpp" />
|
||||||
<ClCompile Include="..\src\game\game_scanner.cpp" />
|
<ClCompile Include="..\src\game\game_scanner.cpp" />
|
||||||
<ClInclude Include="..\src\game\game_scanner.hpp" />
|
<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_accounting.hpp" />
|
||||||
<ClInclude Include="..\src\script\api\script_admin.hpp" />
|
<ClInclude Include="..\src\script\api\script_admin.hpp" />
|
||||||
<ClInclude Include="..\src\script\api\script_airport.hpp" />
|
<ClInclude Include="..\src\script\api\script_airport.hpp" />
|
||||||
|
@ -303,6 +303,9 @@
|
|||||||
<ClCompile Include="..\src\station.cpp">
|
<ClCompile Include="..\src\station.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\strgen\strgen_base.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\src\string.cpp">
|
<ClCompile Include="..\src\string.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -909,6 +912,9 @@
|
|||||||
<ClInclude Include="..\src\stdafx.h">
|
<ClInclude Include="..\src\stdafx.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\src\strgen\strgen.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\src\string_func.h">
|
<ClInclude Include="..\src\string_func.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@ -2022,6 +2028,12 @@
|
|||||||
<ClInclude Include="..\src\game\game_scanner.hpp">
|
<ClInclude Include="..\src\game\game_scanner.hpp">
|
||||||
<Filter>Game Core</Filter>
|
<Filter>Game Core</Filter>
|
||||||
</ClInclude>
|
</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">
|
<ClInclude Include="..\src\script\api\script_accounting.hpp">
|
||||||
<Filter>Script API</Filter>
|
<Filter>Script API</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -702,6 +702,10 @@
|
|||||||
RelativePath=".\..\src\station.cpp"
|
RelativePath=".\..\src\station.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\strgen\strgen_base.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\..\src\string.cpp"
|
RelativePath=".\..\src\string.cpp"
|
||||||
>
|
>
|
||||||
@ -1514,6 +1518,10 @@
|
|||||||
RelativePath=".\..\src\stdafx.h"
|
RelativePath=".\..\src\stdafx.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\strgen\strgen.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\..\src\string_func.h"
|
RelativePath=".\..\src\string_func.h"
|
||||||
>
|
>
|
||||||
@ -3054,6 +3062,14 @@
|
|||||||
RelativePath=".\..\src\game\game_scanner.hpp"
|
RelativePath=".\..\src\game\game_scanner.hpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\game\game_text.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\game\game_text.hpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Script API"
|
Name="Script API"
|
||||||
|
@ -699,6 +699,10 @@
|
|||||||
RelativePath=".\..\src\station.cpp"
|
RelativePath=".\..\src\station.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\strgen\strgen_base.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\..\src\string.cpp"
|
RelativePath=".\..\src\string.cpp"
|
||||||
>
|
>
|
||||||
@ -1511,6 +1515,10 @@
|
|||||||
RelativePath=".\..\src\stdafx.h"
|
RelativePath=".\..\src\stdafx.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\strgen\strgen.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\..\src\string_func.h"
|
RelativePath=".\..\src\string_func.h"
|
||||||
>
|
>
|
||||||
@ -3051,6 +3059,14 @@
|
|||||||
RelativePath=".\..\src\game\game_scanner.hpp"
|
RelativePath=".\..\src\game\game_scanner.hpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\game\game_text.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\..\src\game\game_text.hpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Script API"
|
Name="Script API"
|
||||||
|
@ -68,6 +68,7 @@ sound.cpp
|
|||||||
sprite.cpp
|
sprite.cpp
|
||||||
spritecache.cpp
|
spritecache.cpp
|
||||||
station.cpp
|
station.cpp
|
||||||
|
strgen/strgen_base.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
strings.cpp
|
strings.cpp
|
||||||
subsidy.cpp
|
subsidy.cpp
|
||||||
@ -293,6 +294,7 @@ station_gui.h
|
|||||||
station_type.h
|
station_type.h
|
||||||
statusbar_gui.h
|
statusbar_gui.h
|
||||||
stdafx.h
|
stdafx.h
|
||||||
|
strgen/strgen.h
|
||||||
string_func.h
|
string_func.h
|
||||||
string_type.h
|
string_type.h
|
||||||
strings_func.h
|
strings_func.h
|
||||||
@ -707,6 +709,8 @@ game/game_instance.cpp
|
|||||||
game/game_instance.hpp
|
game/game_instance.hpp
|
||||||
game/game_scanner.cpp
|
game/game_scanner.cpp
|
||||||
game/game_scanner.hpp
|
game/game_scanner.hpp
|
||||||
|
game/game_text.cpp
|
||||||
|
game/game_text.hpp
|
||||||
|
|
||||||
# Script API
|
# Script API
|
||||||
script/api/script_accounting.hpp
|
script/api/script_accounting.hpp
|
||||||
|
@ -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.
|
typedef AutoFreeSmallVector<char*, 4> StringList; ///< Type for a list of strings.
|
||||||
|
|
||||||
#endif /* SMALLVEC_TYPE_HPP */
|
#endif /* SMALLVEC_TYPE_HPP */
|
||||||
|
@ -91,6 +91,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
static class GameInstance *GetInstance() { return Game::instance; }
|
static class GameInstance *GetInstance() { return Game::instance; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current active mainscript.
|
||||||
|
*/
|
||||||
|
static const char *GetMainScript();
|
||||||
|
|
||||||
#if defined(ENABLE_NETWORK)
|
#if defined(ENABLE_NETWORK)
|
||||||
/** Wrapper function for GameScanner::HasGame */
|
/** Wrapper function for GameScanner::HasGame */
|
||||||
static bool HasGame(const struct ContentInfo *ci, bool md5sum);
|
static bool HasGame(const struct ContentInfo *ci, bool md5sum);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "game_scanner.hpp"
|
#include "game_scanner.hpp"
|
||||||
#include "game_config.hpp"
|
#include "game_config.hpp"
|
||||||
#include "game_instance.hpp"
|
#include "game_instance.hpp"
|
||||||
|
#include "game_info.hpp"
|
||||||
|
|
||||||
/* static */ uint Game::frame_counter = 0;
|
/* static */ uint Game::frame_counter = 0;
|
||||||
/* static */ GameInfo *Game::info = NULL;
|
/* static */ GameInfo *Game::info = NULL;
|
||||||
@ -29,6 +30,11 @@
|
|||||||
/* static */ GameScannerInfo *Game::scanner_info = NULL;
|
/* static */ GameScannerInfo *Game::scanner_info = NULL;
|
||||||
/* static */ GameScannerLibrary *Game::scanner_library = NULL;
|
/* static */ GameScannerLibrary *Game::scanner_library = NULL;
|
||||||
|
|
||||||
|
/* static */ const char *Game::GetMainScript()
|
||||||
|
{
|
||||||
|
return Game::info->GetMainScript();
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ void Game::GameLoop()
|
/* static */ void Game::GameLoop()
|
||||||
{
|
{
|
||||||
if (_networking && !_network_server) return;
|
if (_networking && !_network_server) return;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "game_config.hpp"
|
#include "game_config.hpp"
|
||||||
#include "game_info.hpp"
|
#include "game_info.hpp"
|
||||||
#include "game_instance.hpp"
|
#include "game_instance.hpp"
|
||||||
|
#include "game_text.hpp"
|
||||||
#include "game.hpp"
|
#include "game.hpp"
|
||||||
|
|
||||||
/* Convert all Game related classes to Squirrel data.
|
/* Convert all Game related classes to Squirrel data.
|
||||||
@ -180,6 +181,7 @@ void GameInstance::RegisterAPI()
|
|||||||
SQGSWaypointList_Vehicle_Register(this->engine);
|
SQGSWaypointList_Vehicle_Register(this->engine);
|
||||||
SQGSWindow_Register(this->engine);
|
SQGSWindow_Register(this->engine);
|
||||||
|
|
||||||
|
RegisterGameTranslation(this->engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GameInstance::GetSetting(const char *name)
|
int GameInstance::GetSetting(const char *name)
|
||||||
|
384
src/game/game_text.cpp
Normal file
384
src/game/game_text.cpp
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
/* $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];
|
||||||
|
}
|
45
src/game/game_text.hpp
Normal file
45
src/game/game_text.hpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/* $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 */
|
@ -19,6 +19,7 @@
|
|||||||
#include "../game/game_config.hpp"
|
#include "../game/game_config.hpp"
|
||||||
#include "../network/network.h"
|
#include "../network/network.h"
|
||||||
#include "../game/game_instance.hpp"
|
#include "../game/game_instance.hpp"
|
||||||
|
#include "../game/game_text.hpp"
|
||||||
|
|
||||||
static char _game_saveload_name[64];
|
static char _game_saveload_name[64];
|
||||||
static int _game_saveload_version;
|
static int _game_saveload_version;
|
||||||
@ -111,6 +112,67 @@ static void Save_GSDT()
|
|||||||
SlAutolength((AutolengthProc *)SaveReal_GSDT, NULL);
|
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[] = {
|
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},
|
{ 'GSDT', Save_GSDT, Load_GSDT, NULL, NULL, CH_ARRAY | CH_LAST},
|
||||||
};
|
};
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include "smallmap_gui.h"
|
#include "smallmap_gui.h"
|
||||||
#include "window_func.h"
|
#include "window_func.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "game/game_text.hpp"
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
@ -140,6 +141,7 @@ static bool _keep_gender_data = false; ///< Should we retain the gender data in
|
|||||||
const char *GetStringPtr(StringID string)
|
const char *GetStringPtr(StringID string)
|
||||||
{
|
{
|
||||||
switch (GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)) {
|
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. */
|
/* 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 26: return GetStringPtr(GetGRFStringID(0, 0xD000 + GB(string, TAB_SIZE_OFFSET, 10)));
|
||||||
case 28: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
|
case 28: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS));
|
||||||
@ -182,6 +184,9 @@ char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, co
|
|||||||
/* Old table for custom names. This is no longer used */
|
/* Old table for custom names. This is no longer used */
|
||||||
error("Incorrect conversion of custom name string.");
|
error("Incorrect conversion of custom name string.");
|
||||||
|
|
||||||
|
case GAME_TEXT_TAB:
|
||||||
|
return FormatString(buffr, GetGameStringPtr(index), args, last, case_index);
|
||||||
|
|
||||||
case 26:
|
case 26:
|
||||||
/* Include string within newgrf text (format code 81) */
|
/* Include string within newgrf text (format code 81) */
|
||||||
if (HasBit(index, 10)) {
|
if (HasBit(index, 10)) {
|
||||||
@ -1611,6 +1616,7 @@ bool ReadLanguagePack(const LanguageMetadata *lang)
|
|||||||
#endif /* WITH_ICU */
|
#endif /* WITH_ICU */
|
||||||
|
|
||||||
/* Some lists need to be sorted again after a language change. */
|
/* Some lists need to be sorted again after a language change. */
|
||||||
|
ReconsiderGameScriptLanguage();
|
||||||
InitializeSortedCargoSpecs();
|
InitializeSortedCargoSpecs();
|
||||||
SortIndustryTypes();
|
SortIndustryTypes();
|
||||||
BuildIndustriesLegend();
|
BuildIndustriesLegend();
|
||||||
|
Loading…
Reference in New Issue
Block a user