2005-07-24 14:12:37 +00:00
/* $Id$ */
2009-08-21 20:21:05 +00:00
/*
* 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/>.
*/
2008-05-06 15:11:33 +00:00
/** @file strings.cpp Handling of translated strings. */
2007-04-04 01:35:16 +00:00
2004-08-09 17:04:08 +00:00
# include "stdafx.h"
2005-08-06 14:59:54 +00:00
# include "currency.h"
2008-03-31 00:06:17 +00:00
# include "station_base.h"
2004-08-09 17:04:08 +00:00
# include "town.h"
2009-07-22 10:18:19 +00:00
# include "waypoint_base.h"
2010-05-12 18:19:36 +00:00
# include "depot_base.h"
2005-07-15 18:30:13 +00:00
# include "industry.h"
2006-04-21 03:00:20 +00:00
# include "newgrf_text.h"
2008-08-31 10:50:05 +00:00
# include "fileio_func.h"
2008-03-31 07:25:49 +00:00
# include "signs_base.h"
2013-06-23 15:20:23 +00:00
# include "fontdetection.h"
2011-12-10 13:54:10 +00:00
# include "error.h"
2007-12-21 19:49:27 +00:00
# include "strings_func.h"
2008-05-04 21:53:36 +00:00
# include "rev.h"
2007-12-22 21:01:49 +00:00
# include "core/endian_func.hpp"
2007-12-26 13:50:40 +00:00
# include "date_func.h"
2007-12-27 13:35:39 +00:00
# include "vehicle_base.h"
2008-04-29 21:31:29 +00:00
# include "engine_base.h"
2010-11-13 11:11:02 +00:00
# include "language.h"
2009-09-22 13:54:54 +00:00
# include "townname_func.h"
2010-01-15 16:41:15 +00:00
# include "string_func.h"
# include "company_base.h"
2010-03-28 12:25:09 +00:00
# include "smallmap_gui.h"
2010-11-27 22:43:58 +00:00
# include "window_func.h"
2010-11-10 17:48:31 +00:00
# include "debug.h"
2011-12-19 21:05:46 +00:00
# include "game/game_text.hpp"
2011-01-21 23:10:02 +00:00
# include <stack>
2004-08-09 17:04:08 +00:00
2008-01-13 01:21:35 +00:00
# include "table/strings.h"
# include "table/control_codes.h"
2006-08-04 23:45:20 +00:00
2014-04-23 20:13:33 +00:00
# include "safeguards.h"
2010-11-13 11:28:55 +00:00
char _config_language_file [ MAX_PATH ] ; ///< The file (name) stored in the configuration.
2010-11-13 12:09:30 +00:00
LanguageList _languages ; ///< The actual list of language meta data.
2010-11-13 11:25:58 +00:00
const LanguageMetadata * _current_language = NULL ; ///< The currently loaded language.
2010-11-13 11:28:55 +00:00
TextDirection _current_text_dir ; ///< Text direction of the currently selected language.
2005-07-26 19:04:19 +00:00
2010-11-27 22:47:29 +00:00
# ifdef WITH_ICU
Collator * _current_collator = NULL ; ///< Collator for the language currently in use.
# endif /* WITH_ICU */
2011-03-18 13:34:52 +00:00
static uint64 _global_string_params_data [ 20 ] ; ///< Global array of string parameters. To access, use #SetDParam.
static WChar _global_string_params_type [ 20 ] ; ///< Type of parameters stored in #_decode_parameters
StringParameters _global_string_params ( _global_string_params_data , 20 , _global_string_params_type ) ;
2004-08-09 17:04:08 +00:00
2011-03-18 13:34:52 +00:00
/** Reset the type array. */
void StringParameters : : ClearTypeInformation ( )
{
assert ( this - > type ! = NULL ) ;
MemSetT ( this - > type , 0 , this - > num_param ) ;
}
2004-08-09 17:04:08 +00:00
2012-10-14 15:18:09 +00:00
/**
* Read an int64 from the argument array . The offset is increased
* so the next time GetInt64 is called the next value is read .
*/
int64 StringParameters : : GetInt64 ( WChar type )
{
if ( this - > offset > = this - > num_param ) {
DEBUG ( misc , 0 , " Trying to read invalid string parameter " ) ;
return 0 ;
}
if ( this - > type ! = NULL ) {
assert ( this - > type [ this - > offset ] = = 0 | | this - > type [ this - > offset ] = = type ) ;
this - > type [ this - > offset ] = type ;
}
return this - > data [ this - > offset + + ] ;
}
2010-12-09 21:41:31 +00:00
/**
2011-03-18 13:34:52 +00:00
* Shift all data in the data array by the given amount to make
* room for some extra parameters .
2010-12-09 21:41:31 +00:00
*/
2011-03-18 13:34:52 +00:00
void StringParameters : : ShiftParameters ( uint amount )
2005-07-15 14:53:44 +00:00
{
2011-03-18 13:34:52 +00:00
assert ( amount < = this - > num_param ) ;
MemMoveT ( this - > data + amount , this - > data , this - > num_param - amount ) ;
2005-07-15 14:53:44 +00:00
}
2012-12-08 17:18:51 +00:00
/**
* Set DParam n to some number that is suitable for string size computations .
* @ param n Index of the string parameter .
* @ param max_value The biggest value which shall be displayed .
* For the result only the number of digits of \ a max_value matter .
2013-01-08 22:46:42 +00:00
* @ param min_count Minimum number of digits independent of \ a max .
2013-06-01 14:33:48 +00:00
* @ param size Font of the number
2012-12-08 17:18:51 +00:00
*/
2013-06-01 14:33:48 +00:00
void SetDParamMaxValue ( uint n , uint64 max_value , uint min_count , FontSize size )
2012-12-08 17:18:51 +00:00
{
uint num_digits = 1 ;
while ( max_value > = 10 ) {
num_digits + + ;
max_value / = 10 ;
}
2013-06-01 14:33:48 +00:00
SetDParamMaxDigits ( n , max ( min_count , num_digits ) , size ) ;
2012-12-08 17:18:51 +00:00
}
/**
* Set DParam n to some number that is suitable for string size computations .
* @ param n Index of the string parameter .
* @ param count Number of digits which shall be displayable .
2013-06-01 14:33:48 +00:00
* @ param size Font of the number
2012-12-08 17:18:51 +00:00
*/
2013-06-01 14:33:48 +00:00
void SetDParamMaxDigits ( uint n , uint count , FontSize size )
2012-12-08 17:18:51 +00:00
{
2013-06-01 15:10:32 +00:00
uint front , next ;
GetBroadestDigit ( & front , & next , size ) ;
uint64 val = count > 1 ? front : next ;
2012-12-08 17:18:51 +00:00
for ( ; count > 1 ; count - - ) {
2013-06-01 15:10:32 +00:00
val = 10 * val + next ;
2012-12-08 17:18:51 +00:00
}
SetDParam ( n , val ) ;
}
2011-03-18 13:34:52 +00:00
/**
* Copy \ a num string parameters from array \ a src into the global string parameter array .
* @ param offs Index in the global array to copy the first string parameter to .
* @ param src Source array of string parameters .
* @ param num Number of string parameters to copy .
*/
void CopyInDParam ( int offs , const uint64 * src , int num )
2005-07-15 14:53:44 +00:00
{
2011-03-18 13:34:52 +00:00
MemCpyT ( _global_string_params . GetPointerToOffset ( offs ) , src , num ) ;
2005-07-15 14:53:44 +00:00
}
2010-12-09 21:41:31 +00:00
/**
2011-03-18 13:34:52 +00:00
* Copy \ a num string parameters from the global string parameter array to the \ a dst array .
* @ param dst Destination array of string parameters .
* @ param offs Index in the global array to copy the first string parameter from .
* @ param num Number of string parameters to copy .
2010-12-09 21:41:31 +00:00
*/
2011-03-18 13:34:52 +00:00
void CopyOutDParam ( uint64 * dst , int offs , int num )
2005-07-15 14:53:44 +00:00
{
2011-03-18 13:34:52 +00:00
MemCpyT ( dst , _global_string_params . GetPointerToOffset ( offs ) , num ) ;
2005-07-15 14:53:44 +00:00
}
2011-12-10 16:03:12 +00:00
/**
* Copy \ a num string parameters from the global string parameter array to the \ a dst array .
* Furthermore clone raw string parameters into \ a strings and amend the data in \ a dst .
* @ param dst Destination array of string parameters .
* @ param strings Destination array for clone of the raw strings . Must be of same length as dst . Deallocation left to the caller .
* @ param string The string used to determine where raw strings are and where there are no raw strings .
* @ param num Number of string parameters to copy .
*/
void CopyOutDParam ( uint64 * dst , const char * * strings , StringID string , int num )
{
char buf [ DRAW_STRING_BUFFER ] ;
GetString ( buf , string , lastof ( buf ) ) ;
MemCpyT ( dst , _global_string_params . GetPointerToOffset ( 0 ) , num ) ;
for ( int i = 0 ; i < num ; i + + ) {
if ( _global_string_params . HasTypeInformation ( ) & & _global_string_params . GetTypeAtOffset ( i ) = = SCC_RAW_STRING_POINTER ) {
2014-04-25 15:40:32 +00:00
strings [ i ] = stredup ( ( const char * ) ( size_t ) _global_string_params . GetParam ( i ) ) ;
2011-12-10 16:03:12 +00:00
dst [ i ] = ( size_t ) strings [ i ] ;
} else {
strings [ i ] = NULL ;
}
}
}
2011-03-18 13:34:52 +00:00
static char * StationGetSpecialString ( char * buff , int x , const char * last ) ;
static char * GetSpecialTownNameString ( char * buff , int ind , uint32 seed , const char * last ) ;
static char * GetSpecialNameString ( char * buff , int ind , StringParameters * args , const char * last ) ;
2011-12-20 22:11:22 +00:00
static char * FormatString ( char * buff , const char * str , StringParameters * args , const char * last , uint case_index = 0 , bool game_script = false , bool dry_run = false ) ;
2011-03-18 13:34:52 +00:00
struct LanguagePack : public LanguagePackHeader {
char data [ ] ; // list of strings
} ;
static char * * _langpack_offs ;
static LanguagePack * _langpack ;
2011-12-17 23:16:16 +00:00
static uint _langtab_num [ TAB_COUNT ] ; ///< Offset into langpack offs
static uint _langtab_start [ TAB_COUNT ] ; ///< Offset into langpack offs
2012-09-12 18:50:44 +00:00
static bool _scan_for_gender_data = false ; ///< Are we scanning for the gender of the current string? (instead of formatting it)
2011-03-18 13:34:52 +00:00
2005-07-15 14:53:44 +00:00
2008-01-29 17:09:00 +00:00
const char * GetStringPtr ( StringID string )
2004-08-09 17:04:08 +00:00
{
2011-12-17 23:16:16 +00:00
switch ( GB ( string , TAB_COUNT_OFFSET , TAB_COUNT_BITS ) ) {
2011-12-19 21:05:46 +00:00
case GAME_TEXT_TAB : return GetGameStringPtr ( GB ( string , TAB_SIZE_OFFSET , TAB_SIZE_BITS ) ) ;
2014-01-12 18:00:55 +00:00
/* 0xD0xx and 0xD4xx IDs have been converted earlier. */
case 26 : NOT_REACHED ( ) ;
2011-12-17 23:16:16 +00:00
case 28 : return GetGRFStringPtr ( GB ( string , TAB_SIZE_OFFSET , TAB_SIZE_BITS ) ) ;
case 29 : return GetGRFStringPtr ( GB ( string , TAB_SIZE_OFFSET , TAB_SIZE_BITS ) + 0x0800 ) ;
case 30 : return GetGRFStringPtr ( GB ( string , TAB_SIZE_OFFSET , TAB_SIZE_BITS ) + 0x1000 ) ;
default : return _langpack_offs [ _langtab_start [ GB ( string , TAB_COUNT_OFFSET , TAB_COUNT_BITS ) ] + GB ( string , TAB_SIZE_OFFSET , TAB_SIZE_BITS ) ] ;
2008-01-29 17:09:00 +00:00
}
2004-08-09 17:04:08 +00:00
}
2010-08-01 19:22:34 +00:00
/**
2011-10-20 16:51:54 +00:00
* Get a parsed string with most special stringcodes replaced by the string parameters .
2010-12-09 21:41:31 +00:00
* @ param buffr Pointer to a string buffer where the formatted string should be written to .
2007-04-04 01:35:16 +00:00
* @ param string
2011-03-18 13:34:52 +00:00
* @ param args Arguments for the string .
2013-01-08 22:46:42 +00:00
* @ param last Pointer just past the end of \ a buffr .
2011-10-20 16:51:54 +00:00
* @ param case_index The " case index " . This will only be set when FormatString wants to print the string in a different case .
2011-12-20 22:11:22 +00:00
* @ param game_script The string is coming directly from a game script .
2010-12-09 21:41:31 +00:00
* @ return Pointer to the final zero byte of the formatted string .
2007-04-04 01:35:16 +00:00
*/
2011-12-20 22:11:22 +00:00
char * GetStringWithArgs ( char * buffr , StringID string , StringParameters * args , const char * last , uint case_index , bool game_script )
2004-08-09 17:04:08 +00:00
{
2011-10-20 16:51:54 +00:00
if ( string = = 0 ) return GetStringWithArgs ( buffr , STR_UNDEFINED , args , last ) ;
2007-10-30 18:32:26 +00:00
2011-12-17 23:16:16 +00:00
uint index = GB ( string , TAB_SIZE_OFFSET , TAB_SIZE_BITS ) ;
uint tab = GB ( string , TAB_COUNT_OFFSET , TAB_COUNT_BITS ) ;
2004-08-09 17:04:08 +00:00
2005-02-06 16:56:04 +00:00
switch ( tab ) {
case 4 :
2011-12-20 22:11:22 +00:00
if ( index > = 0xC0 & & ! game_script ) {
2011-03-18 13:34:52 +00:00
return GetSpecialTownNameString ( buffr , index - 0xC0 , args - > GetInt32 ( ) , last ) ;
2010-07-24 10:14:39 +00:00
}
2005-02-06 16:56:04 +00:00
break ;
2004-08-09 17:04:08 +00:00
2005-02-06 16:56:04 +00:00
case 14 :
2011-12-20 22:11:22 +00:00
if ( index > = 0xE4 & & ! game_script ) {
2011-03-18 13:34:52 +00:00
return GetSpecialNameString ( buffr , index - 0xE4 , args , last ) ;
2010-07-24 10:14:39 +00:00
}
2005-02-06 16:56:04 +00:00
break ;
2004-08-09 17:04:08 +00:00
2005-02-06 16:56:04 +00:00
case 15 :
2008-01-29 17:09:00 +00:00
/* Old table for custom names. This is no longer used */
2013-11-16 09:54:22 +00:00
if ( ! game_script ) {
error ( " Incorrect conversion of custom name string. " ) ;
}
break ;
2004-08-09 17:04:08 +00:00
2011-12-19 21:05:46 +00:00
case GAME_TEXT_TAB :
2011-12-20 22:11:22 +00:00
return FormatString ( buffr , GetGameStringPtr ( index ) , args , last , case_index , true ) ;
2011-12-19 21:05:46 +00:00
2006-10-03 09:25:42 +00:00
case 26 :
2014-01-12 18:00:55 +00:00
NOT_REACHED ( ) ;
2006-10-03 09:25:42 +00:00
2006-04-21 03:00:20 +00:00
case 28 :
2011-10-20 16:53:34 +00:00
return FormatString ( buffr , GetGRFStringPtr ( index ) , args , last , case_index ) ;
2006-04-21 03:00:20 +00:00
case 29 :
2011-10-20 16:53:34 +00:00
return FormatString ( buffr , GetGRFStringPtr ( index + 0x0800 ) , args , last , case_index ) ;
2006-04-21 03:00:20 +00:00
case 30 :
2011-10-20 16:53:34 +00:00
return FormatString ( buffr , GetGRFStringPtr ( index + 0x1000 ) , args , last , case_index ) ;
2004-08-09 17:04:08 +00:00
}
2005-11-14 19:48:04 +00:00
if ( index > = _langtab_num [ tab ] ) {
2011-12-20 22:11:22 +00:00
if ( game_script ) {
return GetStringWithArgs ( buffr , STR_UNDEFINED , args , last ) ;
}
2009-07-24 09:14:36 +00:00
error ( " String 0x%X is invalid. You are probably using an old version of the .lng file. \n " , string ) ;
2005-11-14 19:48:04 +00:00
}
2004-08-09 17:04:08 +00:00
2011-10-20 16:53:34 +00:00
return FormatString ( buffr , GetStringPtr ( string ) , args , last , case_index ) ;
2005-07-15 14:53:44 +00:00
}
2008-11-24 20:51:55 +00:00
char * GetString ( char * buffr , StringID string , const char * last )
2005-07-15 14:53:44 +00:00
{
2011-03-18 13:34:52 +00:00
_global_string_params . ClearTypeInformation ( ) ;
_global_string_params . offset = 0 ;
return GetStringWithArgs ( buffr , string , & _global_string_params , last ) ;
2004-08-09 17:04:08 +00:00
}
2005-07-15 14:53:44 +00:00
2010-08-01 19:22:34 +00:00
/**
* This function is used to " bind " a C string to a OpenTTD dparam slot .
2007-04-04 01:35:16 +00:00
* @ param n slot of the string
* @ param str string to bind
*/
2005-07-14 09:43:59 +00:00
void SetDParamStr ( uint n , const char * str )
{
2008-07-31 22:55:12 +00:00
SetDParam ( n , ( uint64 ) ( size_t ) str ) ;
2005-07-14 09:43:59 +00:00
}
2009-07-25 07:49:49 +00:00
/**
* Shift the string parameters in the global string parameter array by \ a amount positions , making room at the beginning .
* @ param amount Number of positions to shift .
*/
2008-09-28 13:50:11 +00:00
void InjectDParam ( uint amount )
2004-08-09 17:04:08 +00:00
{
2011-03-18 13:34:52 +00:00
_global_string_params . ShiftParameters ( amount ) ;
2004-08-09 17:04:08 +00:00
}
2011-04-09 20:12:45 +00:00
/**
* Format a number into a string .
* @ param buff the buffer to write to
* @ param number the number to write down
* @ param last the last element in the buffer
* @ param separator the thousands - separator to use
2011-04-09 20:26:14 +00:00
* @ param zerofill minimum number of digits to print for the integer part . The number will be filled with zeros at the front if necessary .
* @ param fractional_digits number of fractional digits to display after a decimal separator . The decimal separator is inserted
* in front of the \ a fractional_digits last digit of \ a number .
2011-04-09 20:12:45 +00:00
* @ return till where we wrote
*/
2011-04-09 20:26:14 +00:00
static char * FormatNumber ( char * buff , int64 number , const char * last , const char * separator , int zerofill = 1 , int fractional_digits = 0 )
2004-08-09 17:04:08 +00:00
{
2011-04-09 20:12:45 +00:00
static const int max_digits = 20 ;
2007-07-29 12:13:22 +00:00
uint64 divisor = 10000000000000000000ULL ;
2011-04-09 20:26:14 +00:00
zerofill + = fractional_digits ;
int thousands_offset = ( max_digits - fractional_digits - 1 ) % 3 ;
2004-08-09 17:04:08 +00:00
if ( number < 0 ) {
2009-08-06 20:21:53 +00:00
buff + = seprintf ( buff , last , " - " ) ;
2004-08-09 17:04:08 +00:00
number = - number ;
}
2009-11-19 13:53:54 +00:00
uint64 num = number ;
uint64 tot = 0 ;
2011-04-09 20:12:45 +00:00
for ( int i = 0 ; i < max_digits ; i + + ) {
2011-04-09 20:26:14 +00:00
if ( i = = max_digits - fractional_digits ) {
const char * decimal_separator = _settings_game . locale . digit_decimal_separator ;
if ( decimal_separator = = NULL ) decimal_separator = _langpack - > digit_decimal_separator ;
buff + = seprintf ( buff , last , " %s " , decimal_separator ) ;
}
2009-11-19 13:53:54 +00:00
uint64 quot = 0 ;
2007-07-29 12:13:22 +00:00
if ( num > = divisor ) {
quot = num / divisor ;
num = num % divisor ;
2004-08-09 17:04:08 +00:00
}
2012-02-12 21:17:32 +00:00
if ( ( tot | = quot ) | | i > = max_digits - zerofill ) {
2009-04-30 12:11:51 +00:00
buff + = seprintf ( buff , last , " %i " , ( int ) quot ) ;
2011-04-17 17:17:09 +00:00
if ( ( i % 3 ) = = thousands_offset & & i < max_digits - 1 - fractional_digits ) buff = strecpy ( buff , separator , last ) ;
2004-08-09 17:04:08 +00:00
}
2007-07-29 12:13:22 +00:00
divisor / = 10 ;
2004-08-09 17:04:08 +00:00
}
2005-02-06 11:23:41 +00:00
* buff = ' \0 ' ;
2004-08-09 17:04:08 +00:00
return buff ;
}
2011-04-09 20:26:14 +00:00
static char * FormatCommaNumber ( char * buff , int64 number , const char * last , int fractional_digits = 0 )
2004-08-09 17:04:08 +00:00
{
2009-04-23 21:05:00 +00:00
const char * separator = _settings_game . locale . digit_group_separator ;
if ( separator = = NULL ) separator = _langpack - > digit_group_separator ;
2011-04-09 20:26:14 +00:00
return FormatNumber ( buff , number , last , separator , 1 , fractional_digits ) ;
2009-04-23 16:17:10 +00:00
}
2004-08-09 17:04:08 +00:00
2009-04-23 16:17:10 +00:00
static char * FormatNoCommaNumber ( char * buff , int64 number , const char * last )
{
return FormatNumber ( buff , number , last , " " ) ;
2004-08-09 17:04:08 +00:00
}
2009-11-19 13:53:54 +00:00
static char * FormatZerofillNumber ( char * buff , int64 number , int64 count , const char * last )
{
2011-04-09 20:12:45 +00:00
return FormatNumber ( buff , number , last , " " , count ) ;
2009-11-19 13:53:54 +00:00
}
2010-04-06 23:45:10 +00:00
static char * FormatHexNumber ( char * buff , uint64 number , const char * last )
2008-09-14 14:31:37 +00:00
{
2010-04-06 23:45:10 +00:00
return buff + seprintf ( buff , last , " 0x " OTTD_PRINTFHEX64 , number ) ;
2008-09-14 14:31:37 +00:00
}
2004-08-09 17:04:08 +00:00
2009-01-16 12:59:47 +00:00
/**
* Format a given number as a number of bytes with the SI prefix .
* @ param buff the buffer to write to
* @ param number the number of bytes to write down
* @ param last the last element in the buffer
* @ return till where we wrote
*/
static char * FormatBytes ( char * buff , int64 number , const char * last )
{
assert ( number > = 0 ) ;
2011-03-22 22:13:20 +00:00
/* 1 2^10 2^20 2^30 2^40 2^50 2^60 */
const char * const iec_prefixes [ ] = { " " , " Ki " , " Mi " , " Gi " , " Ti " , " Pi " , " Ei " } ;
2009-01-16 14:02:40 +00:00
uint id = 1 ;
2009-01-16 12:59:47 +00:00
while ( number > = 1024 * 1024 ) {
number / = 1024 ;
id + + ;
}
2009-08-12 01:28:11 +00:00
const char * decimal_separator = _settings_game . locale . digit_decimal_separator ;
if ( decimal_separator = = NULL ) decimal_separator = _langpack - > digit_decimal_separator ;
2009-01-16 12:59:47 +00:00
if ( number < 1024 ) {
id = 0 ;
buff + = seprintf ( buff , last , " %i " , ( int ) number ) ;
} else if ( number < 1024 * 10 ) {
2009-08-12 01:28:11 +00:00
buff + = seprintf ( buff , last , " %i%s%02i " , ( int ) number / 1024 , decimal_separator , ( int ) ( number % 1024 ) * 100 / 1024 ) ;
2009-01-16 12:59:47 +00:00
} else if ( number < 1024 * 100 ) {
2009-08-12 01:28:11 +00:00
buff + = seprintf ( buff , last , " %i%s%01i " , ( int ) number / 1024 , decimal_separator , ( int ) ( number % 1024 ) * 10 / 1024 ) ;
2009-01-16 12:59:47 +00:00
} else {
assert ( number < 1024 * 1024 ) ;
buff + = seprintf ( buff , last , " %i " , ( int ) number / 1024 ) ;
}
2009-08-05 16:14:40 +00:00
assert ( id < lengthof ( iec_prefixes ) ) ;
2014-08-15 20:14:48 +00:00
buff + = seprintf ( buff , last , NBSP " %sB " , iec_prefixes [ id ] ) ;
2009-01-16 12:59:47 +00:00
return buff ;
}
2011-10-20 16:53:34 +00:00
static char * FormatYmdString ( char * buff , Date date , const char * last , uint case_index )
2004-08-09 17:04:08 +00:00
{
YearMonthDay ymd ;
2006-08-15 16:55:40 +00:00
ConvertDateToYMD ( date , & ymd ) ;
2004-08-09 17:04:08 +00:00
2014-06-20 20:57:32 +00:00
int64 args [ ] = { ymd . day + STR_DAY_NUMBER_1ST - 1 , STR_MONTH_ABBREV_JAN + ymd . month , ymd . year } ;
2011-03-18 13:34:52 +00:00
StringParameters tmp_params ( args ) ;
2011-10-20 16:53:34 +00:00
return FormatString ( buff , GetStringPtr ( STR_FORMAT_DATE_LONG ) , & tmp_params , last , case_index ) ;
2004-08-09 17:04:08 +00:00
}
2011-10-20 16:53:34 +00:00
static char * FormatMonthAndYear ( char * buff , Date date , const char * last , uint case_index )
2004-08-09 17:04:08 +00:00
{
YearMonthDay ymd ;
2006-08-15 16:55:40 +00:00
ConvertDateToYMD ( date , & ymd ) ;
2004-08-09 17:04:08 +00:00
2011-03-22 22:13:20 +00:00
int64 args [ ] = { STR_MONTH_JAN + ymd . month , ymd . year } ;
2011-03-18 13:34:52 +00:00
StringParameters tmp_params ( args ) ;
2011-10-20 16:53:34 +00:00
return FormatString ( buff , GetStringPtr ( STR_FORMAT_DATE_SHORT ) , & tmp_params , last , case_index ) ;
2004-08-09 17:04:08 +00:00
}
2009-01-03 00:56:16 +00:00
static char * FormatTinyOrISODate ( char * buff , Date date , StringID str , const char * last )
2005-01-22 23:13:20 +00:00
{
YearMonthDay ymd ;
2006-08-15 16:55:40 +00:00
ConvertDateToYMD ( date , & ymd ) ;
2005-01-22 23:13:20 +00:00
2007-02-26 00:36:57 +00:00
char day [ 3 ] ;
char month [ 3 ] ;
/* We want to zero-pad the days and months */
2014-04-23 21:12:09 +00:00
seprintf ( day , lastof ( day ) , " %02i " , ymd . day ) ;
seprintf ( month , lastof ( month ) , " %02i " , ymd . month + 1 ) ;
2007-02-26 00:36:57 +00:00
2011-03-22 22:13:20 +00:00
int64 args [ ] = { ( int64 ) ( size_t ) day , ( int64 ) ( size_t ) month , ymd . year } ;
2011-03-18 13:34:52 +00:00
StringParameters tmp_params ( args ) ;
2011-10-20 16:53:34 +00:00
return FormatString ( buff , GetStringPtr ( str ) , & tmp_params , last ) ;
2005-01-22 23:13:20 +00:00
}
2008-11-24 20:51:55 +00:00
static char * FormatGenericCurrency ( char * buff , const CurrencySpec * spec , Money number , bool compact , const char * last )
2004-08-09 17:04:08 +00:00
{
2007-10-20 14:51:09 +00:00
/* We are going to make number absolute for printing, so
* keep this piece of data as we need it later on */
bool negative = number < 0 ;
const char * multiplier = " " ;
2004-08-09 17:04:08 +00:00
2007-10-20 14:51:09 +00:00
number * = spec - > rate ;
2004-08-09 17:04:08 +00:00
2007-04-04 01:35:16 +00:00
/* convert from negative */
2005-02-06 11:23:41 +00:00
if ( number < 0 ) {
2007-08-07 15:20:31 +00:00
if ( buff + Utf8CharLen ( SCC_RED ) > last ) return buff ;
buff + = Utf8Encode ( buff , SCC_RED ) ;
2006-10-21 23:31:34 +00:00
buff = strecpy ( buff , " - " , last ) ;
2005-02-06 11:23:41 +00:00
number = - number ;
}
2004-09-10 19:02:27 +00:00
2012-01-01 17:22:32 +00:00
/* Add prefix part, following symbol_pos specification.
* Here , it can can be either 0 ( prefix ) or 2 ( both prefix and suffix ) .
2006-09-15 02:52:17 +00:00
* The only remaining value is 1 ( suffix ) , so everything that is not 1 */
2006-10-21 23:31:34 +00:00
if ( spec - > symbol_pos ! = 1 ) buff = strecpy ( buff , spec - > prefix , last ) ;
2004-08-09 17:04:08 +00:00
2007-04-04 01:35:16 +00:00
/* for huge numbers, compact the number into k or M */
2004-08-09 17:04:08 +00:00
if ( compact ) {
2010-10-22 16:30:09 +00:00
/* Take care of the 'k' rounding. Having 1 000 000 k
* and 1 000 M is inconsistent , so always use 1 000 M . */
if ( number > = 1000000000 - 500 ) {
2004-08-09 17:04:08 +00:00
number = ( number + 500000 ) / 1000000 ;
2014-08-15 20:14:48 +00:00
multiplier = NBSP " M " ;
2004-08-09 17:04:08 +00:00
} else if ( number > = 1000000 ) {
number = ( number + 500 ) / 1000 ;
2014-08-15 20:14:48 +00:00
multiplier = NBSP " k " ;
2004-09-10 19:02:27 +00:00
}
2004-08-09 17:04:08 +00:00
}
2004-09-10 19:02:27 +00:00
2009-04-23 21:05:00 +00:00
const char * separator = _settings_game . locale . digit_group_separator_currency ;
2009-04-25 20:16:56 +00:00
if ( separator = = NULL & & ! StrEmpty ( _currency - > separator ) ) separator = _currency - > separator ;
2009-04-23 21:05:00 +00:00
if ( separator = = NULL ) separator = _langpack - > digit_group_separator_currency ;
buff = FormatNumber ( buff , number , last , separator ) ;
2006-10-21 23:31:34 +00:00
buff = strecpy ( buff , multiplier , last ) ;
2004-08-09 17:04:08 +00:00
2012-01-01 17:22:32 +00:00
/* Add suffix part, following symbol_pos specification.
* Here , it can can be either 1 ( suffix ) or 2 ( both prefix and suffix ) .
2006-09-15 02:52:17 +00:00
* The only remaining value is 1 ( prefix ) , so everything that is not 0 */
2006-10-21 23:31:34 +00:00
if ( spec - > symbol_pos ! = 0 ) buff = strecpy ( buff , spec - > suffix , last ) ;
2004-08-09 17:04:08 +00:00
2007-10-20 14:51:09 +00:00
if ( negative ) {
2007-08-07 15:20:31 +00:00
if ( buff + Utf8CharLen ( SCC_PREVIOUS_COLOUR ) > last ) return buff ;
buff + = Utf8Encode ( buff , SCC_PREVIOUS_COLOUR ) ;
* buff = ' \0 ' ;
}
2004-08-09 17:04:08 +00:00
return buff ;
}
2010-11-16 21:01:56 +00:00
/**
* Determine the " plural " index given a plural form and a number .
* @ param count The number to get the plural index of .
* @ param plural_form The plural form we want an index for .
* @ return The plural index for the given form .
*/
static int DeterminePluralForm ( int64 count , int plural_form )
2005-07-16 17:12:32 +00:00
{
2007-04-04 01:35:16 +00:00
/* The absolute value determines plurality */
2008-03-25 19:56:16 +00:00
uint64 n = abs ( count ) ;
2005-07-16 17:12:32 +00:00
2010-11-16 21:01:56 +00:00
switch ( plural_form ) {
2008-03-25 19:56:16 +00:00
default :
NOT_REACHED ( ) ;
2012-07-03 19:14:51 +00:00
/* Two forms: singular used for one only.
2008-03-25 19:56:16 +00:00
* Used in :
* Danish , Dutch , English , German , Norwegian , Swedish , Estonian , Finnish ,
* Greek , Hebrew , Italian , Portuguese , Spanish , Esperanto */
case 0 :
2013-01-12 17:20:31 +00:00
return n ! = 1 ? 1 : 0 ;
2008-03-25 19:56:16 +00:00
2012-07-03 19:14:51 +00:00
/* Only one form.
2008-03-25 19:56:16 +00:00
* Used in :
* Hungarian , Japanese , Korean , Turkish */
case 1 :
return 0 ;
2012-07-03 19:14:51 +00:00
/* Two forms: singular used for 0 and 1.
2008-03-25 19:56:16 +00:00
* Used in :
* French , Brazilian Portuguese */
case 2 :
2013-01-12 17:20:31 +00:00
return n > 1 ? 1 : 0 ;
2008-03-25 19:56:16 +00:00
2012-07-03 19:14:51 +00:00
/* Three forms: special cases for 0, and numbers ending in 1 except when ending in 11.
2013-01-12 17:21:30 +00:00
* Note : Cases are out of order for hysterical reasons . ' 0 ' is last .
2008-03-25 19:56:16 +00:00
* Used in :
* Latvian */
case 3 :
return n % 10 = = 1 & & n % 100 ! = 11 ? 0 : n ! = 0 ? 1 : 2 ;
2012-07-03 19:14:51 +00:00
/* Five forms: special cases for 1, 2, 3 to 6, and 7 to 10.
2008-03-25 19:56:16 +00:00
* Used in :
* Gaelige ( Irish ) */
case 4 :
2010-04-17 11:16:34 +00:00
return n = = 1 ? 0 : n = = 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4 ;
2008-03-25 19:56:16 +00:00
2012-07-03 19:14:51 +00:00
/* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 9 except when ending in 12 to 19.
2008-03-25 19:56:16 +00:00
* Used in :
* Lithuanian */
case 5 :
return n % 10 = = 1 & & n % 100 ! = 11 ? 0 : n % 10 > = 2 & & ( n % 100 < 10 | | n % 100 > = 20 ) ? 1 : 2 ;
2013-01-08 22:46:42 +00:00
/* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 4 except when ending in 12 to 14.
2008-03-25 19:56:16 +00:00
* Used in :
2010-03-18 16:34:50 +00:00
* Croatian , Russian , Ukrainian */
2008-03-25 19:56:16 +00:00
case 6 :
return n % 10 = = 1 & & n % 100 ! = 11 ? 0 : n % 10 > = 2 & & n % 10 < = 4 & & ( n % 100 < 10 | | n % 100 > = 20 ) ? 1 : 2 ;
2012-07-03 19:14:51 +00:00
/* Three forms: special cases for 1, and numbers ending in 2 to 4 except when ending in 12 to 14.
2008-03-25 19:56:16 +00:00
* Used in :
* Polish */
case 7 :
return n = = 1 ? 0 : n % 10 > = 2 & & n % 10 < = 4 & & ( n % 100 < 10 | | n % 100 > = 20 ) ? 1 : 2 ;
2012-07-03 19:14:51 +00:00
/* Four forms: special cases for numbers ending in 01, 02, and 03 to 04.
2008-03-25 19:56:16 +00:00
* Used in :
* Slovenian */
case 8 :
return n % 100 = = 1 ? 0 : n % 100 = = 2 ? 1 : n % 100 = = 3 | | n % 100 = = 4 ? 2 : 3 ;
2012-07-03 19:14:51 +00:00
/* Two forms: singular used for numbers ending in 1 except when ending in 11.
2008-03-25 19:56:16 +00:00
* Used in :
* Icelandic */
case 9 :
return n % 10 = = 1 & & n % 100 ! = 11 ? 0 : 1 ;
2009-04-07 00:05:44 +00:00
2012-07-03 19:14:51 +00:00
/* Three forms: special cases for 1, and 2 to 4
2009-04-07 00:05:44 +00:00
* Used in :
2010-03-18 16:34:50 +00:00
* Czech , Slovak */
2009-04-07 00:05:44 +00:00
case 10 :
return n = = 1 ? 0 : n > = 2 & & n < = 4 ? 1 : 2 ;
2009-07-13 14:42:09 +00:00
2012-07-03 19:14:51 +00:00
/* Two forms: cases for numbers ending with a consonant, and with a vowel.
2009-07-13 14:42:09 +00:00
* Korean doesn ' t have the concept of plural , but depending on how a
* number is pronounced it needs another version of a particle .
* As such the plural system is misused to give this distinction .
*/
case 11 :
switch ( n % 10 ) {
case 0 : // yeong
case 1 : // il
case 3 : // sam
case 6 : // yuk
case 7 : // chil
case 8 : // pal
return 0 ;
case 2 : // i
case 4 : // sa
case 5 : // o
case 9 : // gu
return 1 ;
default :
NOT_REACHED ( ) ;
}
2010-04-17 11:16:34 +00:00
2012-07-03 19:14:51 +00:00
/* Four forms: special cases for 1, 0 and numbers ending in 02 to 10, and numbers ending in 11 to 19.
2010-04-17 11:16:34 +00:00
* Used in :
* Maltese */
case 12 :
return ( n = = 1 ? 0 : n = = 0 | | ( n % 100 > 1 & & n % 100 < 11 ) ? 1 : ( n % 100 > 10 & & n % 100 < 20 ) ? 2 : 3 ) ;
2013-03-10 11:02:11 +00:00
/* Four forms: special cases for 1 and 11, 2 and 12, 3 .. 10 and 13 .. 19, other
* Used in :
* Scottish Gaelic */
case 13 :
return ( ( n = = 1 | | n = = 11 ) ? 0 : ( n = = 2 | | n = = 12 ) ? 1 : ( ( n > 2 & & n < 11 ) | | ( n > 12 & & n < 20 ) ) ? 2 : 3 ) ;
2005-07-16 17:12:32 +00:00
}
}
2009-08-06 20:21:53 +00:00
static const char * ParseStringChoice ( const char * b , uint form , char * * dst , const char * last )
2005-07-16 17:12:32 +00:00
{
2009-03-15 00:32:18 +00:00
/* <NUM> {Length of each string} {each string} */
2005-07-16 17:12:32 +00:00
uint n = ( byte ) * b + + ;
2009-08-06 20:21:53 +00:00
uint pos , i , mypos = 0 ;
2006-02-01 07:36:15 +00:00
for ( i = pos = 0 ; i ! = n ; i + + ) {
2005-07-16 17:12:32 +00:00
uint len = ( byte ) * b + + ;
2009-08-06 20:21:53 +00:00
if ( i = = form ) mypos = pos ;
2005-07-16 17:12:32 +00:00
pos + = len ;
}
2009-08-06 20:21:53 +00:00
* dst + = seprintf ( * dst , last , " %s " , b + mypos ) ;
2005-07-16 17:12:32 +00:00
return b + pos ;
}
2011-02-09 12:59:39 +00:00
/** Helper for unit conversion. */
struct UnitConversion {
int multiplier ; ///< Amount to multiply upon conversion.
int shift ; ///< Amount to shift upon conversion.
/**
* Convert value from OpenTTD ' s internal unit into the displayed value .
* @ param input The input to convert .
2011-02-10 20:54:46 +00:00
* @ param round Whether to round the value or not .
2011-02-09 12:59:39 +00:00
* @ return The converted value .
*/
2011-02-10 20:54:46 +00:00
int64 ToDisplay ( int64 input , bool round = true ) const
2011-02-09 12:59:39 +00:00
{
2011-02-10 20:54:46 +00:00
return ( ( input * this - > multiplier ) + ( round & & this - > shift ! = 0 ? 1 < < ( this - > shift - 1 ) : 0 ) ) > > this - > shift ;
2011-02-09 12:59:39 +00:00
}
/**
* Convert the displayed value back into a value of OpenTTD ' s internal unit .
* @ param input The input to convert .
2012-02-27 13:22:38 +00:00
* @ param round Whether to round the value up or not .
* @ param divider Divide the return value by this .
2011-02-09 12:59:39 +00:00
* @ return The converted value .
*/
2012-02-27 13:22:38 +00:00
int64 FromDisplay ( int64 input , bool round = true , int64 divider = 1 ) const
2011-02-09 12:59:39 +00:00
{
2012-02-27 13:22:38 +00:00
return ( ( input < < this - > shift ) + ( round ? ( this - > multiplier * divider ) - 1 : 0 ) ) / ( this - > multiplier * divider ) ;
2011-02-09 12:59:39 +00:00
}
} ;
2013-06-29 09:47:18 +00:00
/** Information about a specific unit system. */
2007-03-07 12:11:48 +00:00
struct Units {
2013-06-29 09:47:18 +00:00
UnitConversion c ; ///< Conversion
StringID s ; ///< String for the unit
2007-03-07 12:11:48 +00:00
} ;
2006-03-26 21:50:57 +00:00
2013-06-29 09:47:18 +00:00
/** Information about a specific unit system with a long variant. */
struct UnitsLong {
UnitConversion c ; ///< Conversion
StringID s ; ///< String for the short variant of the unit
StringID l ; ///< String for the long variant of the unit
} ;
/** Unit conversions for velocity. */
static const Units _units_velocity [ ] = {
{ { 1 , 0 } , STR_UNITS_VELOCITY_IMPERIAL } ,
{ { 103 , 6 } , STR_UNITS_VELOCITY_METRIC } ,
{ { 1831 , 12 } , STR_UNITS_VELOCITY_SI } ,
} ;
/** Unit conversions for velocity. */
static const Units _units_power [ ] = {
{ { 1 , 0 } , STR_UNITS_POWER_IMPERIAL } ,
{ { 4153 , 12 } , STR_UNITS_POWER_METRIC } ,
{ { 6109 , 13 } , STR_UNITS_POWER_SI } ,
} ;
/** Unit conversions for weight. */
static const UnitsLong _units_weight [ ] = {
{ { 4515 , 12 } , STR_UNITS_WEIGHT_SHORT_IMPERIAL , STR_UNITS_WEIGHT_LONG_IMPERIAL } ,
{ { 1 , 0 } , STR_UNITS_WEIGHT_SHORT_METRIC , STR_UNITS_WEIGHT_LONG_METRIC } ,
{ { 1000 , 0 } , STR_UNITS_WEIGHT_SHORT_SI , STR_UNITS_WEIGHT_LONG_SI } ,
} ;
/** Unit conversions for volume. */
static const UnitsLong _units_volume [ ] = {
{ { 4227 , 4 } , STR_UNITS_VOLUME_SHORT_IMPERIAL , STR_UNITS_VOLUME_LONG_IMPERIAL } ,
{ { 1000 , 0 } , STR_UNITS_VOLUME_SHORT_METRIC , STR_UNITS_VOLUME_LONG_METRIC } ,
{ { 1 , 0 } , STR_UNITS_VOLUME_SHORT_SI , STR_UNITS_VOLUME_LONG_SI } ,
} ;
/** Unit conversions for force. */
static const Units _units_force [ ] = {
{ { 3597 , 4 } , STR_UNITS_FORCE_IMPERIAL } ,
{ { 3263 , 5 } , STR_UNITS_FORCE_METRIC } ,
{ { 1 , 0 } , STR_UNITS_FORCE_SI } ,
} ;
/** Unit conversions for height. */
static const Units _units_height [ ] = {
{ { 3 , 0 } , STR_UNITS_HEIGHT_IMPERIAL } , // "Wrong" conversion factor for more nicer GUI values
{ { 1 , 0 } , STR_UNITS_HEIGHT_METRIC } ,
{ { 1 , 0 } , STR_UNITS_HEIGHT_SI } ,
2006-03-26 21:50:57 +00:00
} ;
2005-07-16 17:12:32 +00:00
2008-04-12 10:00:52 +00:00
/**
* Convert the given ( internal ) speed to the display speed .
* @ param speed the speed to convert
* @ return the converted speed .
*/
uint ConvertSpeedToDisplaySpeed ( uint speed )
{
2011-02-10 20:54:46 +00:00
/* For historical reasons we don't want to mess with the
* conversion for speed . So , don ' t round it and keep the
* original conversion factors instead of the real ones . */
2013-06-29 09:47:18 +00:00
return _units_velocity [ _settings_game . locale . units_velocity ] . c . ToDisplay ( speed , false ) ;
2008-04-12 10:00:52 +00:00
}
/**
* Convert the given display speed to the ( internal ) speed .
* @ param speed the speed to convert
* @ return the converted speed .
*/
uint ConvertDisplaySpeedToSpeed ( uint speed )
{
2013-06-29 09:47:18 +00:00
return _units_velocity [ _settings_game . locale . units_velocity ] . c . FromDisplay ( speed ) ;
2008-04-12 10:00:52 +00:00
}
2012-02-14 17:03:56 +00:00
/**
* Convert the given km / h - ish speed to the display speed .
* @ param speed the speed to convert
* @ return the converted speed .
*/
uint ConvertKmhishSpeedToDisplaySpeed ( uint speed )
{
2013-06-29 09:47:18 +00:00
return _units_velocity [ _settings_game . locale . units_velocity ] . c . ToDisplay ( speed * 10 , false ) / 16 ;
2012-02-14 17:03:56 +00:00
}
/**
* Convert the given display speed to the km / h - ish speed .
* @ param speed the speed to convert
* @ return the converted speed .
*/
uint ConvertDisplaySpeedToKmhishSpeed ( uint speed )
{
2013-06-29 09:47:18 +00:00
return _units_velocity [ _settings_game . locale . units_velocity ] . c . FromDisplay ( speed * 16 , true , 10 ) ;
2012-02-14 17:03:56 +00:00
}
2010-12-09 21:41:31 +00:00
/**
* Parse most format codes within a string and write the result to a buffer .
* @ param buff The buffer to write the final string to .
* @ param str The original string with format codes .
2011-03-18 13:34:52 +00:00
* @ param args Pointer to extra arguments used by various string codes .
2011-10-20 16:50:57 +00:00
* @ param case_index
2010-12-09 21:41:31 +00:00
* @ param last Pointer to just past the end of the buff array .
* @ param dry_run True when the argt array is not yet initialized .
*/
2011-12-20 22:11:22 +00:00
static char * FormatString ( char * buff , const char * str_arg , StringParameters * args , const char * last , uint case_index , bool game_script , bool dry_run )
2004-08-09 17:04:08 +00:00
{
2011-03-18 13:34:52 +00:00
uint orig_offset = args - > offset ;
2010-12-09 21:41:31 +00:00
/* When there is no array with types there is no need to do a dry run. */
2011-10-14 10:54:51 +00:00
if ( args - > HasTypeInformation ( ) & & ! dry_run ) {
2011-03-18 13:34:52 +00:00
if ( UsingNewGRFTextStack ( ) ) {
/* Values from the NewGRF text stack are only copied to the normal
* argv array at the time they are encountered . That means that if
* another string command references a value later in the string it
* would fail . We solve that by running FormatString twice . The first
* pass makes sure the argv array is correctly filled and the second
* pass can reference later values without problems . */
struct TextRefStack * backup = CreateTextRefStackBackup ( ) ;
2011-12-20 22:11:22 +00:00
FormatString ( buff , str_arg , args , last , case_index , game_script , true ) ;
2011-03-18 13:34:52 +00:00
RestoreTextRefStackBackup ( backup ) ;
} else {
2011-12-20 22:11:22 +00:00
FormatString ( buff , str_arg , args , last , case_index , game_script , true ) ;
2011-03-18 13:34:52 +00:00
}
/* We have to restore the original offset here to to read the correct values. */
args - > offset = orig_offset ;
2010-12-08 13:44:01 +00:00
}
2013-11-19 19:43:56 +00:00
WChar b = ' \0 ' ;
2011-10-20 16:51:54 +00:00
uint next_substr_case_index = 0 ;
2010-04-06 21:16:36 +00:00
char * buf_start = buff ;
2011-01-21 23:10:02 +00:00
std : : stack < const char * > str_stack ;
str_stack . push ( str_arg ) ;
2011-02-25 21:53:43 +00:00
for ( ; ; ) {
2011-01-21 23:10:02 +00:00
while ( ! str_stack . empty ( ) & & ( b = Utf8Consume ( & str_stack . top ( ) ) ) = = ' \0 ' ) {
str_stack . pop ( ) ;
}
if ( str_stack . empty ( ) ) break ;
const char * & str = str_stack . top ( ) ;
2004-08-09 17:04:08 +00:00
2007-09-22 23:55:34 +00:00
if ( SCC_NEWGRF_FIRST < = b & & b < = SCC_NEWGRF_LAST ) {
/* We need to pass some stuff as it might be modified; oh boy. */
2010-12-09 00:15:38 +00:00
//todo: should argve be passed here too?
2014-01-12 18:00:02 +00:00
b = RemapNewGRFStringControlCode ( b , buf_start , & buff , & str , ( int64 * ) args - > GetDataPointer ( ) , args - > GetDataLeft ( ) , dry_run ) ;
2007-09-22 23:55:34 +00:00
if ( b = = 0 ) continue ;
}
2005-02-06 11:23:41 +00:00
switch ( b ) {
2011-12-19 21:05:57 +00:00
case SCC_ENCODED : {
uint64 sub_args_data [ 20 ] ;
WChar sub_args_type [ 20 ] ;
bool sub_args_need_free [ 20 ] ;
StringParameters sub_args ( sub_args_data , 20 , sub_args_type ) ;
sub_args . ClearTypeInformation ( ) ;
memset ( sub_args_need_free , 0 , sizeof ( sub_args_need_free ) ) ;
uint16 stringid ;
const char * s = str ;
char * p ;
stringid = strtol ( str , & p , 16 ) ;
if ( * p ! = ' : ' & & * p ! = ' \0 ' ) {
while ( * p ! = ' \0 ' ) p + + ;
str = p ;
buff = strecat ( buff , " (invalid SCC_ENCODED) " , last ) ;
break ;
}
if ( stringid > = TAB_SIZE ) {
while ( * p ! = ' \0 ' ) p + + ;
str = p ;
buff = strecat ( buff , " (invalid StringID) " , last ) ;
break ;
}
int i = 0 ;
2012-10-14 15:18:09 +00:00
while ( * p ! = ' \0 ' & & i < 20 ) {
2011-12-19 21:05:57 +00:00
uint64 param ;
s = + + p ;
/* Find the next value */
bool instring = false ;
bool escape = false ;
for ( ; ; p + + ) {
if ( * p = = ' \\ ' ) {
escape = true ;
continue ;
}
if ( * p = = ' " ' & & escape ) {
escape = false ;
continue ;
}
escape = false ;
if ( * p = = ' " ' ) {
instring = ! instring ;
continue ;
}
if ( instring ) {
continue ;
}
if ( * p = = ' : ' ) break ;
if ( * p = = ' \0 ' ) break ;
}
if ( * s ! = ' " ' ) {
/* Check if we want to look up another string */
WChar l ;
size_t len = Utf8Decode ( & l , s ) ;
bool lookup = ( l = = SCC_ENCODED ) ;
if ( lookup ) s + = len ;
2013-01-12 12:48:00 +00:00
param = ( int32 ) strtoul ( s , & p , 16 ) ;
2011-12-19 21:05:57 +00:00
if ( lookup ) {
if ( param > = TAB_SIZE ) {
while ( * p ! = ' \0 ' ) p + + ;
str = p ;
buff = strecat ( buff , " (invalid sub-StringID) " , last ) ;
break ;
}
param = ( GAME_TEXT_TAB < < TAB_COUNT_OFFSET ) + param ;
}
sub_args . SetParam ( i + + , param ) ;
} else {
2014-04-25 15:40:32 +00:00
char * g = stredup ( s ) ;
2011-12-19 21:05:57 +00:00
g [ p - s ] = ' \0 ' ;
sub_args_need_free [ i ] = true ;
sub_args . SetParam ( i + + , ( uint64 ) ( size_t ) g ) ;
}
}
2013-02-08 20:31:51 +00:00
/* If we didn't error out, we can actually print the string. */
if ( * str ! = ' \0 ' ) {
str = p ;
buff = GetStringWithArgs ( buff , ( GAME_TEXT_TAB < < TAB_COUNT_OFFSET ) + stringid , & sub_args , last , true ) ;
}
2011-12-19 21:05:57 +00:00
for ( int i = 0 ; i < 20 ; i + + ) {
if ( sub_args_need_free [ i ] ) free ( ( void * ) sub_args . GetParam ( i ) ) ;
}
break ;
}
2011-01-21 23:10:02 +00:00
case SCC_NEWGRF_STRINL : {
StringID substr = Utf8Consume ( & str ) ;
str_stack . push ( GetStringPtr ( substr ) ) ;
break ;
}
2011-08-20 22:06:38 +00:00
case SCC_NEWGRF_PRINT_WORD_STRING_ID : {
2012-01-21 13:57:24 +00:00
StringID substr = args - > GetInt32 ( SCC_NEWGRF_PRINT_WORD_STRING_ID ) ;
2011-01-21 23:10:02 +00:00
str_stack . push ( GetStringPtr ( substr ) ) ;
2011-10-20 16:51:54 +00:00
case_index = next_substr_case_index ;
next_substr_case_index = 0 ;
2011-01-21 23:10:02 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_GENDER_LIST : { // {G 0 Der Die Das}
/* First read the meta data from the language file. */
uint offset = orig_offset + ( byte ) * str + + ;
int gender = 0 ;
if ( ! dry_run & & args - > GetTypeAtOffset ( offset ) ! = 0 ) {
/* Now we need to figure out what text to resolve, i.e.
* what do we need to draw ? So get the actual raw string
* first using the control code to get said string . */
char input [ 4 + 1 ] ;
char * p = input + Utf8Encode ( input , args - > GetTypeAtOffset ( offset ) ) ;
* p = ' \0 ' ;
/* Now do the string formatting. */
char buf [ 256 ] ;
2012-09-12 18:50:44 +00:00
bool old_sgd = _scan_for_gender_data ;
_scan_for_gender_data = true ;
2011-11-19 22:15:44 +00:00
StringParameters tmp_params ( args - > GetPointerToOffset ( offset ) , args - > num_param - offset , NULL ) ;
p = FormatString ( buf , input , & tmp_params , lastof ( buf ) ) ;
2012-09-12 18:50:44 +00:00
_scan_for_gender_data = old_sgd ;
2011-11-19 22:15:44 +00:00
* p = ' \0 ' ;
/* And determine the string. */
const char * s = buf ;
WChar c = Utf8Consume ( & s ) ;
/* Does this string have a gender, if so, set it */
if ( c = = SCC_GENDER_INDEX ) gender = ( byte ) s [ 0 ] ;
2006-11-16 22:05:33 +00:00
}
2011-11-19 22:15:44 +00:00
str = ParseStringChoice ( str , gender , & buff , last ) ;
2006-11-16 22:05:33 +00:00
break ;
2011-11-19 22:15:44 +00:00
}
2006-11-16 22:05:33 +00:00
2011-11-19 22:15:44 +00:00
/* This sets up the gender for the string.
* We just ignore this one . It ' s used in { G 0 Der Die Das } to determine the case . */
case SCC_GENDER_INDEX : // {GENDER 0}
2012-09-12 18:50:44 +00:00
if ( _scan_for_gender_data ) {
2011-11-19 22:15:44 +00:00
buff + = Utf8Encode ( buff , SCC_GENDER_INDEX ) ;
2006-11-16 22:05:33 +00:00
* buff + + = * str + + ;
2011-11-19 22:15:44 +00:00
} else {
str + + ;
2006-11-16 22:05:33 +00:00
}
break ;
2011-11-19 22:15:44 +00:00
case SCC_PLURAL_LIST : { // {P}
int plural_form = * str + + ; // contains the plural form for this string
uint offset = orig_offset + ( byte ) * str + + ;
int64 v = * args - > GetPointerToOffset ( offset ) ; // contains the number that determines plural
str = ParseStringChoice ( str , DeterminePluralForm ( v , plural_form ) , & buff , last ) ;
2008-07-17 13:47:04 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_ARG_INDEX : { // Move argument pointer
args - > offset = orig_offset + ( byte ) * str + + ;
2006-11-16 22:05:33 +00:00
break ;
2011-11-19 22:15:44 +00:00
}
2006-11-16 22:05:33 +00:00
2011-11-19 22:15:44 +00:00
case SCC_SET_CASE : { // {SET_CASE}
/* This is a pseudo command, it's outputted when someone does {STRING.ack}
* The modifier is added to all subsequent GetStringWithArgs that accept the modifier . */
next_substr_case_index = ( byte ) * str + + ;
2006-11-16 22:05:33 +00:00
break ;
2011-11-19 22:15:44 +00:00
}
2006-11-16 22:05:33 +00:00
2011-11-19 22:15:44 +00:00
case SCC_SWITCH_CASE : { // {Used to implement case switching}
/* <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
* Each LEN is printed using 2 bytes in big endian order . */
uint num = ( byte ) * str + + ;
while ( num ) {
if ( ( byte ) str [ 0 ] = = case_index ) {
/* Found the case, adjust str pointer and continue */
str + = 3 ;
break ;
}
/* Otherwise skip to the next case */
str + = 3 + ( str [ 1 ] < < 8 ) + str [ 2 ] ;
num - - ;
}
2006-11-16 22:05:33 +00:00
break ;
2006-10-21 23:31:34 +00:00
}
2005-09-10 15:14:35 +00:00
2008-11-24 20:51:55 +00:00
case SCC_REVISION : // {REV}
2006-10-21 23:31:34 +00:00
buff = strecpy ( buff , _openttd_revision , last ) ;
2004-08-09 17:04:08 +00:00
break ;
2006-11-16 22:05:33 +00:00
2011-11-19 22:15:44 +00:00
case SCC_RAW_STRING_POINTER : { // {RAW_STRING}
2011-12-20 22:11:22 +00:00
if ( game_script ) break ;
2011-12-10 16:03:12 +00:00
const char * str = ( const char * ) ( size_t ) args - > GetInt64 ( SCC_RAW_STRING_POINTER ) ;
2011-11-19 22:15:44 +00:00
buff = FormatString ( buff , str , args , last ) ;
break ;
}
2006-03-26 21:50:57 +00:00
2011-11-19 22:15:44 +00:00
case SCC_STRING : { // {STRING}
StringID str = args - > GetInt32 ( SCC_STRING ) ;
2011-12-20 22:11:22 +00:00
if ( game_script & & GB ( str , TAB_COUNT_OFFSET , TAB_COUNT_BITS ) ! = GAME_TEXT_TAB ) break ;
2011-11-19 22:15:44 +00:00
/* WARNING. It's prohibited for the included string to consume any arguments.
* For included strings that consume argument , you should use STRING1 , STRING2 etc .
* To debug stuff you can set argv to NULL and it will tell you */
2014-01-12 17:59:43 +00:00
StringParameters tmp_params ( args - > GetDataPointer ( ) , args - > GetDataLeft ( ) , NULL ) ;
2011-12-20 22:11:22 +00:00
buff = GetStringWithArgs ( buff , str , & tmp_params , last , next_substr_case_index , game_script ) ;
2011-11-19 22:15:44 +00:00
next_substr_case_index = 0 ;
2010-08-01 18:53:30 +00:00
break ;
}
2006-11-16 22:05:33 +00:00
2012-01-15 15:49:01 +00:00
case SCC_STRING1 :
case SCC_STRING2 :
case SCC_STRING3 :
case SCC_STRING4 :
case SCC_STRING5 :
case SCC_STRING6 :
case SCC_STRING7 : { // {STRING1..7}
/* Strings that consume arguments */
StringID str = args - > GetInt32 ( b ) ;
2011-12-20 22:11:22 +00:00
if ( game_script & & GB ( str , TAB_COUNT_OFFSET , TAB_COUNT_BITS ) ! = GAME_TEXT_TAB ) break ;
2013-02-08 20:32:56 +00:00
uint size = b - SCC_STRING1 + 1 ;
2014-01-12 17:59:43 +00:00
if ( game_script & & size > args - > GetDataLeft ( ) ) {
2013-02-08 20:32:56 +00:00
buff = strecat ( buff , " (too many parameters) " , last ) ;
} else {
StringParameters sub_args ( * args , size ) ;
buff = GetStringWithArgs ( buff , str , & sub_args , last , next_substr_case_index , game_script ) ;
}
2011-10-20 16:51:54 +00:00
next_substr_case_index = 0 ;
2005-07-15 14:53:44 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_COMMA : // {COMMA}
buff = FormatCommaNumber ( buff , args - > GetInt64 ( SCC_COMMA ) , last ) ;
2005-07-15 14:53:44 +00:00
break ;
2005-07-15 18:30:13 +00:00
2011-11-19 22:15:44 +00:00
case SCC_DECIMAL : { // {DECIMAL}
int64 number = args - > GetInt64 ( SCC_DECIMAL ) ;
int digits = args - > GetInt32 ( SCC_DECIMAL ) ;
buff = FormatCommaNumber ( buff , number , last , digits ) ;
break ;
}
2005-07-15 18:30:13 +00:00
2011-11-19 22:15:44 +00:00
case SCC_NUM : // {NUM}
buff = FormatNoCommaNumber ( buff , args - > GetInt64 ( SCC_NUM ) , last ) ;
break ;
2011-03-22 22:13:20 +00:00
2011-11-19 22:15:44 +00:00
case SCC_ZEROFILL_NUM : { // {ZEROFILL_NUM}
int64 num = args - > GetInt64 ( ) ;
buff = FormatZerofillNumber ( buff , num , args - > GetInt64 ( ) , last ) ;
2005-07-15 18:30:13 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_HEX : // {HEX}
buff = FormatHexNumber ( buff , ( uint64 ) args - > GetInt64 ( SCC_HEX ) , last ) ;
2005-07-16 20:58:04 +00:00
break ;
2011-11-19 22:15:44 +00:00
case SCC_BYTES : // {BYTES}
buff = FormatBytes ( buff , args - > GetInt64 ( ) , last ) ;
break ;
2010-12-09 21:01:50 +00:00
2011-11-23 16:04:28 +00:00
case SCC_CARGO_TINY : { // {CARGO_TINY}
/* Tiny description of cargotypes. Layout:
* param 1 : cargo type
* param 2 : cargo count */
2011-12-19 20:44:39 +00:00
CargoID cargo = args - > GetInt32 ( SCC_CARGO_TINY ) ;
if ( cargo > = CargoSpec : : GetArraySize ( ) ) break ;
StringID cargo_str = CargoSpec : : Get ( cargo ) - > units_volume ;
2011-11-23 16:04:28 +00:00
int64 amount = 0 ;
switch ( cargo_str ) {
case STR_TONS :
2013-06-29 09:47:18 +00:00
amount = _units_weight [ _settings_game . locale . units_weight ] . c . ToDisplay ( args - > GetInt64 ( ) ) ;
2011-11-23 16:04:28 +00:00
break ;
case STR_LITERS :
2013-06-29 09:47:18 +00:00
amount = _units_volume [ _settings_game . locale . units_volume ] . c . ToDisplay ( args - > GetInt64 ( ) ) ;
2011-11-23 16:04:28 +00:00
break ;
default : {
amount = args - > GetInt64 ( ) ;
break ;
}
}
buff = FormatCommaNumber ( buff , amount , last ) ;
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_CARGO_SHORT : { // {CARGO_SHORT}
/* Short description of cargotypes. Layout:
* param 1 : cargo type
* param 2 : cargo count */
2011-12-19 20:44:39 +00:00
CargoID cargo = args - > GetInt32 ( SCC_CARGO_SHORT ) ;
if ( cargo > = CargoSpec : : GetArraySize ( ) ) break ;
StringID cargo_str = CargoSpec : : Get ( cargo ) - > units_volume ;
2011-11-19 22:15:44 +00:00
switch ( cargo_str ) {
case STR_TONS : {
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_weight < lengthof ( _units_weight ) ) ;
int64 args_array [ ] = { _units_weight [ _settings_game . locale . units_weight ] . c . ToDisplay ( args - > GetInt64 ( ) ) } ;
2011-11-19 22:15:44 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_weight [ _settings_game . locale . units_weight ] . l ) , & tmp_params , last ) ;
2011-11-19 22:15:44 +00:00
break ;
}
2010-12-09 21:01:50 +00:00
2011-11-19 22:15:44 +00:00
case STR_LITERS : {
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_volume < lengthof ( _units_volume ) ) ;
int64 args_array [ ] = { _units_volume [ _settings_game . locale . units_volume ] . c . ToDisplay ( args - > GetInt64 ( ) ) } ;
2011-11-19 22:15:44 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_volume [ _settings_game . locale . units_volume ] . l ) , & tmp_params , last ) ;
2011-11-19 22:15:44 +00:00
break ;
}
default : {
StringParameters tmp_params ( * args , 1 ) ;
buff = GetStringWithArgs ( buff , cargo_str , & tmp_params , last ) ;
break ;
}
2010-12-09 21:01:50 +00:00
}
2005-07-16 20:58:04 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_CARGO_LONG : { // {CARGO_LONG}
/* First parameter is cargo type, second parameter is cargo count */
CargoID cargo = args - > GetInt32 ( SCC_CARGO_LONG ) ;
2011-12-19 20:44:39 +00:00
if ( cargo ! = CT_INVALID & & cargo > = CargoSpec : : GetArraySize ( ) ) break ;
2011-11-19 22:15:44 +00:00
StringID cargo_str = ( cargo = = CT_INVALID ) ? STR_QUANTITY_N_A : CargoSpec : : Get ( cargo ) - > quantifier ;
StringParameters tmp_args ( * args , 1 ) ;
buff = GetStringWithArgs ( buff , cargo_str , & tmp_args , last ) ;
2009-01-03 00:56:16 +00:00
break ;
}
2012-03-10 19:04:49 +00:00
case SCC_CARGO_LIST : { // {CARGO_LIST}
uint32 cmask = args - > GetInt32 ( SCC_CARGO_LIST ) ;
bool first = true ;
const CargoSpec * cs ;
FOR_ALL_SORTED_CARGOSPECS ( cs ) {
if ( ! HasBit ( cmask , cs - > Index ( ) ) ) continue ;
if ( buff > = last - 2 ) break ; // ',' and ' '
if ( first ) {
first = false ;
} else {
/* Add a comma if this is not the first item */
* buff + + = ' , ' ;
* buff + + = ' ' ;
}
buff = GetStringWithArgs ( buff , cs - > name , args , last , next_substr_case_index , game_script ) ;
}
/* If first is still true then no cargo is accepted */
if ( first ) buff = GetStringWithArgs ( buff , STR_JUST_NOTHING , args , last , next_substr_case_index , game_script ) ;
* buff = ' \0 ' ;
next_substr_case_index = 0 ;
/* Make sure we detect any buffer overflow */
assert ( buff < last ) ;
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_CURRENCY_SHORT : // {CURRENCY_SHORT}
buff = FormatGenericCurrency ( buff , _currency , args - > GetInt64 ( ) , true , last ) ;
break ;
case SCC_CURRENCY_LONG : // {CURRENCY_LONG}
buff = FormatGenericCurrency ( buff , _currency , args - > GetInt64 ( SCC_CURRENCY_LONG ) , false , last ) ;
break ;
case SCC_DATE_TINY : // {DATE_TINY}
buff = FormatTinyOrISODate ( buff , args - > GetInt32 ( SCC_DATE_TINY ) , STR_FORMAT_DATE_TINY , last ) ;
break ;
case SCC_DATE_SHORT : // {DATE_SHORT}
buff = FormatMonthAndYear ( buff , args - > GetInt32 ( SCC_DATE_SHORT ) , last , next_substr_case_index ) ;
next_substr_case_index = 0 ;
break ;
case SCC_DATE_LONG : // {DATE_LONG}
buff = FormatYmdString ( buff , args - > GetInt32 ( SCC_DATE_LONG ) , last , next_substr_case_index ) ;
next_substr_case_index = 0 ;
break ;
case SCC_DATE_ISO : // {DATE_ISO}
2011-03-18 13:34:52 +00:00
buff = FormatTinyOrISODate ( buff , args - > GetInt32 ( ) , STR_FORMAT_DATE_ISO , last ) ;
2005-07-17 10:18:23 +00:00
break ;
2011-11-19 22:15:44 +00:00
case SCC_FORCE : { // {FORCE}
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_force < lengthof ( _units_force ) ) ;
int64 args_array [ 1 ] = { _units_force [ _settings_game . locale . units_force ] . c . ToDisplay ( args - > GetInt64 ( ) ) } ;
2011-11-19 22:15:44 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_force [ _settings_game . locale . units_force ] . s ) , & tmp_params , last ) ;
2011-11-19 22:15:44 +00:00
break ;
}
case SCC_HEIGHT : { // {HEIGHT}
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_height < lengthof ( _units_height ) ) ;
int64 args_array [ ] = { _units_height [ _settings_game . locale . units_height ] . c . ToDisplay ( args - > GetInt64 ( ) ) } ;
2011-11-19 22:15:44 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_height [ _settings_game . locale . units_height ] . s ) , & tmp_params , last ) ;
2005-07-17 10:18:23 +00:00
break ;
}
2006-11-16 22:05:33 +00:00
case SCC_POWER : { // {POWER}
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_power < lengthof ( _units_power ) ) ;
int64 args_array [ 1 ] = { _units_power [ _settings_game . locale . units_power ] . c . ToDisplay ( args - > GetInt64 ( ) ) } ;
2011-03-22 22:13:20 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_power [ _settings_game . locale . units_power ] . s ) , & tmp_params , last ) ;
2006-03-26 21:50:57 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_VELOCITY : { // {VELOCITY}
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_velocity < lengthof ( _units_velocity ) ) ;
2012-02-14 17:03:56 +00:00
int64 args_array [ ] = { ConvertKmhishSpeedToDisplaySpeed ( args - > GetInt64 ( SCC_VELOCITY ) ) } ;
2011-11-19 22:15:44 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_velocity [ _settings_game . locale . units_velocity ] . s ) , & tmp_params , last ) ;
2011-11-19 22:15:44 +00:00
break ;
}
case SCC_VOLUME_SHORT : { // {VOLUME_SHORT}
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_volume < lengthof ( _units_volume ) ) ;
int64 args_array [ 1 ] = { _units_volume [ _settings_game . locale . units_volume ] . c . ToDisplay ( args - > GetInt64 ( ) ) } ;
2011-03-22 22:13:20 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_volume [ _settings_game . locale . units_volume ] . s ) , & tmp_params , last ) ;
2006-03-26 21:50:57 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_VOLUME_LONG : { // {VOLUME_LONG}
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_volume < lengthof ( _units_volume ) ) ;
int64 args_array [ 1 ] = { _units_volume [ _settings_game . locale . units_volume ] . c . ToDisplay ( args - > GetInt64 ( SCC_VOLUME_LONG ) ) } ;
2011-03-22 22:13:20 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_volume [ _settings_game . locale . units_volume ] . l ) , & tmp_params , last ) ;
2006-03-26 21:50:57 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_WEIGHT_SHORT : { // {WEIGHT_SHORT}
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_weight < lengthof ( _units_weight ) ) ;
int64 args_array [ 1 ] = { _units_weight [ _settings_game . locale . units_weight ] . c . ToDisplay ( args - > GetInt64 ( ) ) } ;
2011-03-22 22:13:20 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_weight [ _settings_game . locale . units_weight ] . s ) , & tmp_params , last ) ;
2006-03-26 21:50:57 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_WEIGHT_LONG : { // {WEIGHT_LONG}
2013-06-29 09:47:18 +00:00
assert ( _settings_game . locale . units_weight < lengthof ( _units_weight ) ) ;
int64 args_array [ 1 ] = { _units_weight [ _settings_game . locale . units_weight ] . c . ToDisplay ( args - > GetInt64 ( SCC_WEIGHT_LONG ) ) } ;
2011-03-22 22:13:20 +00:00
StringParameters tmp_params ( args_array ) ;
2013-06-29 09:47:18 +00:00
buff = FormatString ( buff , GetStringPtr ( _units_weight [ _settings_game . locale . units_weight ] . l ) , & tmp_params , last ) ;
2006-04-09 18:25:31 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_COMPANY_NAME : { // {COMPANY}
2011-12-19 20:44:39 +00:00
const Company * c = Company : : GetIfValid ( args - > GetInt32 ( ) ) ;
if ( c = = NULL ) break ;
2011-11-19 22:15:44 +00:00
if ( c - > name ! = NULL ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) c - > name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2010-02-20 23:42:11 +00:00
} else {
2011-11-19 22:15:44 +00:00
int64 args_array [ ] = { c - > name_2 } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , c - > name_1 , & tmp_params , last ) ;
2010-02-20 23:42:11 +00:00
}
2006-11-16 22:05:33 +00:00
break ;
}
2004-08-09 17:04:08 +00:00
2011-11-19 22:15:44 +00:00
case SCC_COMPANY_NUM : { // {COMPANY_NUM}
CompanyID company = ( CompanyID ) args - > GetInt32 ( ) ;
2005-09-10 15:14:35 +00:00
2011-11-19 22:15:44 +00:00
/* Nothing is added for AI or inactive companies */
if ( Company : : IsValidHumanID ( company ) ) {
int64 args_array [ ] = { company + 1 } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_FORMAT_COMPANY_NUM , & tmp_params , last ) ;
}
2011-04-09 20:26:14 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_DEPOT_NAME : { // {DEPOT}
VehicleType vt = ( VehicleType ) args - > GetInt32 ( SCC_DEPOT_NAME ) ;
if ( vt = = VEH_AIRCRAFT ) {
2012-01-09 22:20:44 +00:00
uint64 args_array [ ] = { args - > GetInt32 ( ) } ;
WChar types_array [ ] = { SCC_STATION_NAME } ;
StringParameters tmp_params ( args_array , 1 , types_array ) ;
2011-11-19 22:15:44 +00:00
buff = GetStringWithArgs ( buff , STR_FORMAT_DEPOT_NAME_AIRCRAFT , & tmp_params , last ) ;
break ;
}
const Depot * d = Depot : : Get ( args - > GetInt32 ( ) ) ;
if ( d - > name ! = NULL ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) d - > name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2011-11-19 22:15:44 +00:00
} else {
int64 args_array [ ] = { d - > town - > index , d - > town_cn + 1 } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + ( d - > town_cn = = 0 ? 0 : 1 ) , & tmp_params , last ) ;
}
2006-11-16 22:05:33 +00:00
break ;
2010-12-21 10:04:40 +00:00
}
2005-09-10 15:14:35 +00:00
2011-11-19 22:15:44 +00:00
case SCC_ENGINE_NAME : { // {ENGINE}
2011-12-19 20:44:39 +00:00
const Engine * e = Engine : : GetIfValid ( args - > GetInt32 ( SCC_ENGINE_NAME ) ) ;
if ( e = = NULL ) break ;
2011-11-19 22:15:44 +00:00
if ( e - > name ! = NULL & & e - > IsEnabled ( ) ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) e - > name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2011-11-19 22:15:44 +00:00
} else {
StringParameters tmp_params ( NULL , 0 , NULL ) ;
buff = GetStringWithArgs ( buff , e - > info . string_id , & tmp_params , last ) ;
}
2006-11-16 22:05:33 +00:00
break ;
}
2005-09-10 15:14:35 +00:00
2011-11-19 22:15:44 +00:00
case SCC_GROUP_NAME : { // {GROUP}
2011-12-19 20:44:39 +00:00
const Group * g = Group : : GetIfValid ( args - > GetInt32 ( ) ) ;
if ( g = = NULL ) break ;
2011-11-19 22:15:44 +00:00
if ( g - > name ! = NULL ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) g - > name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2011-11-19 22:15:44 +00:00
} else {
int64 args_array [ ] = { g - > index } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_FORMAT_GROUP_NAME , & tmp_params , last ) ;
}
2010-08-01 18:53:30 +00:00
break ;
}
2009-11-19 13:53:54 +00:00
2011-11-19 22:15:44 +00:00
case SCC_INDUSTRY_NAME : { // {INDUSTRY}
2011-12-19 20:44:39 +00:00
const Industry * i = Industry : : GetIfValid ( args - > GetInt32 ( SCC_INDUSTRY_NAME ) ) ;
if ( i = = NULL ) break ;
2009-01-16 12:59:47 +00:00
2012-09-12 18:52:11 +00:00
if ( _scan_for_gender_data ) {
/* Gender is defined by the industry type.
* STR_FORMAT_INDUSTRY_NAME may have the town first , so it would result in the gender of the town name */
StringParameters tmp_params ( NULL , 0 , NULL ) ;
buff = FormatString ( buff , GetStringPtr ( GetIndustrySpec ( i - > type ) - > name ) , & tmp_params , last , next_substr_case_index ) ;
} else {
/* First print the town name and the industry type name. */
int64 args_array [ 2 ] = { i - > town - > index , GetIndustrySpec ( i - > type ) - > name } ;
StringParameters tmp_params ( args_array ) ;
2005-09-10 15:14:35 +00:00
2012-09-12 18:52:11 +00:00
buff = FormatString ( buff , GetStringPtr ( STR_FORMAT_INDUSTRY_NAME ) , & tmp_params , last , next_substr_case_index ) ;
}
2011-11-19 22:15:44 +00:00
next_substr_case_index = 0 ;
break ;
}
2008-01-12 19:58:06 +00:00
2011-11-19 22:15:44 +00:00
case SCC_PRESIDENT_NAME : { // {PRESIDENT_NAME}
2011-12-19 20:44:39 +00:00
const Company * c = Company : : GetIfValid ( args - > GetInt32 ( SCC_PRESIDENT_NAME ) ) ;
if ( c = = NULL ) break ;
2008-09-12 17:11:28 +00:00
2011-11-19 22:15:44 +00:00
if ( c - > president_name ! = NULL ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) c - > president_name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2006-11-16 22:05:33 +00:00
} else {
2011-11-19 22:15:44 +00:00
int64 args_array [ ] = { c - > president_name_2 } ;
2011-03-18 13:34:52 +00:00
StringParameters tmp_params ( args_array ) ;
2011-11-19 22:15:44 +00:00
buff = GetStringWithArgs ( buff , c - > president_name_1 , & tmp_params , last ) ;
2006-11-16 22:05:33 +00:00
}
break ;
2005-07-17 10:18:23 +00:00
}
2004-08-09 17:04:08 +00:00
2006-11-16 22:05:33 +00:00
case SCC_STATION_NAME : { // {STATION}
2011-03-18 13:34:52 +00:00
StationID sid = args - > GetInt32 ( SCC_STATION_NAME ) ;
2009-05-18 16:21:28 +00:00
const Station * st = Station : : GetIfValid ( sid ) ;
2005-07-15 14:53:44 +00:00
2009-05-18 16:21:28 +00:00
if ( st = = NULL ) {
2008-09-12 17:14:07 +00:00
/* The station doesn't exist anymore. The only place where we might
* be " drawing " an invalid station is in the case of cargo that is
* in transit . */
2011-03-18 13:34:52 +00:00
StringParameters tmp_params ( NULL , 0 , NULL ) ;
buff = GetStringWithArgs ( buff , STR_UNKNOWN_STATION , & tmp_params , last ) ;
2008-09-12 17:14:07 +00:00
break ;
}
if ( st - > name ! = NULL ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) st - > name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2006-11-16 22:05:33 +00:00
} else {
2008-11-19 23:55:34 +00:00
StringID str = st - > string_id ;
if ( st - > indtype ! = IT_INVALID ) {
/* Special case where the industry provides the name for the station */
const IndustrySpec * indsp = GetIndustrySpec ( st - > indtype ) ;
/* Industry GRFs can change which might remove the station name and
* thus cause very strange things . Here we check for that before we
* actually set the station name . */
if ( indsp - > station_name ! = STR_NULL & & indsp - > station_name ! = STR_UNDEFINED ) {
str = indsp - > station_name ;
}
}
2011-03-22 22:13:20 +00:00
int64 args_array [ ] = { STR_TOWN_NAME , st - > town - > index , st - > index } ;
2011-03-18 13:34:52 +00:00
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , str , & tmp_params , last ) ;
2006-11-16 22:05:33 +00:00
}
break ;
2004-08-16 13:54:37 +00:00
}
2005-11-14 19:48:04 +00:00
2006-11-16 22:05:33 +00:00
case SCC_TOWN_NAME : { // {TOWN}
2011-12-19 20:44:39 +00:00
const Town * t = Town : : GetIfValid ( args - > GetInt32 ( SCC_TOWN_NAME ) ) ;
if ( t = = NULL ) break ;
2004-08-09 17:04:08 +00:00
2008-01-12 19:58:06 +00:00
if ( t - > name ! = NULL ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) t - > name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2007-06-18 23:00:55 +00:00
} else {
2009-09-22 13:54:54 +00:00
buff = GetTownName ( buff , t , last ) ;
2007-06-18 23:00:55 +00:00
}
2006-11-16 22:05:33 +00:00
break ;
}
2004-08-09 17:04:08 +00:00
2011-11-19 22:15:44 +00:00
case SCC_WAYPOINT_NAME : { // {WAYPOINT}
2011-12-19 20:44:39 +00:00
Waypoint * wp = Waypoint : : GetIfValid ( args - > GetInt32 ( SCC_WAYPOINT_NAME ) ) ;
if ( wp = = NULL ) break ;
2007-05-19 09:40:18 +00:00
2011-11-19 22:15:44 +00:00
if ( wp - > name ! = NULL ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) wp - > name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2008-01-12 19:58:06 +00:00
} else {
2011-11-19 22:15:44 +00:00
int64 args_array [ ] = { wp - > town - > index , wp - > town_cn + 1 } ;
2011-03-18 13:34:52 +00:00
StringParameters tmp_params ( args_array ) ;
2011-11-19 22:15:44 +00:00
StringID str = ( ( wp - > string_id = = STR_SV_STNAME_BUOY ) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME ) ;
if ( wp - > town_cn ! = 0 ) str + + ;
buff = GetStringWithArgs ( buff , str , & tmp_params , last ) ;
2008-01-12 19:58:06 +00:00
}
2007-06-25 14:46:32 +00:00
break ;
}
2007-06-24 22:42:11 +00:00
case SCC_VEHICLE_NAME : { // {VEHICLE}
2011-12-19 20:44:39 +00:00
const Vehicle * v = Vehicle : : GetIfValid ( args - > GetInt32 ( SCC_VEHICLE_NAME ) ) ;
if ( v = = NULL ) break ;
2009-05-22 15:13:50 +00:00
2008-01-12 19:58:06 +00:00
if ( v - > name ! = NULL ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) v - > name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2008-01-12 19:58:06 +00:00
} else {
2011-03-22 22:13:20 +00:00
int64 args_array [ ] = { v - > unitnumber } ;
2011-03-18 13:34:52 +00:00
StringParameters tmp_params ( args_array ) ;
2008-01-12 19:58:06 +00:00
StringID str ;
switch ( v - > type ) {
2013-11-16 09:49:13 +00:00
default : str = STR_INVALID_VEHICLE ; break ;
2008-01-12 19:58:06 +00:00
case VEH_TRAIN : str = STR_SV_TRAIN_NAME ; break ;
2009-07-22 22:44:56 +00:00
case VEH_ROAD : str = STR_SV_ROAD_VEHICLE_NAME ; break ;
2008-01-12 19:58:06 +00:00
case VEH_SHIP : str = STR_SV_SHIP_NAME ; break ;
case VEH_AIRCRAFT : str = STR_SV_AIRCRAFT_NAME ; break ;
}
2007-06-24 22:42:11 +00:00
2011-03-18 13:34:52 +00:00
buff = GetStringWithArgs ( buff , str , & tmp_params , last ) ;
2008-01-12 19:58:06 +00:00
}
2007-06-24 22:42:11 +00:00
break ;
}
2007-06-25 10:40:56 +00:00
case SCC_SIGN_NAME : { // {SIGN}
2011-12-19 20:44:39 +00:00
const Sign * si = Sign : : GetIfValid ( args - > GetInt32 ( ) ) ;
if ( si = = NULL ) break ;
2008-01-12 19:58:06 +00:00
if ( si - > name ! = NULL ) {
2011-12-19 21:06:06 +00:00
int64 args_array [ ] = { ( uint64 ) ( size_t ) si - > name } ;
StringParameters tmp_params ( args_array ) ;
buff = GetStringWithArgs ( buff , STR_JUST_RAW_STRING , & tmp_params , last ) ;
2008-01-12 19:58:06 +00:00
} else {
2011-03-18 13:34:52 +00:00
StringParameters tmp_params ( NULL , 0 , NULL ) ;
buff = GetStringWithArgs ( buff , STR_DEFAULT_SIGN_NAME , & tmp_params , last ) ;
2008-01-12 19:58:06 +00:00
}
2007-06-25 10:40:56 +00:00
break ;
}
2011-11-19 22:15:44 +00:00
case SCC_STATION_FEATURES : { // {STATIONFEATURES}
buff = StationGetSpecialString ( buff , args - > GetInt32 ( SCC_STATION_FEATURES ) , last ) ;
2006-11-16 22:05:33 +00:00
break ;
2005-07-17 10:18:23 +00:00
}
2005-01-22 23:13:20 +00:00
2006-11-16 22:05:33 +00:00
default :
if ( buff + Utf8CharLen ( b ) < last ) buff + = Utf8Encode ( buff , b ) ;
break ;
2004-08-09 17:04:08 +00:00
}
}
2005-02-06 11:23:41 +00:00
* buff = ' \0 ' ;
2004-08-09 17:04:08 +00:00
return buff ;
}
2008-11-24 20:51:55 +00:00
static char * StationGetSpecialString ( char * buff , int x , const char * last )
2004-08-09 17:04:08 +00:00
{
2008-04-19 18:03:24 +00:00
if ( ( x & FACIL_TRAIN ) & & ( buff + Utf8CharLen ( SCC_TRAIN ) < last ) ) buff + = Utf8Encode ( buff , SCC_TRAIN ) ;
if ( ( x & FACIL_TRUCK_STOP ) & & ( buff + Utf8CharLen ( SCC_LORRY ) < last ) ) buff + = Utf8Encode ( buff , SCC_LORRY ) ;
if ( ( x & FACIL_BUS_STOP ) & & ( buff + Utf8CharLen ( SCC_BUS ) < last ) ) buff + = Utf8Encode ( buff , SCC_BUS ) ;
if ( ( x & FACIL_DOCK ) & & ( buff + Utf8CharLen ( SCC_SHIP ) < last ) ) buff + = Utf8Encode ( buff , SCC_SHIP ) ;
2010-06-19 16:40:31 +00:00
if ( ( x & FACIL_AIRPORT ) & & ( buff + Utf8CharLen ( SCC_PLANE ) < last ) ) buff + = Utf8Encode ( buff , SCC_PLANE ) ;
2006-11-16 22:05:33 +00:00
* buff = ' \0 ' ;
2004-08-09 17:04:08 +00:00
return buff ;
}
2008-11-24 20:51:55 +00:00
static char * GetSpecialTownNameString ( char * buff , int ind , uint32 seed , const char * last )
2005-02-06 11:23:41 +00:00
{
2009-03-16 10:51:49 +00:00
return GenerateTownNameString ( buff , last , ind , seed ) ;
2004-08-09 17:04:08 +00:00
}
2008-11-24 20:51:55 +00:00
static const char * const _silly_company_names [ ] = {
2004-08-09 17:04:08 +00:00
" Bloggs Brothers " ,
" Tiny Transport Ltd. " ,
" Express Travel " ,
" Comfy-Coach & Co. " ,
" Crush & Bump Ltd. " ,
" Broken & Late Ltd. " ,
" Sam Speedy & Son " ,
" Supersonic Travel " ,
" Mike's Motors " ,
" Lightning International " ,
" Pannik & Loozit Ltd. " ,
" Inter-City Transport " ,
2005-11-16 11:17:52 +00:00
" Getout & Pushit Ltd. "
2004-08-09 17:04:08 +00:00
} ;
2008-11-24 20:51:55 +00:00
static const char * const _surname_list [ ] = {
2004-08-09 17:04:08 +00:00
" Adams " ,
" Allan " ,
" Baker " ,
" Bigwig " ,
" Black " ,
" Bloggs " ,
" Brown " ,
" Campbell " ,
" Gordon " ,
" Hamilton " ,
" Hawthorn " ,
" Higgins " ,
" Green " ,
" Gribble " ,
" Jones " ,
" McAlpine " ,
" MacDonald " ,
" McIntosh " ,
" Muir " ,
" Murphy " ,
" Nelson " ,
" O'Donnell " ,
" Parker " ,
" Phillips " ,
" Pilkington " ,
" Quigley " ,
" Sharkey " ,
" Thomson " ,
2005-11-16 11:17:52 +00:00
" Watkins "
} ;
2008-11-24 20:51:55 +00:00
static const char * const _silly_surname_list [ ] = {
2004-08-09 17:04:08 +00:00
" Grumpy " ,
" Dozy " ,
" Speedy " ,
" Nosey " ,
" Dribble " ,
" Mushroom " ,
" Cabbage " ,
" Sniffle " ,
" Fishy " ,
" Swindle " ,
" Sneaky " ,
2005-11-16 11:17:52 +00:00
" Nutkins "
2004-08-09 17:04:08 +00:00
} ;
2005-02-06 09:52:06 +00:00
static const char _initial_name_letters [ ] = {
2005-02-06 16:56:04 +00:00
' A ' , ' B ' , ' C ' , ' D ' , ' E ' , ' F ' , ' G ' , ' H ' , ' I ' , ' J ' ,
' K ' , ' L ' , ' M ' , ' N ' , ' P ' , ' R ' , ' S ' , ' T ' , ' W ' ,
2004-08-09 17:04:08 +00:00
} ;
2008-11-24 20:51:55 +00:00
static char * GenAndCoName ( char * buff , uint32 arg , const char * last )
2004-08-09 17:04:08 +00:00
{
2008-11-24 20:51:55 +00:00
const char * const * base ;
2005-11-16 11:17:52 +00:00
uint num ;
2004-08-09 17:04:08 +00:00
2008-05-29 15:13:28 +00:00
if ( _settings_game . game_creation . landscape = = LT_TOYLAND ) {
2005-11-16 11:17:52 +00:00
base = _silly_surname_list ;
num = lengthof ( _silly_surname_list ) ;
} else {
base = _surname_list ;
num = lengthof ( _surname_list ) ;
2004-08-09 17:04:08 +00:00
}
2006-10-21 23:31:34 +00:00
buff = strecpy ( buff , base [ num * GB ( arg , 16 , 8 ) > > 8 ] , last ) ;
buff = strecpy ( buff , " & Co. " , last ) ;
2004-08-09 17:04:08 +00:00
return buff ;
}
2008-11-24 20:51:55 +00:00
static char * GenPresidentName ( char * buff , uint32 x , const char * last )
2004-08-09 17:04:08 +00:00
{
2006-10-21 23:31:34 +00:00
char initial [ ] = " ?. " ;
2008-11-24 20:51:55 +00:00
const char * const * base ;
2005-11-16 11:17:52 +00:00
uint num ;
uint i ;
2004-08-09 17:04:08 +00:00
2006-10-21 23:31:34 +00:00
initial [ 0 ] = _initial_name_letters [ sizeof ( _initial_name_letters ) * GB ( x , 0 , 8 ) > > 8 ] ;
buff = strecpy ( buff , initial , last ) ;
2004-08-09 17:04:08 +00:00
2005-07-21 06:31:02 +00:00
i = ( sizeof ( _initial_name_letters ) + 35 ) * GB ( x , 8 , 8 ) > > 8 ;
2004-08-09 17:04:08 +00:00
if ( i < sizeof ( _initial_name_letters ) ) {
2006-10-21 23:31:34 +00:00
initial [ 0 ] = _initial_name_letters [ i ] ;
buff = strecpy ( buff , initial , last ) ;
2004-08-09 17:04:08 +00:00
}
2008-05-29 15:13:28 +00:00
if ( _settings_game . game_creation . landscape = = LT_TOYLAND ) {
2005-11-16 11:17:52 +00:00
base = _silly_surname_list ;
num = lengthof ( _silly_surname_list ) ;
} else {
base = _surname_list ;
num = lengthof ( _surname_list ) ;
2004-08-09 17:04:08 +00:00
}
2006-10-21 23:31:34 +00:00
buff = strecpy ( buff , base [ num * GB ( x , 16 , 8 ) > > 8 ] , last ) ;
2004-08-09 17:04:08 +00:00
return buff ;
}
2011-03-18 13:34:52 +00:00
static char * GetSpecialNameString ( char * buff , int ind , StringParameters * args , const char * last )
2004-08-09 17:04:08 +00:00
{
2005-02-06 11:23:41 +00:00
switch ( ind ) {
2005-02-06 16:56:04 +00:00
case 1 : // not used
2011-09-23 19:25:48 +00:00
return strecpy ( buff , _silly_company_names [ min ( args - > GetInt32 ( ) & 0xFFFF , lengthof ( _silly_company_names ) - 1 ) ] , last ) ;
2004-08-09 17:04:08 +00:00
2005-02-06 16:56:04 +00:00
case 2 : // used for Foobar & Co company names
2011-03-18 13:34:52 +00:00
return GenAndCoName ( buff , args - > GetInt32 ( ) , last ) ;
2004-08-09 17:04:08 +00:00
2005-02-06 16:56:04 +00:00
case 3 : // President name
2011-03-18 13:34:52 +00:00
return GenPresidentName ( buff , args - > GetInt32 ( ) , last ) ;
2004-08-09 17:04:08 +00:00
}
2007-04-04 01:35:16 +00:00
/* town name? */
2008-04-18 04:37:06 +00:00
if ( IsInsideMM ( ind - 6 , 0 , SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1 ) ) {
2011-03-18 13:34:52 +00:00
buff = GetSpecialTownNameString ( buff , ind - 6 , args - > GetInt32 ( ) , last ) ;
2006-10-21 23:31:34 +00:00
return strecpy ( buff , " Transport " , last ) ;
2004-08-09 17:04:08 +00:00
}
2007-04-04 01:35:16 +00:00
/* language name? */
2007-11-24 10:38:43 +00:00
if ( IsInsideMM ( ind , ( SPECSTR_LANGUAGE_START - 0x70E4 ) , ( SPECSTR_LANGUAGE_END - 0x70E4 ) + 1 ) ) {
2004-08-09 17:04:08 +00:00
int i = ind - ( SPECSTR_LANGUAGE_START - 0x70E4 ) ;
2005-05-22 07:43:18 +00:00
return strecpy ( buff ,
2010-11-13 12:09:30 +00:00
& _languages [ i ] = = _current_language ? _current_language - > own_name : _languages [ i ] . name , last ) ;
2004-08-09 17:04:08 +00:00
}
2007-04-04 01:35:16 +00:00
/* resolution size? */
2007-11-24 10:38:43 +00:00
if ( IsInsideMM ( ind , ( SPECSTR_RESOLUTION_START - 0x70E4 ) , ( SPECSTR_RESOLUTION_END - 0x70E4 ) + 1 ) ) {
2004-08-09 17:04:08 +00:00
int i = ind - ( SPECSTR_RESOLUTION_START - 0x70E4 ) ;
2008-10-28 14:42:31 +00:00
buff + = seprintf (
2009-06-27 20:53:45 +00:00
buff , last , " %ux%u " , _resolutions [ i ] . width , _resolutions [ i ] . height
2006-10-21 23:31:34 +00:00
) ;
return buff ;
2004-08-09 17:04:08 +00:00
}
2009-07-31 13:25:20 +00:00
NOT_REACHED ( ) ;
2004-08-09 17:04:08 +00:00
}
2007-06-13 17:34:05 +00:00
# ifdef ENABLE_NETWORK
2007-06-04 16:07:22 +00:00
extern void SortNetworkLanguages ( ) ;
2007-06-13 17:34:05 +00:00
# else /* ENABLE_NETWORK */
static inline void SortNetworkLanguages ( ) { }
# endif /* ENABLE_NETWORK */
2007-06-04 16:07:22 +00:00
2011-01-18 22:31:06 +00:00
/**
* Check whether the header is a valid header for OpenTTD .
* @ return true iff the header is deemed valid .
*/
2010-11-10 17:48:31 +00:00
bool LanguagePackHeader : : IsValid ( ) const
{
2010-11-20 15:44:24 +00:00
return this - > ident = = TO_LE32 ( LanguagePackHeader : : IDENT ) & &
this - > version = = TO_LE32 ( LANGUAGE_PACK_VERSION ) & &
this - > plural_form < LANGUAGE_MAX_PLURAL & &
this - > text_dir < = 1 & &
this - > newgrflangid < MAX_LANG & &
this - > num_genders < MAX_NUM_GENDERS & &
this - > num_cases < MAX_NUM_CASES & &
StrValid ( this - > name , lastof ( this - > name ) ) & &
StrValid ( this - > own_name , lastof ( this - > own_name ) ) & &
StrValid ( this - > isocode , lastof ( this - > isocode ) ) & &
StrValid ( this - > digit_group_separator , lastof ( this - > digit_group_separator ) ) & &
StrValid ( this - > digit_group_separator_currency , lastof ( this - > digit_group_separator_currency ) ) & &
StrValid ( this - > digit_decimal_separator , lastof ( this - > digit_decimal_separator ) ) ;
2010-11-10 17:48:31 +00:00
}
2011-05-02 17:42:12 +00:00
/**
* Read a particular language .
* @ param lang The metadata about the language .
* @ return Whether the loading went okay or not .
*/
2010-11-13 11:38:01 +00:00
bool ReadLanguagePack ( const LanguageMetadata * lang )
2005-02-06 11:23:41 +00:00
{
2010-02-12 23:39:44 +00:00
/* Current language pack */
2004-08-09 17:04:08 +00:00
size_t len ;
2011-02-27 06:36:14 +00:00
LanguagePack * lang_pack = ( LanguagePack * ) ReadFileToMem ( lang - > file , & len , 1U < < 20 ) ;
2010-02-12 23:39:44 +00:00
if ( lang_pack = = NULL ) return false ;
2004-08-09 17:04:08 +00:00
2010-02-12 23:39:44 +00:00
/* End of read data (+ terminating zero added in ReadFileToMem()) */
const char * end = ( char * ) lang_pack + len + 1 ;
2007-03-17 22:21:05 +00:00
2010-02-12 23:39:44 +00:00
/* We need at least one byte of lang_pack->data */
2010-11-10 17:48:31 +00:00
if ( end < = lang_pack - > data | | ! lang_pack - > IsValid ( ) ) {
2004-08-09 17:04:08 +00:00
free ( lang_pack ) ;
return false ;
}
2004-09-10 19:02:27 +00:00
2008-06-17 19:38:00 +00:00
# if TTD_ENDIAN == TTD_BIG_ENDIAN
2011-12-17 23:16:16 +00:00
for ( uint i = 0 ; i < TAB_COUNT ; i + + ) {
2006-02-03 21:51:42 +00:00
lang_pack - > offsets [ i ] = ReadLE16Aligned ( & lang_pack - > offsets [ i ] ) ;
2004-08-09 17:04:08 +00:00
}
2008-06-17 19:38:00 +00:00
# endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
2004-08-09 17:04:08 +00:00
2010-02-12 23:39:44 +00:00
uint count = 0 ;
2011-12-17 23:16:16 +00:00
for ( uint i = 0 ; i < TAB_COUNT ; i + + ) {
2013-11-23 13:18:29 +00:00
uint16 num = lang_pack - > offsets [ i ] ;
if ( num > TAB_SIZE ) {
2013-11-23 13:24:31 +00:00
free ( lang_pack ) ;
return false ;
2013-11-23 13:18:29 +00:00
}
2010-02-12 23:39:44 +00:00
_langtab_start [ i ] = count ;
2004-08-09 17:04:08 +00:00
_langtab_num [ i ] = num ;
2010-02-12 23:39:44 +00:00
count + = num ;
2004-08-09 17:04:08 +00:00
}
2007-04-04 01:35:16 +00:00
/* Allocate offsets */
2010-02-12 23:39:44 +00:00
char * * langpack_offs = MallocT < char * > ( count ) ;
2004-08-09 17:04:08 +00:00
2007-04-04 01:35:16 +00:00
/* Fill offsets */
2010-02-12 23:39:44 +00:00
char * s = lang_pack - > data ;
len = ( byte ) * s + + ;
for ( uint i = 0 ; i < count ; i + + ) {
if ( s + len > = end ) {
free ( lang_pack ) ;
free ( langpack_offs ) ;
return false ;
}
if ( len > = 0xC0 ) {
len = ( ( len & 0x3F ) < < 8 ) + ( byte ) * s + + ;
if ( s + len > = end ) {
free ( lang_pack ) ;
free ( langpack_offs ) ;
return false ;
}
}
2004-08-09 17:04:08 +00:00
langpack_offs [ i ] = s ;
s + = len ;
2010-02-12 23:39:44 +00:00
len = ( byte ) * s ;
* s + + = ' \0 ' ; // zero terminate the string
2004-08-09 17:04:08 +00:00
}
2005-02-06 16:56:04 +00:00
free ( _langpack ) ;
2004-08-09 17:04:08 +00:00
_langpack = lang_pack ;
2005-02-06 16:56:04 +00:00
free ( _langpack_offs ) ;
2004-08-09 17:04:08 +00:00
_langpack_offs = langpack_offs ;
2010-11-13 11:38:01 +00:00
_current_language = lang ;
2010-11-13 11:25:58 +00:00
_current_text_dir = ( TextDirection ) _current_language - > text_dir ;
const char * c_file = strrchr ( _current_language - > file , PATHSEPCHAR ) + 1 ;
2010-11-13 11:28:55 +00:00
strecpy ( _config_language_file , c_file , lastof ( _config_language_file ) ) ;
2010-11-13 11:25:58 +00:00
SetCurrentGrfLangID ( _current_language - > newgrflangid ) ;
2004-08-09 17:04:08 +00:00
2010-11-27 22:47:29 +00:00
# ifdef WITH_ICU
/* Delete previous collator. */
if ( _current_collator ! = NULL ) {
delete _current_collator ;
_current_collator = NULL ;
}
/* Create a collator instance for our current locale. */
UErrorCode status = U_ZERO_ERROR ;
_current_collator = Collator : : createInstance ( Locale ( _current_language - > isocode ) , status ) ;
/* Sort number substrings by their numerical value. */
if ( _current_collator ! = NULL ) _current_collator - > setAttribute ( UCOL_NUMERIC_COLLATION , UCOL_ON , status ) ;
/* Avoid using the collator if it is not correctly set. */
if ( U_FAILURE ( status ) ) {
delete _current_collator ;
_current_collator = NULL ;
}
# endif /* WITH_ICU */
2010-11-27 22:43:58 +00:00
/* Some lists need to be sorted again after a language change. */
2011-12-19 21:05:46 +00:00
ReconsiderGameScriptLanguage ( ) ;
2010-04-01 19:48:28 +00:00
InitializeSortedCargoSpecs ( ) ;
2010-03-28 12:25:09 +00:00
SortIndustryTypes ( ) ;
BuildIndustriesLegend ( ) ;
2007-06-04 16:07:22 +00:00
SortNetworkLanguages ( ) ;
2010-11-27 22:43:58 +00:00
InvalidateWindowClassesData ( WC_BUILD_VEHICLE ) ; // Build vehicle window.
InvalidateWindowClassesData ( WC_TRAINS_LIST ) ; // Train group window.
InvalidateWindowClassesData ( WC_ROADVEH_LIST ) ; // Road vehicle group window.
InvalidateWindowClassesData ( WC_SHIPS_LIST ) ; // Ship group window.
InvalidateWindowClassesData ( WC_AIRCRAFT_LIST ) ; // Aircraft group window.
InvalidateWindowClassesData ( WC_INDUSTRY_DIRECTORY ) ; // Industry directory window.
InvalidateWindowClassesData ( WC_STATION_LIST ) ; // Station list window.
2004-08-09 17:04:08 +00:00
return true ;
}
2009-03-15 00:32:18 +00:00
/* Win32 implementation in win32.cpp.
* OS X implementation in os / macosx / macos . mm . */
2007-08-11 15:52:34 +00:00
# if !(defined(WIN32) || defined(__APPLE__))
2010-08-01 19:22:34 +00:00
/**
* Determine the current charset based on the environment
2006-03-25 09:22:10 +00:00
* First check some default values , after this one we passed ourselves
* and if none exist return the value for $ LANG
2007-04-04 01:35:16 +00:00
* @ param param environment variable to check conditionally if default ones are not
2006-03-25 09:22:10 +00:00
* set . Pass NULL if you don ' t want additional checks .
2010-08-01 19:44:49 +00:00
* @ return return string containing current charset , or NULL if not - determinable
*/
2006-03-25 09:22:10 +00:00
const char * GetCurrentLocale ( const char * param )
{
const char * env ;
env = getenv ( " LANGUAGE " ) ;
if ( env ! = NULL ) return env ;
env = getenv ( " LC_ALL " ) ;
if ( env ! = NULL ) return env ;
if ( param ! = NULL ) {
env = getenv ( param ) ;
if ( env ! = NULL ) return env ;
}
return getenv ( " LANG " ) ;
}
2008-04-19 13:04:29 +00:00
# else
const char * GetCurrentLocale ( const char * param ) ;
2007-08-11 15:52:34 +00:00
# endif /* !(defined(WIN32) || defined(__APPLE__)) */
2006-03-25 09:22:10 +00:00
2009-09-13 17:38:07 +00:00
int CDECL StringIDSorter ( const StringID * a , const StringID * b )
2007-06-04 16:07:22 +00:00
{
char stra [ 512 ] ;
char strb [ 512 ] ;
2009-09-13 17:38:07 +00:00
GetString ( stra , * a , lastof ( stra ) ) ;
GetString ( strb , * b , lastof ( strb ) ) ;
2007-06-04 16:07:22 +00:00
2014-11-18 20:12:42 +00:00
return strnatcmp ( stra , strb ) ;
2007-06-04 16:07:22 +00:00
}
2007-03-17 22:21:05 +00:00
/**
2010-11-13 19:10:30 +00:00
* Get the language with the given NewGRF language ID .
* @ param newgrflangid NewGRF languages ID to check .
* @ return The language ' s metadata , or NULL if it is not known .
2007-03-17 22:21:05 +00:00
*/
2010-11-13 19:10:30 +00:00
const LanguageMetadata * GetLanguage ( byte newgrflangid )
2007-03-17 22:21:05 +00:00
{
2010-11-13 12:09:30 +00:00
for ( const LanguageMetadata * lang = _languages . Begin ( ) ; lang ! = _languages . End ( ) ; lang + + ) {
2010-11-13 19:10:30 +00:00
if ( newgrflangid = = lang - > newgrflangid ) return lang ;
2007-03-17 22:21:05 +00:00
}
2010-11-13 19:10:30 +00:00
return NULL ;
2007-03-17 22:21:05 +00:00
}
/**
2012-01-01 17:22:32 +00:00
* Reads the language file header and checks compatibility .
2007-03-17 22:21:05 +00:00
* @ param file the file to read
* @ param hdr the place to write the header information to
* @ return true if and only if the language file is of a compatible version
*/
2010-11-13 11:11:02 +00:00
static bool GetLanguageFileHeader ( const char * file , LanguagePackHeader * hdr )
2007-03-17 22:21:05 +00:00
{
FILE * f = fopen ( file , " rb " ) ;
if ( f = = NULL ) return false ;
size_t read = fread ( hdr , sizeof ( * hdr ) , 1 , f ) ;
fclose ( f ) ;
2010-11-10 17:48:31 +00:00
bool ret = read = = 1 & & hdr - > IsValid ( ) ;
2008-11-24 18:53:17 +00:00
/* Convert endianness for the windows language ID */
2011-08-21 19:21:38 +00:00
if ( ret ) {
hdr - > missing = FROM_LE16 ( hdr - > missing ) ;
hdr - > winlangid = FROM_LE16 ( hdr - > winlangid ) ;
}
2008-11-24 18:53:17 +00:00
return ret ;
2006-08-04 23:45:20 +00:00
}
2007-03-17 22:21:05 +00:00
/**
* Gets a list of languages from the given directory .
* @ param path the base directory to search in
*/
2010-11-13 12:09:30 +00:00
static void GetLanguageList ( const char * path )
2006-08-04 23:45:20 +00:00
{
2007-03-17 22:21:05 +00:00
DIR * dir = ttd_opendir ( path ) ;
2006-08-04 23:45:20 +00:00
if ( dir ! = NULL ) {
2007-03-17 22:21:05 +00:00
struct dirent * dirent ;
2010-11-13 12:09:30 +00:00
while ( ( dirent = readdir ( dir ) ) ! = NULL ) {
2007-03-17 22:21:05 +00:00
const char * d_name = FS2OTTD ( dirent - > d_name ) ;
const char * extension = strrchr ( d_name , ' . ' ) ;
2006-08-04 23:45:20 +00:00
2007-03-17 22:21:05 +00:00
/* Not a language file */
if ( extension = = NULL | | strcmp ( extension , " .lng " ) ! = 0 ) continue ;
2010-11-13 12:09:30 +00:00
LanguageMetadata lmd ;
seprintf ( lmd . file , lastof ( lmd . file ) , " %s%s " , path , d_name ) ;
2007-03-17 22:21:05 +00:00
/* Check whether the file is of the correct version */
2010-11-13 12:09:30 +00:00
if ( ! GetLanguageFileHeader ( lmd . file , & lmd ) ) {
DEBUG ( misc , 3 , " %s is not a valid language file " , lmd . file ) ;
2010-11-13 19:10:30 +00:00
} else if ( GetLanguage ( lmd . newgrflangid ) ! = NULL ) {
2010-11-13 12:09:30 +00:00
DEBUG ( misc , 3 , " %s's language ID is already known " , lmd . file ) ;
} else {
* _languages . Append ( ) = lmd ;
2006-08-04 23:45:20 +00:00
}
}
closedir ( dir ) ;
}
}
2007-03-17 22:21:05 +00:00
/**
2012-01-01 17:22:32 +00:00
* Make a list of the available language packs . Put the data in
* # _languages list .
2007-03-17 22:21:05 +00:00
*/
2007-03-07 11:47:46 +00:00
void InitializeLanguagePacks ( )
2004-08-09 17:04:08 +00:00
{
2007-06-17 15:48:57 +00:00
Searchpath sp ;
FOR_ALL_SEARCHPATHS ( sp ) {
char path [ MAX_PATH ] ;
2014-04-23 21:23:21 +00:00
FioAppendDirectory ( path , lastof ( path ) , sp , LANG_DIR ) ;
2010-11-13 12:09:30 +00:00
GetLanguageList ( path ) ;
2007-06-17 15:48:57 +00:00
}
2010-11-13 12:09:30 +00:00
if ( _languages . Length ( ) = = 0 ) usererror ( " No available language packs (invalid versions?) " ) ;
2004-08-09 17:04:08 +00:00
2007-03-17 22:21:05 +00:00
/* Acquire the locale of the current system */
const char * lang = GetCurrentLocale ( " LC_MESSAGES " ) ;
if ( lang = = NULL ) lang = " en_GB " ;
2004-09-10 19:02:27 +00:00
2012-01-01 17:22:32 +00:00
const LanguageMetadata * chosen_language = NULL ; ///< Matching the language in the configuration file or the current locale
2010-11-13 11:38:01 +00:00
const LanguageMetadata * language_fallback = NULL ; ///< Using pt_PT for pt_BR locale when pt_BR is not available
2010-11-13 12:09:30 +00:00
const LanguageMetadata * en_GB_fallback = _languages . Begin ( ) ; ///< Fallback when no locale-matching language has been found
2004-08-09 17:04:08 +00:00
2010-11-13 12:09:30 +00:00
/* Find a proper language. */
for ( const LanguageMetadata * lng = _languages . Begin ( ) ; lng ! = _languages . End ( ) ; lng + + ) {
2007-03-17 22:21:05 +00:00
/* We are trying to find a default language. The priority is by
* configuration file , local environment and last , if nothing found ,
2012-01-01 17:22:32 +00:00
* English . */
2010-11-13 12:09:30 +00:00
const char * lang_file = strrchr ( lng - > file , PATHSEPCHAR ) + 1 ;
2010-11-13 11:38:01 +00:00
if ( strcmp ( lang_file , _config_language_file ) = = 0 ) {
chosen_language = lng ;
break ;
2007-03-17 22:21:05 +00:00
}
2010-11-13 11:38:01 +00:00
if ( strcmp ( lng - > isocode , " en_GB " ) = = 0 ) en_GB_fallback = lng ;
if ( strncmp ( lng - > isocode , lang , 5 ) = = 0 ) chosen_language = lng ;
if ( strncmp ( lng - > isocode , lang , 2 ) = = 0 ) language_fallback = lng ;
2007-03-17 22:21:05 +00:00
}
2004-09-10 19:02:27 +00:00
2007-03-17 22:21:05 +00:00
/* We haven't found the language in the config nor the one in the locale.
* Now we set it to one of the fallback languages */
2010-11-13 11:38:01 +00:00
if ( chosen_language = = NULL ) {
chosen_language = ( language_fallback ! = NULL ) ? language_fallback : en_GB_fallback ;
2007-03-17 22:21:05 +00:00
}
2004-08-09 17:04:08 +00:00
2010-11-13 11:38:01 +00:00
if ( ! ReadLanguagePack ( chosen_language ) ) usererror ( " Can't read language pack '%s' " , chosen_language - > file ) ;
2005-07-15 21:28:26 +00:00
}
2007-12-16 18:38:19 +00:00
2009-10-17 20:34:09 +00:00
/**
* Get the ISO language code of the currently loaded language .
* @ return the ISO code .
*/
const char * GetCurrentLanguageIsoCode ( )
{
return _langpack - > isocode ;
}
2010-08-02 12:10:48 +00:00
/**
* Check whether there are glyphs missing in the current language .
* @ param Pointer to an address for storing the text pointer .
2012-01-01 17:36:19 +00:00
* @ return If glyphs are missing , return \ c true , else return \ c false .
2010-11-23 17:59:50 +00:00
* @ post If \ c true is returned and str is not NULL , * str points to a string that is found to contain at least one missing glyph .
2010-08-02 12:10:48 +00:00
*/
2011-11-19 18:43:00 +00:00
bool MissingGlyphSearcher : : FindMissingGlyphs ( const char * * str )
2010-08-02 12:10:48 +00:00
{
2011-11-20 12:01:42 +00:00
InitFreeType ( this - > Monospace ( ) ) ;
2010-11-25 15:20:10 +00:00
const Sprite * question_mark [ FS_END ] ;
2011-12-10 12:56:37 +00:00
for ( FontSize size = this - > Monospace ( ) ? FS_MONO : FS_BEGIN ; size < ( this - > Monospace ( ) ? FS_END : FS_MONO ) ; size + + ) {
2010-11-25 15:20:10 +00:00
question_mark [ size ] = GetGlyph ( size , ' ? ' ) ;
}
2011-11-19 18:43:00 +00:00
this - > Reset ( ) ;
for ( const char * text = this - > NextString ( ) ; text ! = NULL ; text = this - > NextString ( ) ) {
FontSize size = this - > DefaultSize ( ) ;
if ( str ! = NULL ) * str = text ;
for ( WChar c = Utf8Consume ( & text ) ; c ! = ' \0 ' ; c = Utf8Consume ( & text ) ) {
2013-06-24 18:39:19 +00:00
if ( c = = SCC_TINYFONT ) {
2011-11-19 18:43:00 +00:00
size = FS_SMALL ;
} else if ( c = = SCC_BIGFONT ) {
size = FS_LARGE ;
} else if ( ! IsInsideMM ( c , SCC_SPRITE_START , SCC_SPRITE_END ) & & IsPrintable ( c ) & & ! IsTextDirectionChar ( c ) & & c ! = ' ? ' & & GetGlyph ( size , c ) = = question_mark [ size ] ) {
/* The character is printable, but not in the normal font. This is the case we were testing for. */
return true ;
2010-08-02 12:10:48 +00:00
}
}
}
return false ;
}
2011-11-19 18:43:00 +00:00
/** Helper for searching through the language pack. */
class LanguagePackGlyphSearcher : public MissingGlyphSearcher {
uint i ; ///< Iterator for the primary language tables.
uint j ; ///< Iterator for the secondary language tables.
/* virtual */ void Reset ( )
{
this - > i = 0 ;
this - > j = 0 ;
}
2011-11-19 21:02:37 +00:00
/* virtual */ FontSize DefaultSize ( )
2011-11-19 18:43:00 +00:00
{
return FS_NORMAL ;
}
2011-11-19 21:02:37 +00:00
/* virtual */ const char * NextString ( )
2011-11-19 18:43:00 +00:00
{
2011-12-17 23:16:16 +00:00
if ( this - > i > = TAB_COUNT ) return NULL ;
2011-11-19 18:43:00 +00:00
2013-01-14 21:16:56 +00:00
const char * ret = _langpack_offs [ _langtab_start [ this - > i ] + this - > j ] ;
2011-11-19 18:43:00 +00:00
this - > j + + ;
2013-01-14 21:16:56 +00:00
while ( this - > i < TAB_COUNT & & this - > j > = _langtab_num [ this - > i ] ) {
this - > i + + ;
this - > j = 0 ;
2011-11-19 18:43:00 +00:00
}
return ret ;
}
2011-11-19 21:02:37 +00:00
2011-11-20 12:01:42 +00:00
/* virtual */ bool Monospace ( )
{
return false ;
}
2011-11-19 21:02:37 +00:00
/* virtual */ void SetFontNames ( FreeTypeSettings * settings , const char * font_name )
{
2011-11-19 22:27:53 +00:00
# ifdef WITH_FREETYPE
2013-06-23 15:23:22 +00:00
strecpy ( settings - > small . font , font_name , lastof ( settings - > small . font ) ) ;
strecpy ( settings - > medium . font , font_name , lastof ( settings - > medium . font ) ) ;
strecpy ( settings - > large . font , font_name , lastof ( settings - > large . font ) ) ;
2011-11-19 22:27:53 +00:00
# endif /* WITH_FREETYPE */
2011-11-19 21:02:37 +00:00
}
2011-11-19 18:43:00 +00:00
} ;
2007-12-16 18:38:19 +00:00
/**
* Check whether the currently loaded language pack
* uses characters that the currently loaded font
* does not support . If this is the case an error
* message will be shown in English . The error
* message will not be localized because that would
* mean it might use characters that are not in the
* font , which is the whole reason this check has
* been added .
2011-11-17 21:11:34 +00:00
* @ param base_font Whether to look at the base font as well .
2011-11-20 11:52:11 +00:00
* @ param searcher The methods to use to search for strings to check .
* If NULL the loaded language pack searcher is used .
2007-12-16 18:38:19 +00:00
*/
2011-11-20 11:52:11 +00:00
void CheckForMissingGlyphs ( bool base_font , MissingGlyphSearcher * searcher )
2007-12-16 18:38:19 +00:00
{
2011-11-20 11:52:11 +00:00
static LanguagePackGlyphSearcher pack_searcher ;
if ( searcher = = NULL ) searcher = & pack_searcher ;
bool bad_font = ! base_font | | searcher - > FindMissingGlyphs ( NULL ) ;
2008-11-24 18:53:17 +00:00
# ifdef WITH_FREETYPE
2010-08-02 12:10:48 +00:00
if ( bad_font ) {
/* We found an unprintable character... lets try whether we can find
* a fallback font that can print the characters in the current language . */
FreeTypeSettings backup ;
memcpy ( & backup , & _freetype , sizeof ( backup ) ) ;
2011-11-20 11:52:11 +00:00
bad_font = ! SetFallbackFont ( & _freetype , _langpack - > isocode , _langpack - > winlangid , searcher ) ;
2008-11-24 18:53:17 +00:00
2010-08-02 12:10:48 +00:00
memcpy ( & _freetype , & backup , sizeof ( backup ) ) ;
2008-11-24 18:53:17 +00:00
2011-11-17 21:11:34 +00:00
if ( bad_font & & base_font ) {
2010-11-23 17:59:50 +00:00
/* Our fallback font does miss characters too, so keep the
2011-01-21 01:38:30 +00:00
* user chosen font as that is more likely to be any good than
* the wild guess we made */
2011-11-20 12:01:42 +00:00
InitFreeType ( searcher - > Monospace ( ) ) ;
2007-12-16 18:38:19 +00:00
}
2010-08-02 12:10:48 +00:00
}
# endif
if ( bad_font ) {
/* All attempts have failed. Display an error. As we do not want the string to be translated by
* the translators , we ' force ' it into the binary and ' load ' it via a BindCString . To do this
2013-01-08 22:46:42 +00:00
* properly we have to set the colour of the string , otherwise we end up with a lot of artifacts .
2010-08-02 12:10:48 +00:00
* The colour ' character ' might change in the future , so for safety we just Utf8 Encode it into
* the string , which takes exactly three characters , so it replaces the " XXX " with the colour marker . */
2014-04-25 15:40:32 +00:00
static char * err_str = stredup ( " XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this. " ) ;
2010-08-02 12:10:48 +00:00
Utf8Encode ( err_str , SCC_YELLOW ) ;
SetDParamStr ( 0 , err_str ) ;
ShowErrorMessage ( STR_JUST_RAW_STRING , INVALID_STRING_ID , WL_WARNING ) ;
/* Reset the font width */
2011-12-10 12:56:37 +00:00
LoadStringWidthTable ( searcher - > Monospace ( ) ) ;
2010-08-02 12:10:48 +00:00
return ;
2007-12-16 18:38:19 +00:00
}
2008-10-17 17:42:51 +00:00
2009-02-23 18:14:18 +00:00
/* Update the font with cache */
2011-12-10 12:56:37 +00:00
LoadStringWidthTable ( searcher - > Monospace ( ) ) ;
2009-02-23 18:14:18 +00:00
2008-10-17 17:42:51 +00:00
# if !defined(WITH_ICU)
/*
* For right - to - left languages we need the ICU library . If
* we do not have support for that library we warn the user
* about it with a message . As we do not want the string to
* be translated by the translators , we ' force ' it into the
* binary and ' load ' it via a BindCString . To do this
2009-02-09 02:57:15 +00:00
* properly we have to set the colour of the string ,
2013-01-08 22:46:42 +00:00
* otherwise we end up with a lot of artifacts . The colour
2008-10-17 17:42:51 +00:00
* ' character ' might change in the future , so for safety
* we just Utf8 Encode it into the string , which takes
* exactly three characters , so it replaces the " XXX " with
2009-02-09 02:57:15 +00:00
* the colour marker .
2008-10-17 17:42:51 +00:00
*/
2010-11-13 09:56:25 +00:00
if ( _current_text_dir ! = TD_LTR ) {
2014-04-25 15:40:32 +00:00
static char * err_str = stredup ( " XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled. " ) ;
2008-10-17 17:42:51 +00:00
Utf8Encode ( err_str , SCC_YELLOW ) ;
SetDParamStr ( 0 , err_str ) ;
2010-02-24 14:46:15 +00:00
ShowErrorMessage ( STR_JUST_RAW_STRING , INVALID_STRING_ID , WL_ERROR ) ;
2008-10-17 17:42:51 +00:00
}
# endif
2007-12-16 18:38:19 +00:00
}