mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r7182) -Feature: Merge utf8 branch. This brings us support for Unicode/UTF-8 and the option for fonts rendered by FreeType. Language changes to come.
This commit is contained in:
parent
40d647ddde
commit
1a4f1c8177
18
Makefile
18
Makefile
|
@ -235,6 +235,12 @@ $(error WITH_PNG can't be used when LIBPNG_CONFIG is not set. Edit Makefile.conf
|
|||
endif
|
||||
endif
|
||||
|
||||
ifdef WITH_FREETYPE
|
||||
ifndef FREETYPE_CONFIG
|
||||
$(error WITH_FREETYPE can't be used when FREETYPE_CONFIG is not set. Edit Makefile.config to correct this)
|
||||
endif
|
||||
endif
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Compiler configuration
|
||||
|
@ -493,6 +499,15 @@ ifndef MINGW
|
|||
LIBS += -lc
|
||||
endif
|
||||
|
||||
# freetype config
|
||||
ifdef WITH_FREETYPE
|
||||
CDEFS += -DWITH_FREETYPE
|
||||
CCFLAGS_FREETYPE := $(shell $(FREETYPE_CONFIG) --cflags)
|
||||
LDFLAGS_FREETYPE := $(shell $(FREETYPE_CONFIG) --libs)
|
||||
CFLAGS += $(CCFLAGS_FREETYPE)
|
||||
LIBS += $(LDFLAGS_FREETYPE)
|
||||
endif
|
||||
|
||||
# iconv is enabled defaultly on OSX >= 10.3
|
||||
ifdef OSX
|
||||
ifndef JAGUAR
|
||||
|
@ -670,6 +685,7 @@ SRCS += engine.c
|
|||
SRCS += engine_gui.c
|
||||
SRCS += fileio.c
|
||||
SRCS += fios.c
|
||||
SRCS += fontcache.c
|
||||
SRCS += genworld.c
|
||||
SRCS += genworld_gui.c
|
||||
SRCS += gfx.c
|
||||
|
@ -884,7 +900,7 @@ $(TTD): $(OBJS) $(MAKE_CONFIG)
|
|||
$(Q)$(CXX_TARGET) $(LDFLAGS) $(TTDLDFLAGS) $(OBJS) $(LIBS) -o $@
|
||||
endif
|
||||
|
||||
$(STRGEN): strgen/strgen.c string.c endian_host.h
|
||||
$(STRGEN): strgen/strgen.c string.c endian_host.h table/control_codes.h
|
||||
@echo '===> Compiling and Linking $@'
|
||||
$(Q)$(CC_HOST) $(CFLAGS_HOST) -DSTRGEN strgen/strgen.c string.c -o $@
|
||||
|
||||
|
|
|
@ -35,11 +35,13 @@ function showhelp() {
|
|||
echo " iconv Do you want iconv-support? [no]"
|
||||
echo " network Do you want network-support? [yes]"
|
||||
echo " cocoa Do you want cocoa-support? (MacOSX) [no]"
|
||||
echo " freetype Do you want freetype-support? [yes]"
|
||||
echo ""
|
||||
echo "Params used to configure external libs:"
|
||||
echo " --static-zlib-path Set the path to your static zlib []"
|
||||
echo " --sdl-config Where is your sdl-config [sdl-config]"
|
||||
echo " --libpng-config Where is your libpng-config [libpng-config]"
|
||||
echo " --freetype-config Where is your freetype-config [freetype-config]"
|
||||
echo " --with-iconv Set the path to your iconv headers []"
|
||||
echo " "
|
||||
}
|
||||
|
@ -181,6 +183,12 @@ do
|
|||
--without-cocoa)
|
||||
PARAM="$PARAM WITH_COCOA="
|
||||
;;
|
||||
--with-freetype)
|
||||
PARAM="$PARAM WITH_FREETYPE=1"
|
||||
;;
|
||||
--without-freetype)
|
||||
PARAM="$PARAM WITH_FREETYPE="
|
||||
;;
|
||||
--static-zlib-path=*)
|
||||
handle STATIC_ZLIB_PATH "$n"
|
||||
;;
|
||||
|
@ -199,6 +207,12 @@ do
|
|||
--libpng-config)
|
||||
ITEM="LIBPNG_CONFIG"
|
||||
;;
|
||||
--freetype-config=*)
|
||||
handle FREETYPE_CONFIG "$n"
|
||||
;;
|
||||
--freetype-config)
|
||||
ITEM="FREETYPE_CONFIG"
|
||||
;;
|
||||
|
||||
--*=*)
|
||||
echo -n "Unknown switch "
|
||||
|
|
|
@ -181,9 +181,9 @@ static void IConsoleWndProc(Window *w, WindowEvent *e)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
if (IsValidAsciiChar(e->we.keypress.ascii, CS_ALPHANUMERAL)) {
|
||||
if (IsValidChar(e->we.keypress.key, CS_ALPHANUMERAL)) {
|
||||
_iconsole_scroll = ICON_BUFFER;
|
||||
InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.ascii);
|
||||
InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.key);
|
||||
IConsoleResetHistoryPos();
|
||||
SetWindowDirty(w);
|
||||
} else {
|
||||
|
@ -1057,7 +1057,7 @@ void IConsoleCmdExec(const char *cmdstr)
|
|||
if (cmdstr[0] == '#') return; // comments
|
||||
|
||||
for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) {
|
||||
if (!IsValidAsciiChar(*cmdptr, CS_ALPHANUMERAL)) {
|
||||
if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) {
|
||||
IConsoleError("command contains malformed characters, aborting");
|
||||
IConsolePrintF(_icolour_err, "ERROR: command was: '%s'", cmdstr);
|
||||
return;
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
// | | Euro year | | | name
|
||||
// | | | | | | |
|
||||
static const CurrencySpec origin_currency_specs[NUM_CURRENCY] = {
|
||||
{ 1, ',', CF_NOEURO, "\xA3", "", 0, STR_CURR_GBP }, // british pounds
|
||||
{ 1, ',', CF_NOEURO, "£", "", 0, STR_CURR_GBP }, // british pounds
|
||||
{ 2, ',', CF_NOEURO, "$", "", 0, STR_CURR_USD }, // us dollars
|
||||
{ 2, ',', CF_ISEURO, "¤", "", 0, STR_CURR_EUR }, // Euro
|
||||
{ 220, ',', CF_NOEURO, "\xA5", "", 0, STR_CURR_YEN }, // yen
|
||||
{ 2, ',', CF_ISEURO, "€", "", 0, STR_CURR_EUR }, // Euro
|
||||
{ 220, ',', CF_NOEURO, "¥", "", 0, STR_CURR_YEN }, // yen
|
||||
{ 20, ',', 2002, "", " S.", 1, STR_CURR_ATS }, // austrian schilling
|
||||
{ 59, ',', 2002, "BEF ", "", 0, STR_CURR_BEF }, // belgian franc
|
||||
{ 2, ',', CF_NOEURO, "CHF ", "", 0, STR_CURR_CHF }, // swiss franc
|
||||
{ 41, ',', CF_NOEURO, "", " Kc", 1, STR_CURR_CZK }, // czech koruna // TODO: Should use the "c" with an upside down "^"
|
||||
{ 41, ',', CF_NOEURO, "", " Kč", 1, STR_CURR_CZK }, // czech koruna
|
||||
{ 3, '.', 2002, "DM ", "", 0, STR_CURR_DEM }, // deutsche mark
|
||||
{ 11, '.', CF_NOEURO, "", " kr", 1, STR_CURR_DKK }, // danish krone
|
||||
{ 245, '.', 2002, "Pts ", "", 0, STR_CURR_ESP }, // spanish pesetas
|
||||
|
|
4
debug.c
4
debug.c
|
@ -21,6 +21,7 @@ int _debug_oldloader_level;
|
|||
int _debug_ntp_level;
|
||||
int _debug_npf_level;
|
||||
int _debug_yapf_level;
|
||||
int _debug_freetype_level;
|
||||
|
||||
|
||||
void CDECL debug(const char *s, ...)
|
||||
|
@ -53,7 +54,8 @@ typedef struct DebugLevel {
|
|||
DEBUG_LEVEL(oldloader),
|
||||
DEBUG_LEVEL(ntp),
|
||||
DEBUG_LEVEL(npf),
|
||||
DEBUG_LEVEL(yapf)
|
||||
DEBUG_LEVEL(yapf),
|
||||
DEBUG_LEVEL(freetype)
|
||||
};
|
||||
#undef DEBUG_LEVEL
|
||||
|
||||
|
|
1
debug.h
1
debug.h
|
@ -20,6 +20,7 @@
|
|||
extern int _debug_ntp_level;
|
||||
extern int _debug_npf_level;
|
||||
extern int _debug_yapf_level;
|
||||
extern int _debug_freetype_level;
|
||||
#endif
|
||||
|
||||
void CDECL debug(const char *s, ...);
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
/* $Id$ */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "openttd.h"
|
||||
#include "functions.h"
|
||||
#include "macros.h"
|
||||
#include "debug.h"
|
||||
#include "table/sprites.h"
|
||||
#include "table/control_codes.h"
|
||||
#include "spritecache.h"
|
||||
#include "gfx.h"
|
||||
#include "string.h"
|
||||
#include "fontcache.h"
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_GLYPH_H
|
||||
|
||||
static FT_Library _library = NULL;
|
||||
static FT_Face _face_small = NULL;
|
||||
static FT_Face _face_medium = NULL;
|
||||
static FT_Face _face_large = NULL;
|
||||
|
||||
FreeTypeSettings _freetype;
|
||||
|
||||
enum {
|
||||
FACE_COLOUR = 1,
|
||||
SHADOW_COLOUR = 2,
|
||||
};
|
||||
|
||||
|
||||
static void LoadFreeTypeFont(const char *font_name, FT_Face *face, const char *type)
|
||||
{
|
||||
FT_Error error;
|
||||
|
||||
if (strlen(font_name) == 0) return;
|
||||
|
||||
error = FT_New_Face(_library, font_name, 0, face);
|
||||
if (error == FT_Err_Ok) {
|
||||
/* Attempt to select the unicode character map */
|
||||
error = FT_Select_Charmap(*face, ft_encoding_unicode);
|
||||
if (error == FT_Err_Ok) {
|
||||
/* Success */
|
||||
return;
|
||||
} else if (error == FT_Err_Invalid_CharMap_Handle) {
|
||||
/* Try to pick a different character map instead. We default to
|
||||
* the first map, but platform_id 0 encoding_id 0 should also
|
||||
* be unicode (strange system...) */
|
||||
FT_CharMap found = (*face)->charmaps[0];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (*face)->num_charmaps; i++) {
|
||||
FT_CharMap charmap = (*face)->charmaps[i];
|
||||
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
|
||||
found = charmap;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != NULL) {
|
||||
error = FT_Set_Charmap(*face, found);
|
||||
if (error == FT_Err_Ok) return;
|
||||
}
|
||||
}
|
||||
|
||||
FT_Done_Face(*face);
|
||||
*face = NULL;
|
||||
}
|
||||
|
||||
ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", font_name, type, error);
|
||||
}
|
||||
|
||||
|
||||
void InitFreeType(void)
|
||||
{
|
||||
if (strlen(_freetype.small_font) == 0 && strlen(_freetype.medium_font) == 0 && strlen(_freetype.large_font) == 0) {
|
||||
DEBUG(freetype, 1) ("[FreeType] No font faces specified, using sprite fonts instead");
|
||||
return;
|
||||
}
|
||||
|
||||
if (FT_Init_FreeType(&_library) != FT_Err_Ok) {
|
||||
ShowInfoF("Unable to initialize FreeType, using sprite fonts instead");
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(freetype, 2) ("[FreeType] Initialized");
|
||||
|
||||
/* Load each font */
|
||||
LoadFreeTypeFont(_freetype.small_font, &_face_small, "small");
|
||||
LoadFreeTypeFont(_freetype.medium_font, &_face_medium, "medium");
|
||||
LoadFreeTypeFont(_freetype.large_font, &_face_large, "large");
|
||||
|
||||
/* Set each font size */
|
||||
if (_face_small != NULL) FT_Set_Pixel_Sizes(_face_small, 0, _freetype.small_size);
|
||||
if (_face_medium != NULL) FT_Set_Pixel_Sizes(_face_medium, 0, _freetype.medium_size);
|
||||
if (_face_large != NULL) FT_Set_Pixel_Sizes(_face_large, 0, _freetype.large_size);
|
||||
}
|
||||
|
||||
|
||||
static FT_Face GetFontFace(FontSize size)
|
||||
{
|
||||
switch (size) {
|
||||
default: NOT_REACHED();
|
||||
case FS_NORMAL: return _face_medium;
|
||||
case FS_SMALL: return _face_small;
|
||||
case FS_LARGE: return _face_large;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct GlyphEntry {
|
||||
Sprite *sprite;
|
||||
byte width;
|
||||
} GlyphEntry;
|
||||
|
||||
|
||||
/* The glyph cache. This is structured to reduce memory consumption.
|
||||
* 1) There is a 'segment' table for each font size.
|
||||
* 2) Each segment table is a discrete block of characters.
|
||||
* 3) Each block contains 256 (aligned) characters sequential characters.
|
||||
*
|
||||
* The cache is accessed in the following way:
|
||||
* For character 0x0041 ('A'): _glyph_ptr[FS_NORMAL][0x00][0x41]
|
||||
* For character 0x20AC (Euro): _glyph_ptr[FS_NORMAL][0x20][0xAC]
|
||||
*
|
||||
* Currently only 256 segments are allocated, "limiting" us to 65536 characters.
|
||||
* This can be simply changed in the two functions Get & SetGlyphPtr.
|
||||
*/
|
||||
static GlyphEntry **_glyph_ptr[FS_END];
|
||||
|
||||
|
||||
static GlyphEntry *GetGlyphPtr(FontSize size, WChar key)
|
||||
{
|
||||
if (_glyph_ptr[size] == NULL) return NULL;
|
||||
if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) return NULL;
|
||||
return &_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)];
|
||||
}
|
||||
|
||||
|
||||
static void SetGlyphPtr(FontSize size, WChar key, const GlyphEntry *glyph)
|
||||
{
|
||||
if (_glyph_ptr[size] == NULL) {
|
||||
DEBUG(freetype, 3) ("[FreeType] Allocating root glyph cache for size %u", size);
|
||||
_glyph_ptr[size] = calloc(256, sizeof(**_glyph_ptr));
|
||||
}
|
||||
|
||||
if (_glyph_ptr[size][GB(key, 8, 8)] == NULL) {
|
||||
DEBUG(freetype, 3) ("[FreeType] Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), size);
|
||||
_glyph_ptr[size][GB(key, 8, 8)] = calloc(256, sizeof(***_glyph_ptr));
|
||||
}
|
||||
|
||||
DEBUG(freetype, 4) ("[FreeType] Set glyph for unicode character 0x%04X, size %u", key, size);
|
||||
_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite;
|
||||
_glyph_ptr[size][GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width;
|
||||
}
|
||||
|
||||
|
||||
const Sprite *GetGlyph(FontSize size, WChar key)
|
||||
{
|
||||
FT_Face face = GetFontFace(size);
|
||||
FT_GlyphSlot slot;
|
||||
GlyphEntry new_glyph;
|
||||
GlyphEntry *glyph;
|
||||
Sprite *sprite;
|
||||
int width;
|
||||
int height;
|
||||
int x;
|
||||
int y;
|
||||
int y_adj;
|
||||
|
||||
assert(IsPrintable(key));
|
||||
|
||||
/* Bail out if no face loaded, or for our special characters */
|
||||
if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
|
||||
SpriteID sprite = GetUnicodeGlyph(size, key);
|
||||
if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
|
||||
return GetSprite(sprite);
|
||||
}
|
||||
|
||||
/* Check for the glyph in our cache */
|
||||
glyph = GetGlyphPtr(size, key);
|
||||
if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;
|
||||
|
||||
slot = face->glyph;
|
||||
|
||||
FT_Load_Char(face, key, FT_LOAD_DEFAULT);
|
||||
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);
|
||||
|
||||
/* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
|
||||
width = max(1, slot->bitmap.width + (size == FS_NORMAL));
|
||||
height = max(1, slot->bitmap.rows + (size == FS_NORMAL));
|
||||
|
||||
/* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
|
||||
sprite = calloc(width * height + 8, 1);
|
||||
sprite->info = 1;
|
||||
sprite->width = width;
|
||||
sprite->height = height;
|
||||
sprite->x_offs = slot->bitmap_left;
|
||||
// XXX 2 should be determined somehow... it's right for the normal face
|
||||
y_adj = (size == FS_NORMAL) ? 2 : 0;
|
||||
sprite->y_offs = GetCharacterHeight(size) - slot->bitmap_top - y_adj;
|
||||
|
||||
/* Draw shadow for medium size */
|
||||
if (size == FS_NORMAL) {
|
||||
for (y = 0; y < slot->bitmap.rows; y++) {
|
||||
for (x = 0; x < slot->bitmap.width; x++) {
|
||||
if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
|
||||
sprite->data[1 + x + (1 + y) * sprite->width] = SHADOW_COLOUR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (y = 0; y < slot->bitmap.rows; y++) {
|
||||
for (x = 0; x < slot->bitmap.width; x++) {
|
||||
if (HASBIT(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
|
||||
sprite->data[x + y * sprite->width] = FACE_COLOUR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_glyph.sprite = sprite;
|
||||
new_glyph.width = (slot->advance.x >> 6) + (size != FS_NORMAL);
|
||||
|
||||
SetGlyphPtr(size, key, &new_glyph);
|
||||
|
||||
return sprite;
|
||||
}
|
||||
|
||||
|
||||
uint GetGlyphWidth(FontSize size, WChar key)
|
||||
{
|
||||
FT_Face face = GetFontFace(size);
|
||||
GlyphEntry *glyph;
|
||||
|
||||
if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
|
||||
SpriteID sprite = GetUnicodeGlyph(size, key);
|
||||
if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
|
||||
return SpriteExists(sprite) ? GetSprite(sprite)->width + (size != FS_NORMAL) : 0;
|
||||
}
|
||||
|
||||
glyph = GetGlyphPtr(size, key);
|
||||
if (glyph == NULL || glyph->sprite == NULL) {
|
||||
GetGlyph(size, key);
|
||||
glyph = GetGlyphPtr(size, key);
|
||||
}
|
||||
|
||||
return glyph->width;
|
||||
}
|
||||
|
||||
|
||||
#endif /* WITH_FREETYPE */
|
||||
|
||||
/* Sprite based glyph mapping */
|
||||
|
||||
#include "table/unicode.h"
|
||||
|
||||
static SpriteID **_unicode_glyph_map[FS_END];
|
||||
|
||||
|
||||
/** Get the SpriteID of the first glyph for the given font size */
|
||||
static SpriteID GetFontBase(FontSize size)
|
||||
{
|
||||
switch (size) {
|
||||
default: NOT_REACHED();
|
||||
case FS_NORMAL: return SPR_ASCII_SPACE;
|
||||
case FS_SMALL: return SPR_ASCII_SPACE_SMALL;
|
||||
case FS_LARGE: return SPR_ASCII_SPACE_BIG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SpriteID GetUnicodeGlyph(FontSize size, uint32 key)
|
||||
{
|
||||
if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) return 0;
|
||||
return _unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)];
|
||||
}
|
||||
|
||||
|
||||
void SetUnicodeGlyph(FontSize size, uint32 key, SpriteID sprite)
|
||||
{
|
||||
if (_unicode_glyph_map[size] == NULL) _unicode_glyph_map[size] = calloc(256, sizeof(*_unicode_glyph_map[size]));
|
||||
if (_unicode_glyph_map[size][GB(key, 8, 8)] == NULL) _unicode_glyph_map[size][GB(key, 8, 8)] = calloc(256, sizeof(**_unicode_glyph_map[size]));
|
||||
_unicode_glyph_map[size][GB(key, 8, 8)][GB(key, 0, 8)] = sprite;
|
||||
}
|
||||
|
||||
|
||||
void InitializeUnicodeGlyphMap(void)
|
||||
{
|
||||
FontSize size;
|
||||
SpriteID base;
|
||||
SpriteID sprite;
|
||||
uint i;
|
||||
|
||||
for (size = FS_NORMAL; size != FS_END; size++) {
|
||||
base = GetFontBase(size);
|
||||
for (i = ASCII_LETTERSTART; i < 256; i++) {
|
||||
sprite = base + i - ASCII_LETTERSTART;
|
||||
if (!SpriteExists(sprite)) continue;
|
||||
SetUnicodeGlyph(size, i, sprite);
|
||||
SetUnicodeGlyph(size, i + SCC_SPRITE_START, sprite);
|
||||
}
|
||||
for (i = 0; i < lengthof(_default_unicode_map); i++) {
|
||||
sprite = base + _default_unicode_map[i].key - ASCII_LETTERSTART;
|
||||
SetUnicodeGlyph(size, _default_unicode_map[i].code, sprite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/* $Id$ */
|
||||
|
||||
#ifndef FONTCACHE_H
|
||||
#define FONTCACHE_H
|
||||
|
||||
/** Get the SpriteID mapped to the given font size and key */
|
||||
SpriteID GetUnicodeGlyph(FontSize size, uint32 key);
|
||||
|
||||
/** Map a SpriteID to the font size and key */
|
||||
void SetUnicodeGlyph(FontSize size, uint32 key, SpriteID sprite);
|
||||
|
||||
/** Initialize the glyph map */
|
||||
void InitializeUnicodeGlyphMap(void);
|
||||
|
||||
#ifdef WITH_FREETYPE
|
||||
|
||||
typedef struct FreeTypeSettings {
|
||||
char small_font[260];
|
||||
char medium_font[260];
|
||||
char large_font[260];
|
||||
uint small_size;
|
||||
uint medium_size;
|
||||
uint large_size;
|
||||
} FreeTypeSettings;
|
||||
|
||||
extern FreeTypeSettings _freetype;
|
||||
|
||||
void InitFreeType(void);
|
||||
const struct Sprite *GetGlyph(FontSize size, uint32 key);
|
||||
uint GetGlyphWidth(FontSize size, uint32 key);
|
||||
|
||||
#else
|
||||
|
||||
/* Stub for initializiation */
|
||||
static inline void InitFreeType(void) {}
|
||||
|
||||
/** Get the Sprite for a glyph */
|
||||
static inline const Sprite *GetGlyph(FontSize size, uint32 key)
|
||||
{
|
||||
SpriteID sprite = GetUnicodeGlyph(size, key);
|
||||
if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
|
||||
return GetSprite(sprite);
|
||||
}
|
||||
|
||||
|
||||
/** Get the width of a glyph */
|
||||
static inline uint GetGlyphWidth(FontSize size, uint32 key)
|
||||
{
|
||||
SpriteID sprite = GetUnicodeGlyph(size, key);
|
||||
if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
|
||||
return SpriteExists(sprite) ? GetSprite(sprite)->width + (size != FS_NORMAL) : 0;
|
||||
}
|
||||
|
||||
#endif /* WITH_FREETYPE */
|
||||
|
||||
#endif /* FONTCACHE_H */
|
|
@ -147,6 +147,7 @@ char *GetName(char *buff, StringID id, const char* last);
|
|||
#define AllocateNameUnique(name, skip) RealAllocateName(name, skip, true)
|
||||
#define AllocateName(name, skip) RealAllocateName(name, skip, false)
|
||||
StringID RealAllocateName(const char *name, byte skip, bool check_double);
|
||||
void ConvertNameArray(void);
|
||||
|
||||
/* misc functions */
|
||||
void MarkTileDirty(int x, int y);
|
||||
|
|
145
gfx.c
145
gfx.c
|
@ -12,6 +12,8 @@
|
|||
#include "table/sprites.h"
|
||||
#include "hal.h"
|
||||
#include "variables.h"
|
||||
#include "table/control_codes.h"
|
||||
#include "fontcache.h"
|
||||
#include "genworld.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
@ -244,40 +246,6 @@ void GfxDrawLine(int x, int y, int x2, int y2, int color)
|
|||
}
|
||||
|
||||
|
||||
static inline SpriteID GetFontBase(FontSize size)
|
||||
{
|
||||
switch (size) {
|
||||
default: NOT_REACHED();
|
||||
case FS_NORMAL: return SPR_ASCII_SPACE;
|
||||
case FS_SMALL: return SPR_ASCII_SPACE_SMALL;
|
||||
case FS_LARGE: return SPR_ASCII_SPACE_BIG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ASSIGNMENT OF ASCII LETTERS < 32
|
||||
// 0 - end of string
|
||||
// 1 - SETX <BYTE>
|
||||
// 2 - SETXY <BYTE> <BYTE>
|
||||
// 3-7 -
|
||||
// 8 - TINYFONT
|
||||
// 9 - BIGFONT
|
||||
// 10 - newline
|
||||
// 11-14 -
|
||||
// 15-31 - 17 colors
|
||||
|
||||
|
||||
enum {
|
||||
ASCII_SETX = 1,
|
||||
ASCII_SETXY = 2,
|
||||
|
||||
ASCII_TINYFONT = 8,
|
||||
ASCII_BIGFONT = 9,
|
||||
ASCII_NL = 10,
|
||||
|
||||
ASCII_COLORSTART = 15,
|
||||
};
|
||||
|
||||
/** Truncate a given string to a maximum width if neccessary.
|
||||
* If the string is truncated, add three dots ('...') to show this.
|
||||
* @param *dest string that is checked and possibly truncated
|
||||
|
@ -289,13 +257,13 @@ static int TruncateString(char *str, int maxw)
|
|||
FontSize size = _cur_fontsize;
|
||||
int ddd, ddd_w;
|
||||
|
||||
byte c;
|
||||
WChar c;
|
||||
char *ddd_pos;
|
||||
|
||||
ddd_w = ddd = GetCharacterWidth(size, '.') * 3;
|
||||
|
||||
for (ddd_pos = str; (c = *str++) != '\0'; ) {
|
||||
if (c >= ASCII_LETTERSTART) {
|
||||
for (ddd_pos = str; (c = Utf8Consume((const char **)&str)) != '\0'; ) {
|
||||
if (IsPrintable(c)) {
|
||||
w += GetCharacterWidth(size, c);
|
||||
|
||||
if (w >= maxw) {
|
||||
|
@ -305,12 +273,12 @@ static int TruncateString(char *str, int maxw)
|
|||
return ddd_w;
|
||||
}
|
||||
} else {
|
||||
if (c == ASCII_SETX) str++;
|
||||
else if (c == ASCII_SETXY) str += 2;
|
||||
else if (c == ASCII_TINYFONT) {
|
||||
if (c == SCC_SETX) str++;
|
||||
else if (c == SCC_SETXY) str += 2;
|
||||
else if (c == SCC_TINYFONT) {
|
||||
size = FS_SMALL;
|
||||
ddd = GetCharacterWidth(size, '.') * 3;
|
||||
} else if (c == ASCII_BIGFONT) {
|
||||
} else if (c == SCC_BIGFONT) {
|
||||
size = FS_LARGE;
|
||||
ddd = GetCharacterWidth(size, '.') * 3;
|
||||
}
|
||||
|
@ -443,11 +411,11 @@ uint32 FormatStringLinebreaks(char *str, int maxw)
|
|||
int w = 0;
|
||||
|
||||
for (;;) {
|
||||
byte c = *str++;
|
||||
WChar c = Utf8Consume((const char **)&str);
|
||||
/* whitespace is where we will insert the line-break */
|
||||
if (c == ASCII_LETTERSTART) last_space = str;
|
||||
if (c == ' ') last_space = str;
|
||||
|
||||
if (c >= ASCII_LETTERSTART) {
|
||||
if (IsPrintable(c)) {
|
||||
w += GetCharacterWidth(size, c);
|
||||
/* string is longer than maximum width so we need to decide what to
|
||||
* do. We can do two things:
|
||||
|
@ -465,11 +433,11 @@ uint32 FormatStringLinebreaks(char *str, int maxw)
|
|||
} else {
|
||||
switch (c) {
|
||||
case '\0': return num + (size << 16); break;
|
||||
case ASCII_SETX: str++; break;
|
||||
case ASCII_SETXY: str +=2; break;
|
||||
case ASCII_TINYFONT: size = FS_SMALL; break;
|
||||
case ASCII_BIGFONT: size = FS_LARGE; break;
|
||||
case ASCII_NL: goto end_of_inner_loop;
|
||||
case SCC_SETX: str++; break;
|
||||
case SCC_SETXY: str +=2; break;
|
||||
case SCC_TINYFONT: size = FS_SMALL; break;
|
||||
case SCC_BIGFONT: size = FS_LARGE; break;
|
||||
case '\n': goto end_of_inner_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -486,7 +454,7 @@ void DrawStringMultiCenter(int x, int y, StringID str, int maxw)
|
|||
uint32 tmp;
|
||||
int num, w, mt;
|
||||
const char *src;
|
||||
byte c;
|
||||
WChar c;
|
||||
|
||||
GetString(buffer, str, lastof(buffer));
|
||||
|
||||
|
@ -505,7 +473,7 @@ void DrawStringMultiCenter(int x, int y, StringID str, int maxw)
|
|||
_cur_fontsize = _last_fontsize;
|
||||
|
||||
for (;;) {
|
||||
c = *src++;
|
||||
c = Utf8Consume(&src);
|
||||
if (c == 0) {
|
||||
y += mt;
|
||||
if (--num < 0) {
|
||||
|
@ -513,9 +481,9 @@ void DrawStringMultiCenter(int x, int y, StringID str, int maxw)
|
|||
return;
|
||||
}
|
||||
break;
|
||||
} else if (c == ASCII_SETX) {
|
||||
} else if (c == SCC_SETX) {
|
||||
src++;
|
||||
} else if (c == ASCII_SETXY) {
|
||||
} else if (c == SCC_SETXY) {
|
||||
src+=2;
|
||||
}
|
||||
}
|
||||
|
@ -530,7 +498,7 @@ uint DrawStringMultiLine(int x, int y, StringID str, int maxw)
|
|||
int num, mt;
|
||||
uint total_height;
|
||||
const char *src;
|
||||
byte c;
|
||||
WChar c;
|
||||
|
||||
GetString(buffer, str, lastof(buffer));
|
||||
|
||||
|
@ -547,7 +515,7 @@ uint DrawStringMultiLine(int x, int y, StringID str, int maxw)
|
|||
_cur_fontsize = _last_fontsize;
|
||||
|
||||
for (;;) {
|
||||
c = *src++;
|
||||
c = Utf8Consume(&src);
|
||||
if (c == 0) {
|
||||
y += mt;
|
||||
if (--num < 0) {
|
||||
|
@ -555,9 +523,9 @@ uint DrawStringMultiLine(int x, int y, StringID str, int maxw)
|
|||
return total_height;
|
||||
}
|
||||
break;
|
||||
} else if (c == ASCII_SETX) {
|
||||
} else if (c == SCC_SETX) {
|
||||
src++;
|
||||
} else if (c == ASCII_SETXY) {
|
||||
} else if (c == SCC_SETXY) {
|
||||
src+=2;
|
||||
}
|
||||
}
|
||||
|
@ -576,22 +544,24 @@ BoundingRect GetStringBoundingBox(const char *str)
|
|||
FontSize size = _cur_fontsize;
|
||||
BoundingRect br;
|
||||
int max_width;
|
||||
byte c;
|
||||
WChar c;
|
||||
|
||||
br.width = br.height = max_width = 0;
|
||||
for (c = *str; c != '\0'; c = *(++str)) {
|
||||
if (c >= ASCII_LETTERSTART) {
|
||||
for (;;) {
|
||||
c = Utf8Consume(&str);
|
||||
if (c == 0) break;
|
||||
if (IsPrintable(c)) {
|
||||
br.width += GetCharacterWidth(size, c);
|
||||
} else {
|
||||
switch (c) {
|
||||
case ASCII_SETX: br.width += (byte)*++str; break;
|
||||
case ASCII_SETXY:
|
||||
case SCC_SETX: br.width += (byte)*++str; break;
|
||||
case SCC_SETXY:
|
||||
br.width += (byte)*++str;
|
||||
br.height += (byte)*++str;
|
||||
break;
|
||||
case ASCII_TINYFONT: size = FS_SMALL; break;
|
||||
case ASCII_BIGFONT: size = FS_LARGE; break;
|
||||
case ASCII_NL:
|
||||
case SCC_TINYFONT: size = FS_SMALL; break;
|
||||
case SCC_BIGFONT: size = FS_LARGE; break;
|
||||
case '\n':
|
||||
br.height += GetCharacterHeight(size);
|
||||
if (br.width > max_width) max_width = br.width;
|
||||
br.width = 0;
|
||||
|
@ -617,7 +587,7 @@ int DoDrawString(const char *string, int x, int y, uint16 real_color)
|
|||
{
|
||||
DrawPixelInfo *dpi = _cur_dpi;
|
||||
FontSize size = _cur_fontsize;
|
||||
byte c;
|
||||
WChar c;
|
||||
byte color;
|
||||
int xo = x, yo = y;
|
||||
|
||||
|
@ -647,39 +617,39 @@ check_bounds:
|
|||
if (y + 19 <= dpi->top || dpi->top + dpi->height <= y) {
|
||||
skip_char:;
|
||||
for (;;) {
|
||||
c = *string++;
|
||||
if (c < ASCII_LETTERSTART) goto skip_cont;
|
||||
c = Utf8Consume(&string);
|
||||
if (!IsPrintable(c)) goto skip_cont;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
c = *string++;
|
||||
c = Utf8Consume(&string);
|
||||
skip_cont:;
|
||||
if (c == 0) {
|
||||
_last_fontsize = size;
|
||||
return x;
|
||||
}
|
||||
if (c >= ASCII_LETTERSTART) {
|
||||
if (IsPrintable(c)) {
|
||||
if (x >= dpi->left + dpi->width) goto skip_char;
|
||||
if (x + 26 >= dpi->left) {
|
||||
GfxMainBlitter(GetSprite(GetFontBase(size) + c - ASCII_LETTERSTART), x, y, 1);
|
||||
GfxMainBlitter(GetGlyph(size, c), x, y, 1);
|
||||
}
|
||||
x += GetCharacterWidth(size, c);
|
||||
} else if (c == ASCII_NL) { // newline = {}
|
||||
} else if (c == '\n') { // newline = {}
|
||||
x = xo;
|
||||
y += GetCharacterHeight(size);
|
||||
goto check_bounds;
|
||||
} else if (c >= ASCII_COLORSTART) { // change color?
|
||||
color = (byte)(c - ASCII_COLORSTART);
|
||||
} else if (c >= SCC_BLUE && c <= SCC_BLACK) { // change color?
|
||||
color = (byte)(c - SCC_BLUE);
|
||||
goto switch_color;
|
||||
} else if (c == ASCII_SETX) { // {SETX}
|
||||
} else if (c == SCC_SETX) { // {SETX}
|
||||
x = xo + (byte)*string++;
|
||||
} else if (c == ASCII_SETXY) {// {SETXY}
|
||||
} else if (c == SCC_SETXY) {// {SETXY}
|
||||
x = xo + (byte)*string++;
|
||||
y = yo + (byte)*string++;
|
||||
} else if (c == ASCII_TINYFONT) { // {TINYFONT}
|
||||
} else if (c == SCC_TINYFONT) { // {TINYFONT}
|
||||
size = FS_SMALL;
|
||||
} else if (c == ASCII_BIGFONT) { // {BIGFONT}
|
||||
} else if (c == SCC_BIGFONT) { // {BIGFONT}
|
||||
size = FS_LARGE;
|
||||
} else {
|
||||
printf("Unknown string command character %d\n", c);
|
||||
|
@ -1641,28 +1611,33 @@ void DoPaletteAnimations(void)
|
|||
|
||||
void LoadStringWidthTable(void)
|
||||
{
|
||||
SpriteID base;
|
||||
uint i;
|
||||
|
||||
/* Normal font */
|
||||
base = GetFontBase(FS_NORMAL);
|
||||
for (i = 0; i != 224; i++) {
|
||||
_stringwidth_table[FS_NORMAL][i] = SpriteExists(base + i) ? GetSprite(base + i)->width : 0;
|
||||
_stringwidth_table[FS_NORMAL][i] = GetGlyphWidth(FS_NORMAL, i + 32);
|
||||
}
|
||||
|
||||
/* Small font */
|
||||
base = GetFontBase(FS_SMALL);
|
||||
for (i = 0; i != 224; i++) {
|
||||
_stringwidth_table[FS_SMALL][i] = SpriteExists(base + i) ? GetSprite(base + i)->width + 1 : 0;
|
||||
_stringwidth_table[FS_SMALL][i] = GetGlyphWidth(FS_SMALL, i + 32);
|
||||
}
|
||||
|
||||
/* Large font */
|
||||
base = GetFontBase(FS_LARGE);
|
||||
for (i = 0; i != 224; i++) {
|
||||
_stringwidth_table[FS_LARGE][i] = SpriteExists(base + i) ? GetSprite(base + i)->width + 1 : 0;
|
||||
_stringwidth_table[FS_LARGE][i] = GetGlyphWidth(FS_LARGE, i + 32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
byte GetCharacterWidth(FontSize size, WChar key)
|
||||
{
|
||||
if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32];
|
||||
|
||||
return GetGlyphWidth(size, key);
|
||||
}
|
||||
|
||||
|
||||
void ScreenSizeChanged(void)
|
||||
{
|
||||
// check the dirty rect
|
||||
|
|
11
gfx.h
11
gfx.h
|
@ -43,8 +43,8 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo);
|
|||
|
||||
// XXX doesn't really belong here, but the only
|
||||
// consumers always use it in conjunction with DoDrawString()
|
||||
#define UPARROW "\x80"
|
||||
#define DOWNARROW "\xAA"
|
||||
#define UPARROW "\xEE\x8A\x80"
|
||||
#define DOWNARROW "\xEE\x8A\xAA"
|
||||
|
||||
|
||||
int DrawStringCentered(int x, int y, StringID str, uint16 color);
|
||||
|
@ -96,13 +96,8 @@ void ToggleFullScreen(bool fs);
|
|||
/* gfx.c */
|
||||
#define ASCII_LETTERSTART 32
|
||||
extern FontSize _cur_fontsize;
|
||||
extern byte _stringwidth_table[FS_END][224];
|
||||
|
||||
static inline byte GetCharacterWidth(FontSize size, byte key)
|
||||
{
|
||||
assert(key >= ASCII_LETTERSTART);
|
||||
return _stringwidth_table[size][key - ASCII_LETTERSTART];
|
||||
}
|
||||
byte GetCharacterWidth(FontSize size, uint32 key);
|
||||
|
||||
static inline byte GetCharacterHeight(FontSize size)
|
||||
{
|
||||
|
|
2
gui.h
2
gui.h
|
@ -109,7 +109,7 @@ bool HandleCaret(Textbuf *tb);
|
|||
|
||||
void DeleteTextBufferAll(Textbuf *tb);
|
||||
bool DeleteTextBufferChar(Textbuf *tb, int delmode);
|
||||
bool InsertTextBufferChar(Textbuf *tb, byte key);
|
||||
bool InsertTextBufferChar(Textbuf *tb, uint32 key);
|
||||
bool InsertTextBufferClipboard(Textbuf *tb);
|
||||
bool MoveTextBufferPos(Textbuf *tb, int navmode);
|
||||
void InitializeTextBuffer(Textbuf *tb, const char *buf, uint16 maxlength, uint16 maxwidth);
|
||||
|
|
|
@ -2001,8 +2001,8 @@ STR_26816_NONE :None
|
|||
STR_6816_LOW :Low
|
||||
STR_6817_NORMAL :Normal
|
||||
STR_6818_HIGH :High
|
||||
STR_6819 :{BLACK}<
|
||||
STR_681A :{BLACK}>
|
||||
STR_6819 :{BLACK}{SMALLLEFTARROW}
|
||||
STR_681A :{BLACK}{SMALLRIGHTARROW}
|
||||
STR_681B_VERY_SLOW :Very Slow
|
||||
STR_681C_SLOW :Slow
|
||||
STR_681D_MEDIUM :Medium
|
||||
|
|
10
main_gui.c
10
main_gui.c
|
@ -29,6 +29,7 @@
|
|||
#include "variables.h"
|
||||
#include "train.h"
|
||||
#include "unmovable_map.h"
|
||||
#include "string.h"
|
||||
#include "screenshot.h"
|
||||
#include "genworld.h"
|
||||
#include "settings.h"
|
||||
|
@ -2085,15 +2086,16 @@ static bool DrawScrollingStatusText(const NewsItem *ni, int pos)
|
|||
s = buf;
|
||||
d = buffer;
|
||||
|
||||
for (;; s++) {
|
||||
if (*s == '\0') {
|
||||
for (;;) {
|
||||
WChar c = Utf8Consume(&s);
|
||||
if (c == 0) {
|
||||
*d = '\0';
|
||||
break;
|
||||
} else if (*s == 0x0D) {
|
||||
d[0] = d[1] = d[2] = d[3] = ' ';
|
||||
d += 4;
|
||||
} else if ((byte)*s >= ' ' && ((byte)*s < 0x88 || (byte)*s >= 0x99)) {
|
||||
*d++ = *s;
|
||||
} else if (IsPrintable(c)) {
|
||||
d += Utf8Encode(d, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ $(MAKE_CONFIG):
|
|||
$(call CONFIG_LINE,WITH_ICONV_PATH:=$(WITH_ICONV_PATH))
|
||||
$(call CONFIG_LINE,STATIC_ZLIB_PATH:=$(STATIC_ZLIB_PATH))
|
||||
$(call CONFIG_LINE,WITH_COCOA:=$(WITH_COCOA))
|
||||
$(call CONFIG_LINE,WITH_FREETYPE:=$(WITH_FREETYPE))
|
||||
$(call CONFIG_LINE,)
|
||||
|
||||
$(call CONFIG_LINE,\# OS flags)
|
||||
|
@ -100,6 +101,7 @@ $(MAKE_CONFIG):
|
|||
$(call CONFIG_LINE,\# misc)
|
||||
$(call CONFIG_LINE,SDL_CONFIG:=$(SDL_CONFIG))
|
||||
$(call CONFIG_LINE,LIBPNG_CONFIG:=$(LIBPNG_CONFIG))
|
||||
$(call CONFIG_LINE,FREETYPE_CONFIG:=$(FREETYPE_CONFIG))
|
||||
$(call CONFIG_LINE,BEOS_NET_SERVER:=$(BEOS_NET_SERVER))
|
||||
$(call CONFIG_LINE,CONFIG_INCLUDED:=yes)
|
||||
$(call CONFIG_LINE,PATH_SET:=$(PATH_SET))
|
||||
|
|
|
@ -66,6 +66,9 @@ SDL_CONFIG:=sdl-config
|
|||
# set libpng-config to the default value
|
||||
LIBPNG_CONFIG :=libpng-config
|
||||
|
||||
# set freetype-config to the default value
|
||||
FREETYPE_CONFIG:=freetype-config
|
||||
|
||||
# Networking, enabled by default
|
||||
WITH_NETWORK:=1
|
||||
|
||||
|
@ -75,6 +78,9 @@ WITH_SDL:=$(shell $(SDL_CONFIG) --version 2>/dev/null)
|
|||
# libpng detection
|
||||
WITH_PNG:=$(shell $(LIBPNG_CONFIG) --version 2>/dev/null)
|
||||
|
||||
# Freetype detection
|
||||
WITH_FREETYPE:=$(shell $(FREETYPE_CONFIG) --ftversion 2>/dev/null)
|
||||
|
||||
ifdef WITH_PNG
|
||||
# LibPNG depends on Zlib
|
||||
WITH_ZLIB:=1
|
||||
|
|
32
misc.c
32
misc.c
|
@ -202,6 +202,38 @@ StringID RealAllocateName(const char *name, byte skip, bool check_double)
|
|||
}
|
||||
}
|
||||
|
||||
void ConvertNameArray(void)
|
||||
{
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < lengthof(_name_array); i++) {
|
||||
const char *strfrom = _name_array[i];
|
||||
char tmp[sizeof(*_name_array)];
|
||||
char *strto = tmp;
|
||||
|
||||
for (; *strfrom != '\0'; strfrom++) {
|
||||
WChar c = (byte)*strfrom;
|
||||
switch (c) {
|
||||
case 0xA4: c = 0x20AC; break; // Euro
|
||||
case 0xA6: c = 0x0160; break; // S with caron
|
||||
case 0xA8: c = 0x0161; break; // s with caron
|
||||
case 0xB4: c = 0x017D; break; // Z with caron
|
||||
case 0xB8: c = 0x017E; break; // z with caron
|
||||
case 0xBC: c = 0x0152; break; // OE ligature
|
||||
case 0xBD: c = 0x0153; break; // oe ligature
|
||||
case 0xBE: c = 0x0178; break; // Y with diaresis
|
||||
default: break;
|
||||
}
|
||||
if (strto + Utf8CharLen(c) > lastof(tmp)) break;
|
||||
strto += Utf8Encode(strto, c);
|
||||
}
|
||||
|
||||
/* Terminate the new string and copy it back to the name array */
|
||||
*strto = '\0';
|
||||
memcpy(_name_array[i], tmp, sizeof(*_name_array));
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate constants that depend on the landscape type.
|
||||
void InitializeLandscapeVariables(bool only_constants)
|
||||
{
|
||||
|
|
92
misc_gui.c
92
misc_gui.c
|
@ -205,8 +205,8 @@ static const char *credits[] = {
|
|||
" Bjarni Corfitzen (Bjarni) - MacOSX port, coder",
|
||||
" Matthijs Kooijman (blathijs) - Pathfinder-god",
|
||||
" Victor Fischer (Celestar) - Programming everywhere you need him to",
|
||||
" Tamás Faragó (Darkvater) - Lead coder",
|
||||
" Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
|
||||
" Tamás Faragó (Darkvater) - Lead coder",
|
||||
" Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
|
||||
" Owen Rudge (orudge) - Forum- and masterserver host, OS/2 port",
|
||||
" Peter Nelson (peter1138) - Spiritual descendant from newgrf gods",
|
||||
" Christoph Mallon (Tron) - Programmer, code correctness police",
|
||||
|
@ -221,13 +221,13 @@ static const char *credits[] = {
|
|||
" Josef Drexler - For his great work on TTDPatch",
|
||||
" Marcin Grzegorczyk - For his documentation of TTD internals",
|
||||
" Petr Baudis (pasky) - Many patches, newgrf support",
|
||||
" Stefan Meißner (sign_de) - For his work on the console",
|
||||
" Stefan Meißner (sign_de) - For his work on the console",
|
||||
" Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with (and PBS)",
|
||||
" Cian Duffy (MYOB) - BeOS port / manual writing",
|
||||
" Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
|
||||
"",
|
||||
" Michael Blunck - Pre-Signals and Semaphores Š 2003",
|
||||
" George - Canal/Lock graphics Š 2003-2004",
|
||||
" Michael Blunck - Pre-Signals and Semaphores © 2003",
|
||||
" George - Canal/Lock graphics © 2003-2004",
|
||||
" Marcin Grzegorczyk - Foundations for Tracks on Slopes",
|
||||
" All Translators - Who made OpenTTD a truly international game",
|
||||
" Bug Reporters - Without whom OpenTTD would still be full of bugs!",
|
||||
|
@ -782,11 +782,30 @@ void SetHScrollCount(Window *w, int num)
|
|||
if (num < w->hscroll.pos) w->hscroll.pos = num;
|
||||
}
|
||||
|
||||
static void DelChar(Textbuf *tb)
|
||||
/* Delete a character at the caret position in a text buf.
|
||||
* If backspace is set, delete the character before the caret,
|
||||
* else delete the character after it. */
|
||||
static void DelChar(Textbuf *tb, bool backspace)
|
||||
{
|
||||
tb->width -= GetCharacterWidth(FS_NORMAL, (byte)tb->buf[tb->caretpos]);
|
||||
memmove(tb->buf + tb->caretpos, tb->buf + tb->caretpos + 1, tb->length - tb->caretpos);
|
||||
tb->length--;
|
||||
WChar c;
|
||||
uint width;
|
||||
size_t len;
|
||||
|
||||
if (backspace) {
|
||||
do {
|
||||
tb->caretpos--;
|
||||
} while (IsUtf8Part(*(tb->buf + tb->caretpos)));
|
||||
}
|
||||
|
||||
len = Utf8Decode(&c, tb->buf + tb->caretpos);
|
||||
width = GetCharacterWidth(FS_NORMAL, c);
|
||||
|
||||
tb->width -= width;
|
||||
if (backspace) tb->caretxoffs -= width;
|
||||
|
||||
/* Move the remaining characters over the marker */
|
||||
memmove(tb->buf + tb->caretpos, tb->buf + tb->caretpos + len, tb->length - tb->caretpos - len + 1);
|
||||
tb->length -= len;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -799,13 +818,10 @@ static void DelChar(Textbuf *tb)
|
|||
bool DeleteTextBufferChar(Textbuf *tb, int delmode)
|
||||
{
|
||||
if (delmode == WKC_BACKSPACE && tb->caretpos != 0) {
|
||||
tb->caretpos--;
|
||||
tb->caretxoffs -= GetCharacterWidth(FS_NORMAL, (byte)tb->buf[tb->caretpos]);
|
||||
|
||||
DelChar(tb);
|
||||
DelChar(tb, true);
|
||||
return true;
|
||||
} else if (delmode == WKC_DELETE && tb->caretpos < tb->length) {
|
||||
DelChar(tb);
|
||||
DelChar(tb, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -831,16 +847,17 @@ void DeleteTextBufferAll(Textbuf *tb)
|
|||
* @param key Character to be inserted
|
||||
* @return Return true on successfull change of Textbuf, or false otherwise
|
||||
*/
|
||||
bool InsertTextBufferChar(Textbuf *tb, byte key)
|
||||
bool InsertTextBufferChar(Textbuf *tb, WChar key)
|
||||
{
|
||||
const byte charwidth = GetCharacterWidth(FS_NORMAL, key);
|
||||
if (tb->length < (tb->maxlength - 1) && (tb->maxwidth == 0 || tb->width + charwidth <= tb->maxwidth)) {
|
||||
memmove(tb->buf + tb->caretpos + 1, tb->buf + tb->caretpos, (tb->length - tb->caretpos) + 1);
|
||||
tb->buf[tb->caretpos] = key;
|
||||
tb->length++;
|
||||
tb->width += charwidth;
|
||||
size_t len = Utf8CharLen(key);
|
||||
if (tb->length < (tb->maxlength - len) && (tb->maxwidth == 0 || tb->width + charwidth <= tb->maxwidth)) {
|
||||
memmove(tb->buf + tb->caretpos + len, tb->buf + tb->caretpos, tb->length - tb->caretpos + 1);
|
||||
Utf8Encode(tb->buf + tb->caretpos, key);
|
||||
tb->length += len;
|
||||
tb->width += charwidth;
|
||||
|
||||
tb->caretpos++;
|
||||
tb->caretpos += len;
|
||||
tb->caretxoffs += charwidth;
|
||||
return true;
|
||||
}
|
||||
|
@ -859,15 +876,25 @@ bool MoveTextBufferPos(Textbuf *tb, int navmode)
|
|||
switch (navmode) {
|
||||
case WKC_LEFT:
|
||||
if (tb->caretpos != 0) {
|
||||
tb->caretpos--;
|
||||
tb->caretxoffs -= GetCharacterWidth(FS_NORMAL, (byte)tb->buf[tb->caretpos]);
|
||||
WChar c;
|
||||
|
||||
do {
|
||||
tb->caretpos--;
|
||||
} while (IsUtf8Part(*(tb->buf + tb->caretpos)));
|
||||
|
||||
Utf8Decode(&c, tb->buf + tb->caretpos);
|
||||
tb->caretxoffs -= GetCharacterWidth(FS_NORMAL, c);
|
||||
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case WKC_RIGHT:
|
||||
if (tb->caretpos < tb->length) {
|
||||
tb->caretxoffs += GetCharacterWidth(FS_NORMAL, (byte)tb->buf[tb->caretpos]);
|
||||
tb->caretpos++;
|
||||
WChar c;
|
||||
|
||||
tb->caretpos += Utf8Decode(&c, tb->buf + tb->caretpos);
|
||||
tb->caretxoffs += GetCharacterWidth(FS_NORMAL, c);
|
||||
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
@ -910,16 +937,16 @@ void InitializeTextBuffer(Textbuf *tb, const char *buf, uint16 maxlength, uint16
|
|||
*/
|
||||
void UpdateTextBufferSize(Textbuf *tb)
|
||||
{
|
||||
const char *buf;
|
||||
const char *buf = tb->buf;
|
||||
WChar c = Utf8Consume(&buf);
|
||||
|
||||
tb->length = 0;
|
||||
tb->width = 0;
|
||||
|
||||
for (buf = tb->buf; *buf != '\0' && tb->length < (tb->maxlength - 1); buf++) {
|
||||
tb->length++;
|
||||
tb->width += GetCharacterWidth(FS_NORMAL, (byte)*buf);
|
||||
for (; c != '\0' && tb->length < (tb->maxlength - 1); c = Utf8Consume(&buf)) {
|
||||
tb->width += GetCharacterWidth(FS_NORMAL, c);
|
||||
}
|
||||
|
||||
tb->length = buf - tb->buf - 1;
|
||||
tb->caretpos = tb->length;
|
||||
tb->caretxoffs = tb->width;
|
||||
}
|
||||
|
@ -948,9 +975,10 @@ int HandleEditBoxKey(Window *w, querystr_d *string, int wid, WindowEvent *e)
|
|||
InvalidateWidget(w, wid);
|
||||
break;
|
||||
default:
|
||||
if (IsValidAsciiChar(e->we.keypress.ascii, string->afilter)) {
|
||||
if (InsertTextBufferChar(&string->text, e->we.keypress.ascii))
|
||||
if (IsValidChar(e->we.keypress.key, string->afilter)) {
|
||||
if (InsertTextBufferChar(&string->text, e->we.keypress.key)) {
|
||||
InvalidateWidget(w, wid);
|
||||
}
|
||||
} else { // key wasn't caught. Continue only if standard entry specified
|
||||
e->we.keypress.cont = (string->afilter == CS_ALPHANUMERAL);
|
||||
}
|
||||
|
|
|
@ -480,13 +480,15 @@ static byte MakeCzechTownName(char *buf, uint32 seed, const char *last)
|
|||
|
||||
strecat(buf, name_czech_adj[prefix].name, last);
|
||||
endpos = strlen(buf) - 1;
|
||||
/* Find the first character in a UTF-8 sequence */
|
||||
while (GB(buf[endpos], 6, 2) == 2) endpos--;
|
||||
if (gender == CZG_SMASC && pattern == CZP_PRIVL) {
|
||||
/* -ovX -> -uv */
|
||||
buf[endpos - 2] = 'u';
|
||||
assert(buf[endpos - 1] == 'v');
|
||||
buf[endpos] = '\0';
|
||||
} else {
|
||||
buf[endpos] = name_czech_patmod[gender][pattern];
|
||||
strecpy(buf + endpos, name_czech_patmod[gender][pattern], last);
|
||||
}
|
||||
|
||||
strecat(buf, " ", last);
|
||||
|
|
|
@ -526,7 +526,7 @@ void ParseConnectionString(const char **player, const char **port, char *connect
|
|||
if (*p == '#') {
|
||||
*p = '\0';
|
||||
*player = ++p;
|
||||
while (IsValidAsciiChar(*p, CS_NUMERAL)) p++;
|
||||
while (IsValidChar(*p, CS_NUMERAL)) p++;
|
||||
if (*p == '\0') break;
|
||||
} else if (*p == ':') {
|
||||
*port = p + 1;
|
||||
|
|
38
newgrf.c
38
newgrf.c
|
@ -23,6 +23,7 @@
|
|||
#include "vehicle.h"
|
||||
#include "newgrf_text.h"
|
||||
#include "table/sprites.h"
|
||||
#include "fontcache.h"
|
||||
#include "date.h"
|
||||
#include "currency.h"
|
||||
#include "sound.h"
|
||||
|
@ -3039,6 +3040,42 @@ static void LoadGRFSound(byte *buf, int len)
|
|||
}
|
||||
}
|
||||
|
||||
/* Action 0x12 */
|
||||
static void LoadFontGlyph(byte *buf, int len)
|
||||
{
|
||||
/* <12> <num_def> <font_size> <num_char> <base_char>
|
||||
*
|
||||
* B num_def Number of definitions
|
||||
* B font_size Size of font (0 = normal, 1 = small, 2 = large)
|
||||
* B num_char Number of consecutive glyphs
|
||||
* W base_char First character index */
|
||||
|
||||
uint8 num_def;
|
||||
uint i;
|
||||
|
||||
buf++; len--;
|
||||
check_length(len, 1, "LoadFontGlyph");
|
||||
|
||||
num_def = grf_load_byte(&buf);
|
||||
|
||||
check_length(len, 1 + num_def * 4, "LoadFontGlyph");
|
||||
|
||||
for (i = 0; i < num_def; i++) {
|
||||
FontSize size = grf_load_byte(&buf);
|
||||
uint8 num_char = grf_load_byte(&buf);
|
||||
uint16 base_char = grf_load_word(&buf);
|
||||
uint c;
|
||||
|
||||
DEBUG(grf, 7) ("LoadFontGlyph: Loading %u glyph(s) at 0x%04X for size %u", num_char, base_char, size);
|
||||
|
||||
for (c = 0; c < num_char; c++) {
|
||||
SetUnicodeGlyph(size, base_char + c, _cur_spriteid);
|
||||
LoadNextSprite(_cur_spriteid++, _file_index);
|
||||
_nfo_line++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 'Action 0xFF' */
|
||||
static void GRFDataBlock(byte *buf, int len)
|
||||
{
|
||||
|
@ -3421,6 +3458,7 @@ static void DecodeSpecialSprite(uint num, GrfLoadingStage stage)
|
|||
/* 0x0F */ { NULL, NULL, NULL, },
|
||||
/* 0x10 */ { DefineGotoLabel, NULL, NULL, },
|
||||
/* 0x11 */ { NULL, NULL, GRFSound, },
|
||||
/* 0x12 */ { NULL, NULL, LoadFontGlyph, },
|
||||
};
|
||||
|
||||
byte* buf;
|
||||
|
|
128
newgrf_text.c
128
newgrf_text.c
|
@ -18,6 +18,7 @@
|
|||
#include "macros.h"
|
||||
#include "table/strings.h"
|
||||
#include "newgrf_text.h"
|
||||
#include "table/control_codes.h"
|
||||
|
||||
#define GRFTAB 28
|
||||
#define TABSIZE 11
|
||||
|
@ -153,46 +154,104 @@ static GRFTextEntry _grf_text[(1 << TABSIZE) * 3];
|
|||
static byte _currentLangID = GRFLX_ENGLISH; //by default, english is used.
|
||||
|
||||
|
||||
static void TranslateTTDPatchCodes(char *str)
|
||||
static char *TranslateTTDPatchCodes(const char *str)
|
||||
{
|
||||
char *c;
|
||||
char *tmp = malloc(strlen(str) * 10); /* Allocate space to allow for expansion */
|
||||
char *d = tmp;
|
||||
bool unicode = false;
|
||||
WChar c = Utf8Consume(&str);
|
||||
|
||||
for (c = str; *c != '\0'; c++) {
|
||||
switch ((byte)*c) {
|
||||
case 0x01: c++; break;
|
||||
case 0x0D: *c = 10; break;
|
||||
case 0x0E: *c = 8; break;
|
||||
case 0x0F: *c = 9; break;
|
||||
case 0x1F: *c = 2; c += 2; break;
|
||||
if (c == 0x00DE) {
|
||||
/* The thorn ('þ') indicates a unicode string to TTDPatch */
|
||||
unicode = true;
|
||||
} else {
|
||||
str--;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
const char *tmp = str; /* Used for UTF-8 decoding */
|
||||
|
||||
c = (byte)*str++;
|
||||
if (c == 0) break;
|
||||
|
||||
switch (c) {
|
||||
case 0x01:
|
||||
d += Utf8Encode(d, SCC_SETX);
|
||||
*d++ = *str++;
|
||||
break;
|
||||
case 0x0D: *d++ = 10; break;
|
||||
case 0x0E: d += Utf8Encode(d, SCC_TINYFONT); break;
|
||||
case 0x0F: d += Utf8Encode(d, SCC_BIGFONT); break;
|
||||
case 0x1F:
|
||||
d += Utf8Encode(d, SCC_SETXY);
|
||||
*d++ = *str++;
|
||||
*d++ = *str++;
|
||||
break;
|
||||
case 0x7B:
|
||||
case 0x7C:
|
||||
case 0x7D:
|
||||
case 0x7E: *c = 0x8E; break;
|
||||
case 0x81: c += 2; break;
|
||||
case 0x85: *c = 0x86; break;
|
||||
case 0x88: *c = 15; break;
|
||||
case 0x89: *c = 16; break;
|
||||
case 0x8A: *c = 17; break;
|
||||
case 0x8B: *c = 18; break;
|
||||
case 0x8C: *c = 19; break;
|
||||
case 0x8D: *c = 20; break;
|
||||
case 0x8E: *c = 21; break;
|
||||
case 0x8F: *c = 22; break;
|
||||
case 0x90: *c = 23; break;
|
||||
case 0x91: *c = 24; break;
|
||||
case 0x92: *c = 25; break;
|
||||
case 0x93: *c = 26; break;
|
||||
case 0x94: *c = 27; break;
|
||||
case 0x95: *c = 28; break;
|
||||
case 0x96: *c = 29; break;
|
||||
case 0x97: *c = 30; break;
|
||||
case 0x98: *c = 31; break;
|
||||
case 0x7E: d += Utf8Encode(d, SCC_NUM); break;
|
||||
case 0x7F: d += Utf8Encode(d, SCC_CURRENCY); break;
|
||||
case 0x80: d += Utf8Encode(d, SCC_STRING); break;
|
||||
case 0x81: {
|
||||
StringID string;
|
||||
string = *str++;
|
||||
string |= *str++ << 8;
|
||||
d += Utf8Encode(d, SCC_STRING_ID);
|
||||
d += Utf8Encode(d, string);
|
||||
break;
|
||||
}
|
||||
case 0x82: d += Utf8Encode(d, SCC_DATE_TINY); break;
|
||||
case 0x83: d += Utf8Encode(d, SCC_DATE_SHORT); break;
|
||||
case 0x84: d += Utf8Encode(d, SCC_VELOCITY); break;
|
||||
case 0x85: d += Utf8Encode(d, SCC_SKIP); break;
|
||||
case 0x86: /* "Rotate down top 4 words on stack" */ break;
|
||||
case 0x87: d += Utf8Encode(d, SCC_VOLUME); break;
|
||||
case 0x88: d += Utf8Encode(d, SCC_BLUE); break;
|
||||
case 0x89: d += Utf8Encode(d, SCC_SILVER); break;
|
||||
case 0x8A: d += Utf8Encode(d, SCC_GOLD); break;
|
||||
case 0x8B: d += Utf8Encode(d, SCC_RED); break;
|
||||
case 0x8C: d += Utf8Encode(d, SCC_PURPLE); break;
|
||||
case 0x8D: d += Utf8Encode(d, SCC_LTBROWN); break;
|
||||
case 0x8E: d += Utf8Encode(d, SCC_ORANGE); break;
|
||||
case 0x8F: d += Utf8Encode(d, SCC_GREEN); break;
|
||||
case 0x90: d += Utf8Encode(d, SCC_YELLOW); break;
|
||||
case 0x91: d += Utf8Encode(d, SCC_DKGREEN); break;
|
||||
case 0x92: d += Utf8Encode(d, SCC_CREAM); break;
|
||||
case 0x93: d += Utf8Encode(d, SCC_BROWN); break;
|
||||
case 0x94: d += Utf8Encode(d, SCC_WHITE); break;
|
||||
case 0x95: d += Utf8Encode(d, SCC_LTBLUE); break;
|
||||
case 0x96: d += Utf8Encode(d, SCC_GRAY); break;
|
||||
case 0x97: d += Utf8Encode(d, SCC_DKBLUE); break;
|
||||
case 0x98: d += Utf8Encode(d, SCC_BLACK); break;
|
||||
case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro
|
||||
case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis
|
||||
case 0xA0: d += Utf8Encode(d, SCC_UPARROW); break;
|
||||
case 0xAA: d += Utf8Encode(d, SCC_DOWNARROW); break;
|
||||
case 0xAC: d += Utf8Encode(d, SCC_CHECKMARK); break;
|
||||
case 0xAD: d += Utf8Encode(d, SCC_CROSS); break;
|
||||
case 0xAF: d += Utf8Encode(d, SCC_RIGHTARROW); break;
|
||||
case 0xB4: d += Utf8Encode(d, SCC_TRAIN); break;
|
||||
case 0xB5: d += Utf8Encode(d, SCC_LORRY); break;
|
||||
case 0xB6: d += Utf8Encode(d, SCC_BUS); break;
|
||||
case 0xB7: d += Utf8Encode(d, SCC_PLANE); break;
|
||||
case 0xB8: d += Utf8Encode(d, SCC_SHIP); break;
|
||||
default:
|
||||
if (unicode) {
|
||||
d += Utf8Encode(d, Utf8Consume(&tmp));
|
||||
str = tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Validate any unhandled character */
|
||||
if (!IsValidAsciiChar(*c, CS_ALPHANUMERAL)) *c = '?';
|
||||
if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?';
|
||||
d += Utf8Encode(d, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*d = '\0';
|
||||
return realloc(tmp, strlen(tmp) + 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -201,6 +260,7 @@ static void TranslateTTDPatchCodes(char *str)
|
|||
*/
|
||||
StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool new_scheme, const char *text_to_add, StringID def_string)
|
||||
{
|
||||
char *translatedtext;
|
||||
GRFText *newtext;
|
||||
uint id;
|
||||
|
||||
|
@ -231,12 +291,14 @@ StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool ne
|
|||
/* Too many strings allocated, return empty */
|
||||
if (id == lengthof(_grf_text)) return STR_EMPTY;
|
||||
|
||||
newtext = malloc(sizeof(*newtext) + strlen(text_to_add) + 1);
|
||||
translatedtext = TranslateTTDPatchCodes(text_to_add);
|
||||
|
||||
newtext = malloc(sizeof(*newtext) + strlen(translatedtext) + 1);
|
||||
newtext->next = NULL;
|
||||
newtext->langid = langid_to_add;
|
||||
strcpy(newtext->text, text_to_add);
|
||||
strcpy(newtext->text, translatedtext);
|
||||
|
||||
TranslateTTDPatchCodes(newtext->text);
|
||||
free(translatedtext);
|
||||
|
||||
/* If we didn't find our stringid and grfid in the list, allocate a new id */
|
||||
if (id == _num_grf_texts) _num_grf_texts++;
|
||||
|
|
16
news_gui.c
16
news_gui.c
|
@ -15,6 +15,7 @@
|
|||
#include "sound.h"
|
||||
#include "variables.h"
|
||||
#include "date.h"
|
||||
#include "string.h"
|
||||
|
||||
/* News system
|
||||
* News system is realized as a FIFO queue (in an array)
|
||||
|
@ -569,7 +570,8 @@ static byte getNews(byte i)
|
|||
static void DrawNewsString(int x, int y, uint16 color, const NewsItem *ni, uint maxw)
|
||||
{
|
||||
char buffer[512], buffer2[512];
|
||||
char *ptr, *dest;
|
||||
const char *ptr;
|
||||
char *dest;
|
||||
StringID str;
|
||||
|
||||
if (ni->display_mode == 3) {
|
||||
|
@ -582,12 +584,16 @@ static void DrawNewsString(int x, int y, uint16 color, const NewsItem *ni, uint
|
|||
GetString(buffer, str, lastof(buffer));
|
||||
/* Copy the just gotten string to another buffer to remove any formatting
|
||||
* from it such as big fonts, etc. */
|
||||
for (ptr = buffer, dest = buffer2; *ptr != '\0'; ptr++) {
|
||||
if (*ptr == '\r') {
|
||||
ptr = buffer;
|
||||
dest = buffer2;
|
||||
for (;;) {
|
||||
WChar c = Utf8Consume(&ptr);
|
||||
if (c == 0) break;
|
||||
if (c == '\r') {
|
||||
dest[0] = dest[1] = dest[2] = dest[3] = ' ';
|
||||
dest += 4;
|
||||
} else if ((byte)*ptr >= ' ' && ((byte)*ptr < 0x88 || (byte)*ptr >= 0x99)) {
|
||||
*dest++ = *ptr;
|
||||
} else if (IsPrintable(c)) {
|
||||
dest += Utf8Encode(dest, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
10
openttd.c
10
openttd.c
|
@ -52,6 +52,7 @@
|
|||
#include "genworld.h"
|
||||
#include "date.h"
|
||||
#include "clear_map.h"
|
||||
#include "fontcache.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
@ -432,10 +433,15 @@ int ttd_main(int argc, char *argv[])
|
|||
MxInitialize(11025);
|
||||
SoundInitialize("sample.cat");
|
||||
|
||||
/* Initialize FreeType */
|
||||
InitFreeType();
|
||||
|
||||
// This must be done early, since functions use the InvalidateWindow* calls
|
||||
InitWindowSystem();
|
||||
|
||||
GfxLoadSprites();
|
||||
/* Initialize the unicode to sprite mapping table */
|
||||
InitializeUnicodeGlyphMap();
|
||||
LoadStringWidthTable();
|
||||
|
||||
DEBUG(driver, 1) ("Loading drivers...");
|
||||
|
@ -1526,5 +1532,9 @@ bool AfterLoadGame(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (CheckSavegameVersion(37)) {
|
||||
ConvertNameArray();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
16
openttd.h
16
openttd.h
|
@ -464,6 +464,10 @@ enum {
|
|||
EXPENSES_OTHER = 12,
|
||||
};
|
||||
|
||||
enum {
|
||||
MAX_LANG = 64,
|
||||
};
|
||||
|
||||
// special string constants
|
||||
enum SpecialStrings {
|
||||
|
||||
|
@ -506,17 +510,17 @@ enum SpecialStrings {
|
|||
SPECSTR_PRESIDENT_NAME = 0x70E7,
|
||||
SPECSTR_SONGNAME = 0x70E8,
|
||||
|
||||
// reserve 32 strings for the *.lng files
|
||||
// reserve MAX_LANG strings for the *.lng files
|
||||
SPECSTR_LANGUAGE_START = 0x7100,
|
||||
SPECSTR_LANGUAGE_END = 0x711f,
|
||||
SPECSTR_LANGUAGE_END = SPECSTR_LANGUAGE_START + MAX_LANG - 1,
|
||||
|
||||
// reserve 32 strings for various screen resolutions
|
||||
SPECSTR_RESOLUTION_START = 0x7120,
|
||||
SPECSTR_RESOLUTION_END = 0x713f,
|
||||
SPECSTR_RESOLUTION_START = SPECSTR_LANGUAGE_END + 1,
|
||||
SPECSTR_RESOLUTION_END = SPECSTR_RESOLUTION_START + 0x1F,
|
||||
|
||||
// reserve 32 strings for screenshot formats
|
||||
SPECSTR_SCREENSHOT_START = 0x7140,
|
||||
SPECSTR_SCREENSHOT_END = 0x715F,
|
||||
SPECSTR_SCREENSHOT_START = SPECSTR_RESOLUTION_END + 1,
|
||||
SPECSTR_SCREENSHOT_END = SPECSTR_SCREENSHOT_START + 0x1F,
|
||||
|
||||
// Used to implement SetDParamStr
|
||||
STR_SPEC_DYNSTRING = 0xF800,
|
||||
|
|
|
@ -234,6 +234,9 @@
|
|||
<File
|
||||
RelativePath=".\fios.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\fontcache.c">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\genworld.c">
|
||||
</File>
|
||||
|
@ -478,6 +481,9 @@
|
|||
<File
|
||||
RelativePath=".\fileio.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\fontcache.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\functions.h">
|
||||
</File>
|
||||
|
@ -853,6 +859,9 @@
|
|||
<File
|
||||
RelativePath=".\table\clear_land.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\table\control_codes.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\table\elrail_data.h">
|
||||
</File>
|
||||
|
@ -910,6 +919,9 @@
|
|||
<File
|
||||
RelativePath=".\table\tunnel_land.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\table\unicode.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\table\unmovable_land.h">
|
||||
</File>
|
||||
|
|
|
@ -560,6 +560,10 @@
|
|||
RelativePath=".\fios.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\fontcache.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\genworld.c"
|
||||
>
|
||||
|
@ -931,6 +935,10 @@
|
|||
RelativePath=".\fileio.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\fontcache.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\functions.h"
|
||||
>
|
||||
|
@ -1435,6 +1443,10 @@
|
|||
RelativePath=".\table\clear_land.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\table\control_codes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\table\elrail_data.h"
|
||||
>
|
||||
|
@ -1511,6 +1523,10 @@
|
|||
RelativePath=".\table\tunnel_land.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\table\unicode.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\table\unmovable_land.h"
|
||||
>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "variables.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
const uint16 SAVEGAME_VERSION = 36;
|
||||
const uint16 SAVEGAME_VERSION = 37;
|
||||
uint16 _sl_version; /// the major savegame version identifier
|
||||
byte _sl_minor_version; /// the minor savegame version, DO NOT USE!
|
||||
|
||||
|
|
12
settings.c
12
settings.c
|
@ -38,6 +38,10 @@
|
|||
#include "newgrf.h"
|
||||
#include "genworld.h"
|
||||
#include "date.h"
|
||||
#ifdef WITH_FREETYPE
|
||||
#include "gfx.h"
|
||||
#include "fontcache.h"
|
||||
#endif
|
||||
|
||||
/** The patch values that are used for new games and/or modified in config file */
|
||||
Patches _patches_newgame;
|
||||
|
@ -1186,6 +1190,14 @@ static const SettingDescGlobVarList _misc_settings[] = {
|
|||
SDTG_STR("screenshot_format",SLE_STRB, S, 0, _screenshot_format_name,NULL, STR_NULL, NULL),
|
||||
SDTG_STR("savegame_format", SLE_STRB, S, 0, _savegame_format, NULL, STR_NULL, NULL),
|
||||
SDTG_BOOL("rightclick_emulate", S, 0, _rightclick_emulate, false, STR_NULL, NULL),
|
||||
#ifdef WITH_FREETYPE
|
||||
SDTG_STR("small_font", SLE_STRB, S, 0, _freetype.small_font, NULL, STR_NULL, NULL),
|
||||
SDTG_STR("medium_font", SLE_STRB, S, 0, _freetype.medium_font, NULL, STR_NULL, NULL),
|
||||
SDTG_STR("large_font", SLE_STRB, S, 0, _freetype.large_font, NULL, STR_NULL, NULL),
|
||||
SDTG_VAR("small_size", SLE_UINT, S, 0, _freetype.small_size, 6, 0, 72, 0, STR_NULL, NULL),
|
||||
SDTG_VAR("medium_size", SLE_UINT, S, 0, _freetype.medium_size, 10, 0, 72, 0, STR_NULL, NULL),
|
||||
SDTG_VAR("large_size", SLE_UINT, S, 0, _freetype.large_size, 16, 0, 72, 0, STR_NULL, NULL),
|
||||
#endif
|
||||
SDTG_END()
|
||||
};
|
||||
|
||||
|
|
202
strgen/strgen.c
202
strgen/strgen.c
|
@ -3,6 +3,7 @@
|
|||
#include "../stdafx.h"
|
||||
#include "../macros.h"
|
||||
#include "../string.h"
|
||||
#include "../table/control_codes.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -199,26 +200,41 @@ static void PutByte(byte c)
|
|||
}
|
||||
|
||||
|
||||
static void EmitSingleByte(char *buf, int value)
|
||||
static void PutUtf8(uint32 value)
|
||||
{
|
||||
if (*buf != '\0') warning("Ignoring trailing letters in command");
|
||||
PutByte((byte)value);
|
||||
if (value < 0x80) {
|
||||
PutByte(value);
|
||||
} else if (value < 0x800) {
|
||||
PutByte(0xC0 + GB(value, 6, 5));
|
||||
PutByte(0x80 + GB(value, 0, 6));
|
||||
} else if (value < 0x10000) {
|
||||
PutByte(0xE0 + GB(value, 12, 4));
|
||||
PutByte(0x80 + GB(value, 6, 6));
|
||||
PutByte(0x80 + GB(value, 0, 6));
|
||||
} else if (value < 0x110000) {
|
||||
PutByte(0xF0 + GB(value, 18, 3));
|
||||
PutByte(0x80 + GB(value, 12, 6));
|
||||
PutByte(0x80 + GB(value, 6, 6));
|
||||
PutByte(0x80 + GB(value, 0, 6));
|
||||
} else {
|
||||
warning("Invalid unicode value U+0x%X\n", value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void EmitEscapedByte(char *buf, int value)
|
||||
static void EmitSingleChar(char *buf, int value)
|
||||
{
|
||||
if (*buf != '\0') warning("Ignoring trailing letters in command");
|
||||
PutByte(0x85);
|
||||
PutByte((byte)value);
|
||||
PutUtf8(value);
|
||||
}
|
||||
|
||||
|
||||
static void EmitSetX(char *buf, int value)
|
||||
{
|
||||
char *err;
|
||||
int x = strtol(buf, &err, 0);
|
||||
if (*err != 0) fatal("SetX param invalid");
|
||||
PutByte(1);
|
||||
PutUtf8(SCC_SETX);
|
||||
PutByte((byte)x);
|
||||
}
|
||||
|
||||
|
@ -234,7 +250,7 @@ static void EmitSetXY(char *buf, int value)
|
|||
y = strtol(err + 1, &err, 0);
|
||||
if (*err != 0) fatal("SetXY param invalid");
|
||||
|
||||
PutByte(2);
|
||||
PutUtf8(SCC_SETXY);
|
||||
PutByte((byte)x);
|
||||
PutByte((byte)y);
|
||||
}
|
||||
|
@ -352,7 +368,7 @@ static void EmitPlural(char *buf, int value)
|
|||
}
|
||||
}
|
||||
|
||||
PutByte(0x8D);
|
||||
PutUtf8(SCC_PLURAL_LIST);
|
||||
PutByte(TranslateArgumentIdx(argidx));
|
||||
EmitWordList(words, nw);
|
||||
}
|
||||
|
@ -372,7 +388,7 @@ static void EmitGender(char *buf, int value)
|
|||
if (strcmp(buf, _genders[nw]) == 0) break;
|
||||
}
|
||||
// now nw contains the gender index
|
||||
PutByte(0x87);
|
||||
PutUtf8(SCC_GENDER_INDEX);
|
||||
PutByte(nw);
|
||||
} else {
|
||||
const char* words[8];
|
||||
|
@ -386,8 +402,7 @@ static void EmitGender(char *buf, int value)
|
|||
if (words[nw] == NULL) break;
|
||||
}
|
||||
if (nw != _numgenders) fatal("Bad # of arguments for gender command");
|
||||
PutByte(0x85);
|
||||
PutByte(13);
|
||||
PutUtf8(SCC_GENDER_LIST);
|
||||
PutByte(TranslateArgumentIdx(argidx));
|
||||
EmitWordList(words, nw);
|
||||
}
|
||||
|
@ -396,109 +411,108 @@ static void EmitGender(char *buf, int value)
|
|||
|
||||
static const CmdStruct _cmd_structs[] = {
|
||||
// Update position
|
||||
{"SETX", EmitSetX, 1, 0, 0},
|
||||
{"SETXY", EmitSetXY, 2, 0, 0},
|
||||
{"SETX", EmitSetX, SCC_SETX, 0, 0},
|
||||
{"SETXY", EmitSetXY, SCC_SETXY, 0, 0},
|
||||
|
||||
// Font size
|
||||
{"TINYFONT", EmitSingleByte, 8, 0, 0},
|
||||
{"BIGFONT", EmitSingleByte, 9, 0, 0},
|
||||
{"TINYFONT", EmitSingleChar, SCC_TINYFONT, 0, 0},
|
||||
{"BIGFONT", EmitSingleChar, SCC_BIGFONT, 0, 0},
|
||||
|
||||
// Colors
|
||||
{"BLUE", EmitSingleByte, 15, 0, 0},
|
||||
{"SILVER", EmitSingleByte, 16, 0, 0},
|
||||
{"GOLD", EmitSingleByte, 17, 0, 0},
|
||||
{"RED", EmitSingleByte, 18, 0, 0},
|
||||
{"PURPLE", EmitSingleByte, 19, 0, 0},
|
||||
{"LTBROWN", EmitSingleByte, 20, 0, 0},
|
||||
{"ORANGE", EmitSingleByte, 21, 0, 0},
|
||||
{"GREEN", EmitSingleByte, 22, 0, 0},
|
||||
{"YELLOW", EmitSingleByte, 23, 0, 0},
|
||||
{"DKGREEN", EmitSingleByte, 24, 0, 0},
|
||||
{"CREAM", EmitSingleByte, 25, 0, 0},
|
||||
{"BROWN", EmitSingleByte, 26, 0, 0},
|
||||
{"WHITE", EmitSingleByte, 27, 0, 0},
|
||||
{"LTBLUE", EmitSingleByte, 28, 0, 0},
|
||||
{"GRAY", EmitSingleByte, 29, 0, 0},
|
||||
{"DKBLUE", EmitSingleByte, 30, 0, 0},
|
||||
{"BLACK", EmitSingleByte, 31, 0, 0},
|
||||
{"BLUE", EmitSingleChar, SCC_BLUE, 0, 0},
|
||||
{"SILVER", EmitSingleChar, SCC_SILVER, 0, 0},
|
||||
{"GOLD", EmitSingleChar, SCC_GOLD, 0, 0},
|
||||
{"RED", EmitSingleChar, SCC_RED, 0, 0},
|
||||
{"PURPLE", EmitSingleChar, SCC_PURPLE, 0, 0},
|
||||
{"LTBROWN", EmitSingleChar, SCC_LTBROWN, 0, 0},
|
||||
{"ORANGE", EmitSingleChar, SCC_ORANGE, 0, 0},
|
||||
{"GREEN", EmitSingleChar, SCC_GREEN, 0, 0},
|
||||
{"YELLOW", EmitSingleChar, SCC_YELLOW, 0, 0},
|
||||
{"DKGREEN", EmitSingleChar, SCC_DKGREEN, 0, 0},
|
||||
{"CREAM", EmitSingleChar, SCC_CREAM, 0, 0},
|
||||
{"BROWN", EmitSingleChar, SCC_BROWN, 0, 0},
|
||||
{"WHITE", EmitSingleChar, SCC_WHITE, 0, 0},
|
||||
{"LTBLUE", EmitSingleChar, SCC_LTBLUE, 0, 0},
|
||||
{"GRAY", EmitSingleChar, SCC_GRAY, 0, 0},
|
||||
{"DKBLUE", EmitSingleChar, SCC_DKBLUE, 0, 0},
|
||||
{"BLACK", EmitSingleChar, SCC_BLACK, 0, 0},
|
||||
|
||||
{"CURRCOMPACT", EmitEscapedByte, 0, 1, 0}, // compact currency (32 bits)
|
||||
{"REV", EmitEscapedByte, 2, 0, 0}, // openttd revision string
|
||||
{"SHORTCARGO", EmitEscapedByte, 3, 2, 0}, // short cargo description, only ### tons, or ### litres
|
||||
{"CURRCOMPACT64", EmitEscapedByte, 4, 2, 0}, // compact currency 64 bits
|
||||
{"CURRCOMPACT", EmitSingleChar, SCC_CURRENCY_COMPACT, 1, 0}, // compact currency (32 bits)
|
||||
{"REV", EmitSingleChar, SCC_REVISION, 0, 0}, // openttd revision string
|
||||
{"SHORTCARGO", EmitSingleChar, SCC_CARGO_SHORT, 2, 0}, // short cargo description, only ### tons, or ### litres
|
||||
{"CURRCOMPACT64", EmitSingleChar, SCC_CURRENCY_COMPACT_64, 2, 0}, // compact currency 64 bits
|
||||
|
||||
// These are special versions of {STRING1}
|
||||
// The first string includes the second string.
|
||||
{"COMPANY", EmitEscapedByte, 5, 1, 0},
|
||||
{"PLAYERNAME", EmitEscapedByte, 5, 1, 0},
|
||||
{"VEHICLE", EmitEscapedByte, 5, 1, 0},
|
||||
{"COMPANY", EmitSingleChar, SCC_STRING1, 1, 0},
|
||||
{"PLAYERNAME", EmitSingleChar, SCC_STRING1, 1, 0},
|
||||
{"VEHICLE", EmitSingleChar, SCC_STRING1, 1, 0},
|
||||
|
||||
{"STRING1", EmitEscapedByte, 5, 1, C_CASE}, // included string that consumes ONE argument
|
||||
{"STRING2", EmitEscapedByte, 6, 2, C_CASE}, // included string that consumes TWO arguments
|
||||
{"STRING3", EmitEscapedByte, 7, 3, C_CASE}, // included string that consumes THREE arguments
|
||||
{"STRING4", EmitEscapedByte, 8, 4, C_CASE}, // included string that consumes FOUR arguments
|
||||
{"STRING5", EmitEscapedByte, 9, 5, C_CASE}, // included string that consumes FIVE arguments
|
||||
{"STRING1", EmitSingleChar, SCC_STRING1, 1, C_CASE}, // included string that consumes ONE argument
|
||||
{"STRING2", EmitSingleChar, SCC_STRING2, 2, C_CASE}, // included string that consumes TWO arguments
|
||||
{"STRING3", EmitSingleChar, SCC_STRING3, 3, C_CASE}, // included string that consumes THREE arguments
|
||||
{"STRING4", EmitSingleChar, SCC_STRING4, 4, C_CASE}, // included string that consumes FOUR arguments
|
||||
{"STRING5", EmitSingleChar, SCC_STRING5, 5, C_CASE}, // included string that consumes FIVE arguments
|
||||
|
||||
{"STATIONFEATURES", EmitEscapedByte, 10, 1, 0}, // station features string, icons of the features
|
||||
{"INDUSTRY", EmitEscapedByte, 11, 1, 0}, // industry, takes an industry #
|
||||
{"VOLUME", EmitEscapedByte, 12, 1, 0},
|
||||
{"DATE_TINY", EmitEscapedByte, 14, 1, 0},
|
||||
{"CARGO", EmitEscapedByte, 15, 2, 0},
|
||||
{"POWER", EmitEscapedByte, 16, 1, 0},
|
||||
{"VOLUME_S", EmitEscapedByte, 17, 1, 0},
|
||||
{"WEIGHT", EmitEscapedByte, 18, 1, 0},
|
||||
{"WEIGHT_S", EmitEscapedByte, 19, 1, 0},
|
||||
{"FORCE", EmitEscapedByte, 20, 1, 0},
|
||||
{"STATIONFEATURES", EmitSingleChar, SCC_STATION_FEATURES, 1, 0}, // station features string, icons of the features
|
||||
{"INDUSTRY", EmitSingleChar, SCC_INDUSTRY_NAME, 1, 0}, // industry, takes an industry #
|
||||
{"CARGO", EmitSingleChar, SCC_CARGO, 2, 0},
|
||||
{"POWER", EmitSingleChar, SCC_POWER, 1, 0},
|
||||
{"VOLUME", EmitSingleChar, SCC_VOLUME, 1, 0},
|
||||
{"VOLUME_S", EmitSingleChar, SCC_VOLUME_SHORT, 1, 0},
|
||||
{"WEIGHT", EmitSingleChar, SCC_WEIGHT, 1, 0},
|
||||
{"WEIGHT_S", EmitSingleChar, SCC_WEIGHT_SHORT, 1, 0},
|
||||
{"FORCE", EmitSingleChar, SCC_FORCE, 1, 0},
|
||||
{"VELOCITY", EmitSingleChar, SCC_VELOCITY, 1, 0},
|
||||
|
||||
{"P", EmitPlural, 0, 0, C_DONTCOUNT}, // plural specifier
|
||||
{"G", EmitGender, 0, 0, C_DONTCOUNT}, // gender specifier
|
||||
|
||||
{"DATE_LONG", EmitSingleByte, 0x82, 1, 0},
|
||||
{"DATE_SHORT", EmitSingleByte, 0x83, 1, 0},
|
||||
{"DATE_TINY", EmitSingleChar, SCC_DATE_TINY, 1, 0},
|
||||
{"DATE_SHORT", EmitSingleChar, SCC_DATE_SHORT, 1, 0},
|
||||
{"DATE_LONG", EmitSingleChar, SCC_DATE_LONG, 1, 0},
|
||||
|
||||
{"VELOCITY", EmitSingleByte, 0x84, 1, 0},
|
||||
{"SKIP", EmitSingleChar, SCC_SKIP, 1, 0},
|
||||
|
||||
// 0x85 is the marker for escaped commands
|
||||
|
||||
{"SKIP", EmitSingleByte, 0x86, 1, 0},
|
||||
|
||||
{"STRING", EmitSingleByte, 0x88, 1, C_CASE},
|
||||
{"STRING", EmitSingleChar, SCC_STRING, 1, C_CASE},
|
||||
|
||||
// Numbers
|
||||
{"COMMA", EmitSingleByte, 0x8B, 1, 0}, // Number with comma
|
||||
{"NUM", EmitSingleByte, 0x8E, 1, 0}, // Signed number
|
||||
{"COMMA", EmitSingleChar, SCC_COMMA, 1, 0}, // Number with comma
|
||||
{"NUM", EmitSingleChar, SCC_NUM, 1, 0}, // Signed number
|
||||
|
||||
{"CURRENCY", EmitSingleByte, 0x8F, 1, 0},
|
||||
{"CURRENCY64", EmitSingleByte, 0x9C, 2, 0},
|
||||
{"CURRENCY", EmitSingleChar, SCC_CURRENCY, 1, 0},
|
||||
{"CURRENCY64", EmitSingleChar, SCC_CURRENCY_64, 2, 0},
|
||||
|
||||
{"WAYPOINT", EmitSingleByte, 0x99, 1, 0}, // waypoint name
|
||||
{"STATION", EmitSingleByte, 0x9A, 1, 0},
|
||||
{"TOWN", EmitSingleByte, 0x9B, 1, 0},
|
||||
{"WAYPOINT", EmitSingleChar, SCC_WAYPOINT_NAME, 1, 0}, // waypoint name
|
||||
{"STATION", EmitSingleChar, SCC_STATION_NAME, 1, 0},
|
||||
{"TOWN", EmitSingleChar, SCC_TOWN_NAME, 1, 0},
|
||||
|
||||
// 0x9D is used for the pseudo command SETCASE
|
||||
// 0x9E is used for case switching
|
||||
|
||||
{"", EmitSingleByte, '\n', 0, C_DONTCOUNT},
|
||||
{"{", EmitSingleByte, '{', 0, C_DONTCOUNT},
|
||||
{"UPARROW", EmitSingleByte, 0x80, 0, 0},
|
||||
{"SMALLUPARROW", EmitSingleByte, 0x90, 0, 0},
|
||||
{"SMALLDOWNARROW", EmitSingleByte, 0x91, 0, 0},
|
||||
{"TRAIN", EmitSingleByte, 0x94, 0, 0},
|
||||
{"LORRY", EmitSingleByte, 0x95, 0, 0},
|
||||
{"BUS", EmitSingleByte, 0x96, 0, 0},
|
||||
{"PLANE", EmitSingleByte, 0x97, 0, 0},
|
||||
{"SHIP", EmitSingleByte, 0x98, 0, 0},
|
||||
{"NBSP", EmitSingleByte, 0xA0, 0, C_DONTCOUNT},
|
||||
{"CENT", EmitSingleByte, '¢', 0, C_DONTCOUNT},
|
||||
{"POUNDSIGN", EmitSingleByte, '£', 0, C_DONTCOUNT},
|
||||
{"EURO", EmitSingleByte, '¤', 0, C_DONTCOUNT},
|
||||
{"YENSIGN", EmitSingleByte, '¥', 0, C_DONTCOUNT},
|
||||
{"COPYRIGHT", EmitSingleByte, '©', 0, C_DONTCOUNT},
|
||||
{"DOWNARROW", EmitSingleByte, 0xAA, 0, C_DONTCOUNT},
|
||||
{"CHECKMARK", EmitSingleByte, 0xAC, 0, C_DONTCOUNT},
|
||||
{"CROSS", EmitSingleByte, 0xAD, 0, C_DONTCOUNT},
|
||||
{"REGISTERED", EmitSingleByte, '®', 0, C_DONTCOUNT},
|
||||
{"RIGHTARROW", EmitSingleByte, 0xAF, 0, C_DONTCOUNT},
|
||||
{"", EmitSingleChar, '\n', 0, C_DONTCOUNT},
|
||||
{"{", EmitSingleChar, '{', 0, C_DONTCOUNT},
|
||||
{"UPARROW", EmitSingleChar, SCC_UPARROW, 0, 0},
|
||||
{"SMALLUPARROW", EmitSingleChar, SCC_SMALLUPARROW, 0, 0},
|
||||
{"SMALLDOWNARROW", EmitSingleChar, SCC_SMALLDOWNARROW, 0, 0},
|
||||
{"TRAIN", EmitSingleChar, SCC_TRAIN, 0, 0},
|
||||
{"LORRY", EmitSingleChar, SCC_LORRY, 0, 0},
|
||||
{"BUS", EmitSingleChar, SCC_BUS, 0, 0},
|
||||
{"PLANE", EmitSingleChar, SCC_PLANE, 0, 0},
|
||||
{"SHIP", EmitSingleChar, SCC_SHIP, 0, 0},
|
||||
{"NBSP", EmitSingleChar, 0xA0, 0, C_DONTCOUNT},
|
||||
{"CENT", EmitSingleChar, 0xA2, 0, C_DONTCOUNT},
|
||||
{"POUNDSIGN", EmitSingleChar, 0xA3, 0, C_DONTCOUNT},
|
||||
{"EURO", EmitSingleChar, 0x20AC, 0, C_DONTCOUNT},
|
||||
{"YENSIGN", EmitSingleChar, 0xA5, 0, C_DONTCOUNT},
|
||||
{"COPYRIGHT", EmitSingleChar, 0xA9, 0, C_DONTCOUNT},
|
||||
{"DOWNARROW", EmitSingleChar, SCC_DOWNARROW, 0, C_DONTCOUNT},
|
||||
{"CHECKMARK", EmitSingleChar, SCC_CHECKMARK, 0, C_DONTCOUNT},
|
||||
{"CROSS", EmitSingleChar, SCC_CROSS, 0, C_DONTCOUNT},
|
||||
{"REGISTERED", EmitSingleChar, 0xAE, 0, C_DONTCOUNT},
|
||||
{"RIGHTARROW", EmitSingleChar, SCC_RIGHTARROW, 0, C_DONTCOUNT},
|
||||
{"SMALLLEFTARROW", EmitSingleChar, SCC_LESSTHAN, 0, C_DONTCOUNT},
|
||||
{"SMALLRIGHTARROW",EmitSingleChar, SCC_GREATERTHAN, 0, C_DONTCOUNT},
|
||||
};
|
||||
|
||||
|
||||
|
@ -1028,7 +1042,7 @@ static int TranslateArgumentIdx(int argidx)
|
|||
|
||||
static void PutArgidxCommand(void)
|
||||
{
|
||||
PutByte(0x8C);
|
||||
PutUtf8(SCC_ARG_INDEX);
|
||||
PutByte(TranslateArgumentIdx(_cur_argidx));
|
||||
}
|
||||
|
||||
|
@ -1052,7 +1066,7 @@ static void PutCommandString(const char *str)
|
|||
if (cs == NULL) break;
|
||||
|
||||
if (casei != -1) {
|
||||
PutByte(0x9D); // {SETCASE}
|
||||
PutUtf8(SCC_SETCASE); // {SETCASE}
|
||||
PutByte(casei);
|
||||
}
|
||||
|
||||
|
@ -1163,7 +1177,7 @@ static void WriteLangfile(const char *filename, int show_todo)
|
|||
// It has this format
|
||||
// <0x9E> <NUM CASES> <CASE1> <LEN1> <STRING1> <CASE2> <LEN2> <STRING2> <CASE3> <LEN3> <STRING3> <STRINGDEFAULT>
|
||||
// Each LEN is printed using 2 bytes in big endian order.
|
||||
PutByte(0x9E);
|
||||
PutUtf8(SCC_SWITCH_CASE);
|
||||
// Count the number of cases
|
||||
for (num = 0, c = casep; c; c = c->next) num++;
|
||||
PutByte(num);
|
||||
|
|
124
string.c
124
string.c
|
@ -4,6 +4,8 @@
|
|||
#include "openttd.h"
|
||||
#include "functions.h"
|
||||
#include "string.h"
|
||||
#include "macros.h"
|
||||
#include "table/control_codes.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h> // required for tolower()
|
||||
|
@ -68,8 +70,27 @@ char* CDECL str_fmt(const char* str, ...)
|
|||
|
||||
void str_validate(char *str)
|
||||
{
|
||||
for (; *str != '\0'; str++)
|
||||
if (!IsValidAsciiChar(*str, CS_ALPHANUMERAL)) *str = '?';
|
||||
char *dst = str;
|
||||
WChar c;
|
||||
size_t len = Utf8Decode(&c, str);
|
||||
|
||||
for (; c != '\0'; len = Utf8Decode(&c, str)) {
|
||||
if (IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END ||
|
||||
IsValidChar(c - SCC_SPRITE_START, CS_ALPHANUMERAL))) {
|
||||
/* Copy the character back. Even if dst is current the same as str
|
||||
* (i.e. no characters have been changed) this is quicker than
|
||||
* moving the pointers ahead by len */
|
||||
do {
|
||||
*dst++ = *str++;
|
||||
} while (--len);
|
||||
} else {
|
||||
/* Replace the undesirable character with a question mark */
|
||||
str += len;
|
||||
*dst++ = '?';
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
void str_strip_colours(char *str)
|
||||
|
@ -92,29 +113,15 @@ void str_strip_colours(char *str)
|
|||
* @param afilter the filter to use
|
||||
* @return true or false depending if the character is printable/valid or not
|
||||
*/
|
||||
bool IsValidAsciiChar(byte key, CharSetFilter afilter)
|
||||
bool IsValidChar(WChar key, CharSetFilter afilter)
|
||||
{
|
||||
bool firsttest = false;
|
||||
|
||||
switch (afilter) {
|
||||
case CS_ALPHANUMERAL:
|
||||
firsttest = (key >= ' ' && key < 127);
|
||||
break;
|
||||
|
||||
/* We are very strict here */
|
||||
case CS_NUMERAL:
|
||||
return (key >= '0' && key <= '9');
|
||||
|
||||
case CS_ALPHA:
|
||||
default:
|
||||
firsttest = ((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z'));
|
||||
break;
|
||||
case CS_ALPHANUMERAL: return IsPrintable(key);
|
||||
case CS_NUMERAL: return (key >= '0' && key <= '9');
|
||||
case CS_ALPHA: return IsPrintable(key) && !(key >= '0' && key <= '9');
|
||||
}
|
||||
|
||||
/* Allow some special chars too that are non-ASCII but still valid (like '^' above 'a') */
|
||||
return (firsttest || (key >= 160 &&
|
||||
key != 0xAA && key != 0xAC && key != 0xAD && key != 0xAF &&
|
||||
key != 0xB5 && key != 0xB6 && key != 0xB7 && key != 0xB9));
|
||||
return false;
|
||||
}
|
||||
|
||||
void strtolower(char *str)
|
||||
|
@ -145,3 +152,78 @@ int CDECL vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
|||
#endif /* _MSC_VER */
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
|
||||
/* UTF-8 handling routines */
|
||||
|
||||
|
||||
/* Decode and consume the next UTF-8 encoded character
|
||||
* @param c Buffer to place decoded character.
|
||||
* @param s Character stream to retrieve character from.
|
||||
* @return Number of characters in the sequence.
|
||||
*/
|
||||
size_t Utf8Decode(WChar *c, const char *s)
|
||||
{
|
||||
assert(c != NULL);
|
||||
|
||||
if (!HASBIT(s[0], 7)) {
|
||||
/* Single byte character: 0xxxxxxx */
|
||||
*c = s[0];
|
||||
return 1;
|
||||
} else if (GB(s[0], 5, 3) == 6) {
|
||||
if (IsUtf8Part(s[1])) {
|
||||
/* Double byte character: 110xxxxx 10xxxxxx */
|
||||
*c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6);
|
||||
if (*c >= 0x80) return 2;
|
||||
}
|
||||
} else if (GB(s[0], 4, 4) == 14) {
|
||||
if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) {
|
||||
/* Triple byte character: 1110xxxx 10xxxxxx 10xxxxxx */
|
||||
*c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6);
|
||||
if (*c >= 0x800) return 3;
|
||||
}
|
||||
} else if (GB(s[0], 3, 5) == 30) {
|
||||
if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) {
|
||||
/* 4 byte character: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
|
||||
*c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6);
|
||||
if (*c >= 0x10000 && *c <= 0x10FFFF) return 4;
|
||||
}
|
||||
}
|
||||
|
||||
//DEBUG(misc, 1) ("Invalid UTF-8 sequence");
|
||||
*c = '?';
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Encode a unicode character and place it in the buffer
|
||||
* @param buf Buffer to place character.
|
||||
* @param c Unicode character to encode.
|
||||
* @return Number of characters in the encoded sequence.
|
||||
*/
|
||||
size_t Utf8Encode(char *buf, WChar c)
|
||||
{
|
||||
if (c < 0x80) {
|
||||
*buf = c;
|
||||
return 1;
|
||||
} else if (c < 0x800) {
|
||||
*buf++ = 0xC0 + GB(c, 6, 5);
|
||||
*buf = 0x80 + GB(c, 0, 6);
|
||||
return 2;
|
||||
} else if (c < 0x10000) {
|
||||
*buf++ = 0xE0 + GB(c, 12, 4);
|
||||
*buf++ = 0x80 + GB(c, 6, 6);
|
||||
*buf = 0x80 + GB(c, 0, 6);
|
||||
return 3;
|
||||
} else if (c < 0x110000) {
|
||||
*buf++ = 0xF0 + GB(c, 18, 3);
|
||||
*buf++ = 0x80 + GB(c, 12, 6);
|
||||
*buf++ = 0x80 + GB(c, 6, 6);
|
||||
*buf = 0x80 + GB(c, 0, 6);
|
||||
return 4;
|
||||
}
|
||||
|
||||
//DEBUG(misc, 1) ("Can't UTF-8 encode value 0x%X", c);
|
||||
*buf = '?';
|
||||
return 1;
|
||||
}
|
||||
|
|
56
string.h
56
string.h
|
@ -3,6 +3,8 @@
|
|||
#ifndef STRING_H
|
||||
#define STRING_H
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
/*
|
||||
* dst: destination buffer
|
||||
* src: string to copy/concatenate
|
||||
|
@ -33,7 +35,7 @@ void str_validate(char *str);
|
|||
void str_strip_colours(char *str);
|
||||
|
||||
/**
|
||||
* Valid filter types for IsValidAsciiChar.
|
||||
* Valid filter types for IsValidChar.
|
||||
*/
|
||||
typedef enum CharSetFilter {
|
||||
CS_ALPHANUMERAL, //! Both numeric and alphabetic and spaces and stuff
|
||||
|
@ -41,6 +43,11 @@ typedef enum CharSetFilter {
|
|||
CS_ALPHA, //! Only alphabetic values
|
||||
} CharSetFilter;
|
||||
|
||||
/** Convert the given string to lowercase */
|
||||
void strtolower(char *str);
|
||||
|
||||
typedef uint32 WChar;
|
||||
|
||||
/**
|
||||
* Only allow certain keys. You can define the filter to be used. This makes
|
||||
* sure no invalid keys can get into an editbox, like BELL.
|
||||
|
@ -48,9 +55,50 @@ typedef enum CharSetFilter {
|
|||
* @param afilter the filter to use
|
||||
* @return true or false depending if the character is printable/valid or not
|
||||
*/
|
||||
bool IsValidAsciiChar(byte key, CharSetFilter afilter);
|
||||
bool IsValidChar(WChar key, CharSetFilter afilter);
|
||||
|
||||
size_t Utf8Decode(WChar *c, const char *s);
|
||||
size_t Utf8Encode(char *buf, WChar c);
|
||||
|
||||
|
||||
static inline WChar Utf8Consume(const char **s)
|
||||
{
|
||||
WChar c;
|
||||
*s += Utf8Decode(&c, *s);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/** Return the length of a UTF-8 encoded character.
|
||||
* @param c Unicode character.
|
||||
* @return Length of UTF-8 encoding for character.
|
||||
*/
|
||||
static inline size_t Utf8CharLen(WChar c)
|
||||
{
|
||||
if (c < 0x80) return 1;
|
||||
if (c < 0x800) return 2;
|
||||
if (c < 0x10000) return 3;
|
||||
if (c < 0x110000) return 4;
|
||||
|
||||
/* Invalid valid, we encode as a '?' */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Check if the given character is part of a UTF8 sequence */
|
||||
static inline bool IsUtf8Part(char c)
|
||||
{
|
||||
return GB(c, 6, 2) == 2;
|
||||
}
|
||||
|
||||
|
||||
static inline bool IsPrintable(WChar c)
|
||||
{
|
||||
if (c < 0x20) return false;
|
||||
if (c < 0xE000) return true;
|
||||
if (c < 0xE200) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Convert the given string to lowercase */
|
||||
void strtolower(char *str);
|
||||
|
||||
#endif /* STRING_H */
|
||||
|
|
361
strings.c
361
strings.c
|
@ -18,6 +18,7 @@
|
|||
#include "variables.h"
|
||||
#include "newgrf_text.h"
|
||||
#include "table/landscape_const.h"
|
||||
#include "table/control_codes.h"
|
||||
#include "music.h"
|
||||
#include "date.h"
|
||||
#include "industry.h"
|
||||
|
@ -236,6 +237,14 @@ char *GetString(char *buffr, StringID string, const char* last)
|
|||
}
|
||||
|
||||
|
||||
char *InlineString(char *buf, StringID string)
|
||||
{
|
||||
buf += Utf8Encode(buf, SCC_STRING_ID);
|
||||
buf += Utf8Encode(buf, string);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
// This function takes a C-string and allocates a temporary string ID.
|
||||
// The duration of the bound string is valid only until the next GetString,
|
||||
// so be careful.
|
||||
|
@ -564,54 +573,57 @@ static const Units units[] = {
|
|||
static char* FormatString(char* buff, const char* str, const int32* argv, uint casei, const char* last)
|
||||
{
|
||||
extern const char _openttd_revision[];
|
||||
byte b;
|
||||
WChar b;
|
||||
const int32 *argv_orig = argv;
|
||||
uint modifier = 0;
|
||||
|
||||
while ((b = *str++) != '\0') {
|
||||
while ((b = Utf8Consume(&str)) != '\0') {
|
||||
switch (b) {
|
||||
case 0x1: // {SETX}
|
||||
if (buff != last && buff + 1 != last) {
|
||||
*buff++ = b;
|
||||
*buff++ = *str++;
|
||||
}
|
||||
break;
|
||||
case 0x2: // {SETXY}
|
||||
if (buff != last && buff + 1 != last && buff + 2 != last) {
|
||||
*buff++ = b;
|
||||
*buff++ = *str++;
|
||||
*buff++ = *str++;
|
||||
}
|
||||
break;
|
||||
case SCC_SETX: // {SETX}
|
||||
if (buff + Utf8CharLen(SCC_SETX) + 1 < last) {
|
||||
buff += Utf8Encode(buff, SCC_SETX);
|
||||
*buff++ = *str++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81: // {STRINL}
|
||||
buff = GetStringWithArgs(buff, ReadLE16Unaligned(str), argv, last);
|
||||
str += 2;
|
||||
break;
|
||||
case 0x82: // {DATE_LONG}
|
||||
buff = FormatYmdString(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
case 0x83: // {DATE_SHORT}
|
||||
buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
case 0x84: {// {VELOCITY}
|
||||
int32 args[1];
|
||||
assert(_opt_ptr->units < lengthof(units));
|
||||
args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s;
|
||||
buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last);
|
||||
modifier = 0;
|
||||
break;
|
||||
}
|
||||
// 0x85 is used as escape character..
|
||||
case 0x85:
|
||||
switch (*str++) {
|
||||
case 0: /* {CURRCOMPACT} */
|
||||
case SCC_SETXY: // {SETXY}
|
||||
if (buff + Utf8CharLen(SCC_SETXY) + 2 < last) {
|
||||
buff += Utf8Encode(buff, SCC_SETXY);
|
||||
*buff++ = *str++;
|
||||
*buff++ = *str++;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCC_STRING_ID: // {STRINL}
|
||||
buff = GetStringWithArgs(buff, Utf8Consume(&str), argv, last);
|
||||
break;
|
||||
|
||||
case SCC_DATE_LONG: // {DATE_LONG}
|
||||
buff = FormatYmdString(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
|
||||
case SCC_DATE_SHORT: // {DATE_SHORT}
|
||||
buff = FormatMonthAndYear(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
|
||||
case SCC_VELOCITY: {// {VELOCITY}
|
||||
int32 args[1];
|
||||
assert(_opt_ptr->units < lengthof(units));
|
||||
args[0] = GetInt32(&argv) * units[_opt_ptr->units].s_m >> units[_opt_ptr->units].s_s;
|
||||
buff = FormatString(buff, GetStringPtr(units[_opt_ptr->units].velocity), args, modifier >> 24, last);
|
||||
modifier = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_CURRENCY_COMPACT: /* {CURRCOMPACT} */
|
||||
buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), true, last);
|
||||
break;
|
||||
case 2: /* {REV} */
|
||||
|
||||
case SCC_REVISION: /* {REV} */
|
||||
buff = strecpy(buff, _openttd_revision, last);
|
||||
break;
|
||||
case 3: { /* {SHORTCARGO} */
|
||||
|
||||
case SCC_CARGO_SHORT: { /* {SHORTCARGO} */
|
||||
// Short description of cargotypes. Layout:
|
||||
// 8-bit = cargo type
|
||||
// 16-bit = cargo count
|
||||
|
@ -642,40 +654,46 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
} break;
|
||||
case 4: {/* {CURRCOMPACT64} */
|
||||
|
||||
case SCC_CURRENCY_COMPACT_64: { /* {CURRCOMPACT64} */
|
||||
// 64 bit compact currency-unit
|
||||
buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), true, last);
|
||||
break;
|
||||
}
|
||||
case 5: { /* {STRING1} */
|
||||
|
||||
case SCC_STRING1: { /* {STRING1} */
|
||||
// String that consumes ONE argument
|
||||
uint str = modifier + GetInt32(&argv);
|
||||
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 1), last);
|
||||
modifier = 0;
|
||||
break;
|
||||
}
|
||||
case 6: { /* {STRING2} */
|
||||
|
||||
case SCC_STRING2: { /* {STRING2} */
|
||||
// String that consumes TWO arguments
|
||||
uint str = modifier + GetInt32(&argv);
|
||||
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 2), last);
|
||||
modifier = 0;
|
||||
break;
|
||||
}
|
||||
case 7: { /* {STRING3} */
|
||||
|
||||
case SCC_STRING3: { /* {STRING3} */
|
||||
// String that consumes THREE arguments
|
||||
uint str = modifier + GetInt32(&argv);
|
||||
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 3), last);
|
||||
modifier = 0;
|
||||
break;
|
||||
}
|
||||
case 8: { /* {STRING4} */
|
||||
|
||||
case SCC_STRING4: { /* {STRING4} */
|
||||
// String that consumes FOUR arguments
|
||||
uint str = modifier + GetInt32(&argv);
|
||||
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 4), last);
|
||||
modifier = 0;
|
||||
break;
|
||||
}
|
||||
case 9: { /* {STRING5} */
|
||||
|
||||
case SCC_STRING5: { /* {STRING5} */
|
||||
// String that consumes FIVE arguments
|
||||
uint str = modifier + GetInt32(&argv);
|
||||
buff = GetStringWithArgs(buff, str, GetArgvPtr(&argv, 5), last);
|
||||
|
@ -683,12 +701,12 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
|
||||
case 10: { /* {STATIONFEATURES} */
|
||||
case SCC_STATION_FEATURES: { /* {STATIONFEATURES} */
|
||||
buff = StationGetSpecialString(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
}
|
||||
|
||||
case 11: { /* {INDUSTRY} */
|
||||
case SCC_INDUSTRY_NAME: { /* {INDUSTRY} */
|
||||
const Industry* i = GetIndustry(GetInt32(&argv));
|
||||
int32 args[2];
|
||||
|
||||
|
@ -704,7 +722,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
|
||||
case 12: { // {VOLUME}
|
||||
case SCC_VOLUME: { // {VOLUME}
|
||||
int32 args[1];
|
||||
assert(_opt_ptr->units < lengthof(units));
|
||||
args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
|
||||
|
@ -713,22 +731,22 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
|
||||
case 13: { // {G 0 Der Die Das}
|
||||
const byte* s = (const byte*)GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender.
|
||||
case SCC_GENDER_LIST: { // {G 0 Der Die Das}
|
||||
const char* s = GetStringPtr(argv_orig[(byte)*str++]); // contains the string that determines gender.
|
||||
int len;
|
||||
int gender = 0;
|
||||
if (s != NULL && s[0] == 0x87) gender = s[1];
|
||||
if (s != NULL && Utf8Consume(&s) == SCC_GENDER_INDEX) gender = (byte)s[0];
|
||||
str = ParseStringChoice(str, gender, buff, &len);
|
||||
buff += len;
|
||||
break;
|
||||
}
|
||||
|
||||
case 14: { // {DATE_TINY}
|
||||
case SCC_DATE_TINY: { // {DATE_TINY}
|
||||
buff = FormatTinyDate(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
}
|
||||
|
||||
case 15: { // {CARGO}
|
||||
case SCC_CARGO: { // {CARGO}
|
||||
// Layout now is:
|
||||
// 8bit - cargo type
|
||||
// 16-bit - cargo count
|
||||
|
@ -738,7 +756,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
|
||||
case 16: { // {POWER}
|
||||
case SCC_POWER: { // {POWER}
|
||||
int32 args[1];
|
||||
assert(_opt_ptr->units < lengthof(units));
|
||||
args[0] = GetInt32(&argv) * units[_opt_ptr->units].p_m >> units[_opt_ptr->units].p_s;
|
||||
|
@ -747,7 +765,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
|
||||
case 17: { // {VOLUME_S}
|
||||
case SCC_VOLUME_SHORT: { // {VOLUME_S}
|
||||
int32 args[1];
|
||||
assert(_opt_ptr->units < lengthof(units));
|
||||
args[0] = GetInt32(&argv) * units[_opt_ptr->units].v_m >> units[_opt_ptr->units].v_s;
|
||||
|
@ -756,7 +774,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
|
||||
case 18: { // {WEIGHT}
|
||||
case SCC_WEIGHT: { // {WEIGHT}
|
||||
int32 args[1];
|
||||
assert(_opt_ptr->units < lengthof(units));
|
||||
args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
|
||||
|
@ -765,7 +783,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
|
||||
case 19: { // {WEIGHT_S}
|
||||
case SCC_WEIGHT_SHORT: { // {WEIGHT_S}
|
||||
int32 args[1];
|
||||
assert(_opt_ptr->units < lengthof(units));
|
||||
args[0] = GetInt32(&argv) * units[_opt_ptr->units].w_m >> units[_opt_ptr->units].w_s;
|
||||
|
@ -774,7 +792,7 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
|
||||
case 20: { // {FORCE}
|
||||
case SCC_FORCE: { // {FORCE}
|
||||
int32 args[1];
|
||||
assert(_opt_ptr->units < lengthof(units));
|
||||
args[0] = GetInt32(&argv) * units[_opt_ptr->units].f_m >> units[_opt_ptr->units].f_s;
|
||||
|
@ -783,124 +801,122 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error("!invalid escape sequence in string");
|
||||
case SCC_SKIP: // {SKIP}
|
||||
argv++;
|
||||
break;
|
||||
|
||||
// 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}
|
||||
str++;
|
||||
break;
|
||||
|
||||
case SCC_STRING: {// {STRING}
|
||||
uint str = modifier + GetInt32(&argv);
|
||||
// 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
|
||||
buff = GetStringWithArgs(buff, str, argv, last);
|
||||
modifier = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x86: // {SKIP}
|
||||
argv++;
|
||||
break;
|
||||
case SCC_COMMA: // {COMMA}
|
||||
buff = FormatCommaNumber(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
|
||||
// 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 0x87: // {GENDER 0}
|
||||
str++;
|
||||
break;
|
||||
case SCC_ARG_INDEX: // Move argument pointer
|
||||
argv = argv_orig + (byte)*str++;
|
||||
break;
|
||||
|
||||
case 0x88: {// {STRING}
|
||||
uint str = modifier + GetInt32(&argv);
|
||||
// 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
|
||||
buff = GetStringWithArgs(buff, str, argv, last);
|
||||
modifier = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8B: // {COMMA}
|
||||
buff = FormatCommaNumber(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
|
||||
case 0x8C: // Move argument pointer
|
||||
argv = argv_orig + (byte)*str++;
|
||||
break;
|
||||
|
||||
case 0x8D: { // {P}
|
||||
int32 v = argv_orig[(byte)*str++]; // contains the number that determines plural
|
||||
int len;
|
||||
str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
|
||||
buff += len;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x8E: // {NUM}
|
||||
buff = FormatNoCommaNumber(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
|
||||
case 0x8F: // {CURRENCY}
|
||||
buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last);
|
||||
break;
|
||||
|
||||
case 0x99: { // {WAYPOINT}
|
||||
int32 temp[2];
|
||||
Waypoint *wp = GetWaypoint(GetInt32(&argv));
|
||||
StringID str;
|
||||
if (wp->string != STR_NULL) {
|
||||
str = wp->string;
|
||||
} else {
|
||||
temp[0] = wp->town_index;
|
||||
temp[1] = wp->town_cn + 1;
|
||||
str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
|
||||
case SCC_PLURAL_LIST: { // {P}
|
||||
int32 v = argv_orig[(byte)*str++]; // contains the number that determines plural
|
||||
int len;
|
||||
str = ParseStringChoice(str, DeterminePluralForm(v), buff, &len);
|
||||
buff += len;
|
||||
break;
|
||||
}
|
||||
buff = GetStringWithArgs(buff, str, temp, last);
|
||||
} break;
|
||||
|
||||
case 0x9A: { // {STATION}
|
||||
const Station* st = GetStation(GetInt32(&argv));
|
||||
case SCC_NUM: // {NUM}
|
||||
buff = FormatNoCommaNumber(buff, GetInt32(&argv), last);
|
||||
break;
|
||||
|
||||
if (!IsValidStation(st)) { // station doesn't exist anymore
|
||||
buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
|
||||
} else {
|
||||
case SCC_CURRENCY: // {CURRENCY}
|
||||
buff = FormatGenericCurrency(buff, _currency, GetInt32(&argv), false, last);
|
||||
break;
|
||||
|
||||
case SCC_WAYPOINT_NAME: { // {WAYPOINT}
|
||||
int32 temp[2];
|
||||
temp[0] = st->town->townnametype;
|
||||
temp[1] = st->town->townnameparts;
|
||||
buff = GetStringWithArgs(buff, st->string_id, temp, last);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x9B: { // {TOWN}
|
||||
const Town* t = GetTown(GetInt32(&argv));
|
||||
int32 temp[1];
|
||||
|
||||
assert(IsValidTown(t));
|
||||
|
||||
temp[0] = t->townnameparts;
|
||||
buff = GetStringWithArgs(buff, t->townnametype, temp, last);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9C: { // {CURRENCY64}
|
||||
buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9D: { // {SETCASE}
|
||||
// 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.
|
||||
modifier = (byte)*str++ << 24;
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x9E: { // {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] == casei) {
|
||||
// Found the case, adjust str pointer and continue
|
||||
str += 3;
|
||||
break;
|
||||
Waypoint *wp = GetWaypoint(GetInt32(&argv));
|
||||
StringID str;
|
||||
if (wp->string != STR_NULL) {
|
||||
str = wp->string;
|
||||
} else {
|
||||
temp[0] = wp->town_index;
|
||||
temp[1] = wp->town_cn + 1;
|
||||
str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL;
|
||||
}
|
||||
// Otherwise skip to the next case
|
||||
str += 3 + (str[1] << 8) + str[2];
|
||||
num--;
|
||||
buff = GetStringWithArgs(buff, str, temp, last);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (buff != last) *buff++ = b;
|
||||
case SCC_STATION_NAME: { // {STATION}
|
||||
const Station* st = GetStation(GetInt32(&argv));
|
||||
|
||||
if (!IsValidStation(st)) { // station doesn't exist anymore
|
||||
buff = GetStringWithArgs(buff, STR_UNKNOWN_DESTINATION, NULL, last);
|
||||
} else {
|
||||
int32 temp[2];
|
||||
temp[0] = st->town->townnametype;
|
||||
temp[1] = st->town->townnameparts;
|
||||
buff = GetStringWithArgs(buff, st->string_id, temp, last);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_TOWN_NAME: { // {TOWN}
|
||||
const Town* t = GetTown(GetInt32(&argv));
|
||||
int32 temp[1];
|
||||
|
||||
assert(IsValidTown(t));
|
||||
|
||||
temp[0] = t->townnameparts;
|
||||
buff = GetStringWithArgs(buff, t->townnametype, temp, last);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_CURRENCY_64: { // {CURRENCY64}
|
||||
buff = FormatGenericCurrency(buff, _currency, GetInt64(&argv), false, last);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCC_SETCASE: { // {SETCASE}
|
||||
// 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.
|
||||
modifier = (byte)*str++ << 24;
|
||||
break;
|
||||
}
|
||||
|
||||
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] == casei) {
|
||||
// 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--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*buff = '\0';
|
||||
|
@ -910,11 +926,12 @@ static char* FormatString(char* buff, const char* str, const int32* argv, uint c
|
|||
|
||||
static char *StationGetSpecialString(char *buff, int x, const char* last)
|
||||
{
|
||||
if (x & 0x01) buff = strecpy(buff, "\x94", last);
|
||||
if (x & 0x02) buff = strecpy(buff, "\x95", last);
|
||||
if (x & 0x04) buff = strecpy(buff, "\x96", last);
|
||||
if (x & 0x08) buff = strecpy(buff, "\x97", last);
|
||||
if (x & 0x10) buff = strecpy(buff, "\x98", last);
|
||||
if ((x & 0x01) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN);
|
||||
if ((x & 0x02) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY);
|
||||
if ((x & 0x04) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS);
|
||||
if ((x & 0x08) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE);
|
||||
if ((x & 0x10) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP);
|
||||
*buff = '\0';
|
||||
return buff;
|
||||
}
|
||||
|
||||
|
@ -1122,7 +1139,7 @@ bool ReadLanguagePack(int lang_index)
|
|||
|
||||
{
|
||||
char *lang = str_fmt("%s%s", _path.lang_dir, _dynlang.ent[lang_index].file);
|
||||
lang_pack = ReadFileToMem(lang, &len, 100000);
|
||||
lang_pack = ReadFileToMem(lang, &len, 200000);
|
||||
free(lang);
|
||||
}
|
||||
if (lang_pack == NULL) return false;
|
||||
|
@ -1237,7 +1254,7 @@ void InitializeLanguagePacks(void)
|
|||
int fallback;
|
||||
LanguagePack hdr;
|
||||
FILE *in;
|
||||
char *files[32];
|
||||
char *files[MAX_LANG];
|
||||
const char* lang;
|
||||
|
||||
lang = GetCurrentLocale("LC_MESSAGES");
|
||||
|
|
|
@ -3,14 +3,7 @@
|
|||
#ifndef STRINGS_H
|
||||
#define STRINGS_H
|
||||
|
||||
static inline char* InlineString(char* buf, uint16 string)
|
||||
{
|
||||
*buf++ = '\x81';
|
||||
*buf++ = string & 0xFF;
|
||||
*buf++ = string >> 8;
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *InlineString(char *buf, uint16 string);
|
||||
char *GetString(char *buffr, uint16 string, const char* last);
|
||||
|
||||
extern char _userstring[128];
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/* $Id$ */
|
||||
|
||||
#ifndef CONTROL_CODES_H
|
||||
#define CONTROL_CODES_H
|
||||
|
||||
/* List of string control codes used for string formatting, displaying, and
|
||||
* by strgen to generate the language files. */
|
||||
|
||||
enum {
|
||||
SCC_CONTROL_START = 0xE000,
|
||||
SCC_CONTROL_END = 0xE1FF,
|
||||
|
||||
SCC_SPRITE_START = 0xE200,
|
||||
SCC_SPRITE_END = SCC_SPRITE_START + 0xFF,
|
||||
|
||||
/* Display control codes */
|
||||
SCC_SETX = SCC_CONTROL_START,
|
||||
SCC_SETXY,
|
||||
SCC_TINYFONT,
|
||||
SCC_BIGFONT,
|
||||
|
||||
/* Formatting control codes */
|
||||
SCC_REVISION,
|
||||
SCC_STATION_FEATURES,
|
||||
SCC_INDUSTRY_NAME,
|
||||
SCC_WAYPOINT_NAME,
|
||||
SCC_STATION_NAME,
|
||||
SCC_TOWN_NAME,
|
||||
|
||||
SCC_CURRENCY_COMPACT,
|
||||
SCC_CURRENCY_COMPACT_64,
|
||||
SCC_CURRENCY,
|
||||
SCC_CURRENCY_64,
|
||||
|
||||
SCC_CARGO,
|
||||
SCC_CARGO_SHORT,
|
||||
SCC_POWER,
|
||||
SCC_VOLUME,
|
||||
SCC_VOLUME_SHORT,
|
||||
SCC_WEIGHT,
|
||||
SCC_WEIGHT_SHORT,
|
||||
SCC_FORCE,
|
||||
SCC_VELOCITY,
|
||||
|
||||
SCC_DATE_TINY,
|
||||
SCC_DATE_SHORT,
|
||||
SCC_DATE_LONG,
|
||||
|
||||
SCC_STRING1,
|
||||
SCC_STRING2,
|
||||
SCC_STRING3,
|
||||
SCC_STRING4,
|
||||
SCC_STRING5,
|
||||
|
||||
SCC_SKIP,
|
||||
SCC_STRING,
|
||||
SCC_COMMA,
|
||||
SCC_NUM,
|
||||
|
||||
SCC_STRING_ID,
|
||||
SCC_PLURAL_LIST,
|
||||
SCC_GENDER_LIST,
|
||||
SCC_GENDER_INDEX,
|
||||
SCC_ARG_INDEX,
|
||||
SCC_SETCASE,
|
||||
SCC_SWITCH_CASE,
|
||||
|
||||
/* Colour codes */
|
||||
SCC_BLUE,
|
||||
SCC_SILVER,
|
||||
SCC_GOLD,
|
||||
SCC_RED,
|
||||
SCC_PURPLE,
|
||||
SCC_LTBROWN,
|
||||
SCC_ORANGE,
|
||||
SCC_GREEN,
|
||||
SCC_YELLOW,
|
||||
SCC_DKGREEN,
|
||||
SCC_CREAM,
|
||||
SCC_BROWN,
|
||||
SCC_WHITE,
|
||||
SCC_LTBLUE,
|
||||
SCC_GRAY,
|
||||
SCC_DKBLUE,
|
||||
SCC_BLACK,
|
||||
|
||||
/* Special printable symbols.
|
||||
* These are mapped to the original glyphs */
|
||||
SCC_LESSTHAN = SCC_SPRITE_START + 0x3C,
|
||||
SCC_GREATERTHAN = SCC_SPRITE_START + 0x3E,
|
||||
SCC_UPARROW = SCC_SPRITE_START + 0x80,
|
||||
SCC_SMALLUPARROW = SCC_SPRITE_START + 0x90,
|
||||
SCC_SMALLDOWNARROW = SCC_SPRITE_START + 0x91,
|
||||
SCC_TRAIN = SCC_SPRITE_START + 0x94,
|
||||
SCC_LORRY = SCC_SPRITE_START + 0x95,
|
||||
SCC_BUS = SCC_SPRITE_START + 0x96,
|
||||
SCC_PLANE = SCC_SPRITE_START + 0x97,
|
||||
SCC_SHIP = SCC_SPRITE_START + 0x98,
|
||||
SCC_DOWNARROW = SCC_SPRITE_START + 0xAA,
|
||||
SCC_CHECKMARK = SCC_SPRITE_START + 0xAC,
|
||||
SCC_CROSS = SCC_SPRITE_START + 0xAD,
|
||||
SCC_RIGHTARROW = SCC_SPRITE_START + 0xAF,
|
||||
};
|
||||
|
||||
#endif /* CONTROL_CODES_H */
|
688
table/namegen.h
688
table/namegen.h
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,21 @@
|
|||
/* $Id$ */
|
||||
|
||||
|
||||
typedef struct DefaultUnicodeMapping {
|
||||
WChar code; ///< Unicode value
|
||||
byte key; ///< Character index of sprite
|
||||
} DefaultUnicodeMapping;
|
||||
|
||||
|
||||
/* Default unicode mapping table for sprite based glyphs.
|
||||
* This table allows us use unicode characters even though the glyphs don't
|
||||
* exist, or are in the wrong place, in the standard sprite fonts.
|
||||
* This is not used for FreeType rendering */
|
||||
|
||||
static DefaultUnicodeMapping _default_unicode_map[] = {
|
||||
{ 0x010D, 0x63 }, /* Small letter c with caron */
|
||||
{ 0x0160, 0xA6 }, /* Capital letter s with caron */
|
||||
{ 0x0161, 0xA8 }, /* Small letter s with caron */
|
||||
{ 0x017E, 0xB8 }, /* Small letter z with caron */
|
||||
{ 0x20AC, 0xA4 }, /* Euro symbol */
|
||||
};
|
2
unix.c
2
unix.c
|
@ -291,7 +291,7 @@ void CSleep(int milliseconds)
|
|||
#include <errno.h>
|
||||
#include "debug.h"
|
||||
|
||||
#define INTERNALCODE "ISO-8859-15"
|
||||
#define INTERNALCODE "UTF-8"
|
||||
|
||||
/** Try and try to decipher the current locale from environmental
|
||||
* variables. MacOSX is hardcoded, other OS's are dynamic. If no suitable
|
||||
|
|
|
@ -323,12 +323,12 @@ VARDEF char _ini_videodriver[16], _ini_musicdriver[16], _ini_sounddriver[16];
|
|||
typedef struct {
|
||||
int num; // number of languages
|
||||
int curr; // currently selected language index
|
||||
char curr_file[32]; // currently selected language file
|
||||
StringID dropdown[32 + 1]; // used in settings dialog
|
||||
char curr_file[MAX_LANG]; // currently selected language file
|
||||
StringID dropdown[MAX_LANG + 1]; // used in settings dialog
|
||||
struct {
|
||||
char *name;
|
||||
char *file;
|
||||
} ent[32];
|
||||
} ent[MAX_LANG];
|
||||
} DynamicLanguages;
|
||||
|
||||
VARDEF DynamicLanguages _dynlang;
|
||||
|
|
|
@ -349,14 +349,15 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||
case WM_KEYDOWN: {
|
||||
// this is the rewritten ascii input function
|
||||
// it disables windows deadkey handling --> more linux like :D
|
||||
WORD w = 0;
|
||||
wchar_t w = 0;
|
||||
byte ks[256];
|
||||
uint scancode;
|
||||
uint32 pressed_key;
|
||||
|
||||
GetKeyboardState(ks);
|
||||
if (ToAscii(wParam, 0, ks, &w, 0) == 0) {
|
||||
w = 0; // no translation was possible
|
||||
if (ToUnicode(wParam, 0, ks, &w, 1, 0) == 0) {
|
||||
/* On win9x ToUnicode always fails, so fall back to ToAscii */
|
||||
if (ToAscii(wParam, 0, ks, &w, 0) == 0) w = 0; // no translation was possible
|
||||
}
|
||||
|
||||
pressed_key = w | MapWindowsKey(wParam) << 16;
|
||||
|
|
82
win32.c
82
win32.c
|
@ -926,39 +926,67 @@ void DeterminePaths(void)
|
|||
*/
|
||||
bool InsertTextBufferClipboard(Textbuf *tb)
|
||||
{
|
||||
if (IsClipboardFormatAvailable(CF_TEXT)) {
|
||||
HGLOBAL cbuf;
|
||||
const byte *data, *dataptr;
|
||||
uint16 width = 0;
|
||||
uint16 length = 0;
|
||||
HGLOBAL cbuf;
|
||||
char utf8_buf[512];
|
||||
const char *ptr;
|
||||
|
||||
WChar c;
|
||||
uint16 width, length;
|
||||
|
||||
if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
|
||||
int bytec;
|
||||
|
||||
OpenClipboard(NULL);
|
||||
cbuf = GetClipboardData(CF_TEXT);
|
||||
data = GlobalLock(cbuf); // clipboard data
|
||||
dataptr = data;
|
||||
|
||||
for (; IsValidAsciiChar(*dataptr, CS_ALPHANUMERAL) && (tb->length + length) < (tb->maxlength - 1) &&
|
||||
(tb->maxwidth == 0 || width + tb->width + GetCharacterWidth(FS_NORMAL, (byte)*dataptr) <= tb->maxwidth); dataptr++) {
|
||||
width += GetCharacterWidth(FS_NORMAL, (byte)*dataptr);
|
||||
length++;
|
||||
}
|
||||
|
||||
if (length == 0) return false;
|
||||
|
||||
memmove(tb->buf + tb->caretpos + length, tb->buf + tb->caretpos, tb->length - tb->caretpos);
|
||||
memcpy(tb->buf + tb->caretpos, data, length);
|
||||
tb->width += width;
|
||||
tb->caretxoffs += width;
|
||||
|
||||
tb->length += length;
|
||||
tb->caretpos += length;
|
||||
tb->buf[tb->length] = '\0'; // terminating zero
|
||||
cbuf = GetClipboardData(CF_UNICODETEXT);
|
||||
|
||||
ptr = GlobalLock(cbuf);
|
||||
bytec = WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)ptr, -1, utf8_buf, lengthof(utf8_buf), NULL, NULL);
|
||||
GlobalUnlock(cbuf);
|
||||
CloseClipboard();
|
||||
return true;
|
||||
|
||||
if (bytec == 0) {
|
||||
DEBUG(misc, 0) ("[utf8] Error converting '%s'. Errno %d", ptr, GetLastError());
|
||||
return false;
|
||||
}
|
||||
} else if (IsClipboardFormatAvailable(CF_TEXT)) {
|
||||
OpenClipboard(NULL);
|
||||
cbuf = GetClipboardData(CF_TEXT);
|
||||
|
||||
ptr = GlobalLock(cbuf);
|
||||
ttd_strlcpy(utf8_buf, ptr, lengthof(utf8_buf));
|
||||
GlobalUnlock(cbuf);
|
||||
CloseClipboard();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
width = length = 0;
|
||||
|
||||
for (ptr = utf8_buf; (c = Utf8Consume(&ptr)) != '\0';) {
|
||||
byte charwidth;
|
||||
|
||||
if (!IsPrintable(c)) break;
|
||||
if (tb->length + length >= tb->maxlength - 1) break;
|
||||
charwidth = GetCharacterWidth(FS_NORMAL, c);
|
||||
|
||||
if (tb->maxwidth != 0 && width + tb->width + charwidth > tb->maxwidth) break;
|
||||
|
||||
width += charwidth;
|
||||
length += Utf8CharLen(c);
|
||||
}
|
||||
|
||||
if (length == 0) return false;
|
||||
|
||||
memmove(tb->buf + tb->caretpos + length, tb->buf + tb->caretpos, tb->length - tb->caretpos);
|
||||
memcpy(tb->buf + tb->caretpos, utf8_buf, length);
|
||||
tb->width += width;
|
||||
tb->caretxoffs += width;
|
||||
|
||||
tb->length += length;
|
||||
tb->caretpos += length;
|
||||
tb->buf[tb->length] = '\0'; // terminating zero
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
2
window.c
2
window.c
|
@ -1422,7 +1422,7 @@ void HandleKeypress(uint32 key)
|
|||
|
||||
// Setup event
|
||||
e.event = WE_KEYPRESS;
|
||||
e.we.keypress.ascii = GB(key, 0, 8);
|
||||
e.we.keypress.key = GB(key, 0, 16);
|
||||
e.we.keypress.keycode = GB(key, 16, 16);
|
||||
e.we.keypress.cont = true;
|
||||
|
||||
|
|
Loading…
Reference in New Issue