From 06144864e13fb2fb9ed32c68e8a612a68103317c Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Wed, 24 Jun 2009 19:12:45 +0000 Subject: SCI: Partial support for dual-language games. svn-id: r41833 --- engines/sci/engine/kgraphics.cpp | 24 ++++++++------- engines/sci/engine/script.cpp | 3 ++ engines/sci/engine/state.cpp | 65 ++++++++++++++++++++++++++++++++++++++++ engines/sci/engine/state.h | 26 ++++++++++++++++ engines/sci/engine/vm.h | 6 +++- 5 files changed, 113 insertions(+), 11 deletions(-) (limited to 'engines/sci/engine') diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index a26c2dbcb1..2856c76aa3 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -621,10 +621,14 @@ reg_t kGraph(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t kTextSize(EngineState *s, int funct_nr, int argc, reg_t *argv) { int width, height; char *text = argv[1].segment ? (char *) kernel_dereference_bulk_pointer(s, argv[1], 0) : NULL; + const char *sep = NULL; reg_t *dest = kernel_dereference_reg_pointer(s, argv[0], 4); int maxwidth = (argc > 3) ? argv[3].toUint16() : 0; int font_nr = argv[2].toUint16(); + if ((argc > 4) && (argv[4].segment)) + sep = (const char *)kernel_dereference_bulk_pointer(s, argv[4], 0); + if (maxwidth < 0) maxwidth = 0; @@ -636,7 +640,7 @@ reg_t kTextSize(EngineState *s, int funct_nr, int argc, reg_t *argv) { return s->r_acc; } - GFX_ASSERT(gfxop_get_text_params(s->gfx_state, font_nr, text, maxwidth ? maxwidth : MAX_TEXT_WIDTH_MAGIC_VALUE, + GFX_ASSERT(gfxop_get_text_params(s->gfx_state, font_nr, s->strSplit(text, sep).c_str(), maxwidth ? maxwidth : MAX_TEXT_WIDTH_MAGIC_VALUE, &width, &height, 0, NULL, NULL, NULL)); debugC(2, kDebugLevelStrings, "GetTextSize '%s' -> %dx%d\n", text, width, height); @@ -1570,7 +1574,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { int font_nr = GET_SEL32V(obj, font); reg_t text_pos = GET_SEL32(obj, text); - char *text = text_pos.isNull() ? NULL : (char *)s->seg_manager->dereference(text_pos, NULL); + const char *text = text_pos.isNull() ? NULL : (char *)s->seg_manager->dereference(text_pos, NULL); int view = GET_SEL32V(obj, view); int cel = sign_extend_byte(GET_SEL32V(obj, cel)); int loop = sign_extend_byte(GET_SEL32V(obj, loop)); @@ -1584,7 +1588,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { switch (type) { case K_CONTROL_BUTTON: debugC(2, kDebugLevelGraphics, "drawing button %04x:%04x to %d,%d\n", PRINT_REG(obj), x, y); - ADD_TO_CURRENT_PICTURE_PORT(sciw_new_button_control(s->port, obj, area, text, font_nr, + ADD_TO_CURRENT_PICTURE_PORT(sciw_new_button_control(s->port, obj, area, s->strSplit(text, NULL).c_str(), font_nr, (int8)(state & kControlStateFramed), (int8)inverse, (int8)(state & kControlStateDisabled))); break; @@ -1593,7 +1597,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { debugC(2, kDebugLevelGraphics, "drawing text %04x:%04x to %d,%d, mode=%d\n", PRINT_REG(obj), x, y, mode); - ADD_TO_CURRENT_PICTURE_PORT(sciw_new_text_control(s->port, obj, area, text, font_nr, mode, + ADD_TO_CURRENT_PICTURE_PORT(sciw_new_text_control(s->port, obj, area, s->strSplit(text).c_str(), font_nr, mode, (int8)(!!(state & kControlStateDitherFramed)), (int8)inverse)); break; @@ -1620,8 +1624,8 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { case K_CONTROL_CONTROL: case K_CONTROL_CONTROL_ALIAS: { - char **entries_list = NULL; - char *seeker; + const char **entries_list = NULL; + const char *seeker; int entries_nr; int lsTop = GET_SEL32V(obj, lsTop) - text_pos.offset; int list_top = 0; @@ -1641,7 +1645,7 @@ static void _k_draw_control(EngineState *s, reg_t obj, int inverse) { if (entries_nr) { // determine list_top, selection, and the entries_list seeker = text; - entries_list = (char**)malloc(sizeof(char *) * entries_nr); + entries_list = (const char**)malloc(sizeof(char *) * entries_nr); for (i = 0; i < entries_nr; i++) { entries_list[i] = seeker; seeker += entry_size ; @@ -2524,10 +2528,10 @@ reg_t kNewWindow(EngineState *s, int funct_nr, int argc, reg_t *argv) { lWhite.alpha = 0; lWhite.priority = -1; lWhite.control = -1; + const char *title = argv[4 + argextra].segment ? kernel_dereference_char_pointer(s, argv[4 + argextra], 0) : NULL; window = sciw_new_window(s, gfx_rect(x, y, xl, yl), s->titlebar_port->_font, fgcolor, bgcolor, - s->titlebar_port->_font, lWhite, black, argv[4 + argextra].segment ? - kernel_dereference_char_pointer(s, argv[4 + argextra], 0) : NULL, flags); + s->titlebar_port->_font, lWhite, black, title ? s->strSplit(title, NULL).c_str() : NULL, flags); // PQ3 and SCI1.1 games have the interpreter store underBits implicitly if (argextra) @@ -3287,7 +3291,7 @@ reg_t kDisplay(EngineState *s, int funct_nr, int argc, reg_t *argv) { assert_primary_widget_lists(s); - text_handle = gfxw_new_text(s->gfx_state, area, font_nr, text, halign, ALIGN_TOP, color0, *color1, bg_color, 0); + text_handle = gfxw_new_text(s->gfx_state, area, font_nr, s->strSplit(text).c_str(), halign, ALIGN_TOP, color0, *color1, bg_color, 0); if (!text_handle) { error("Display: Failed to create text widget"); diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp index a0bfdeddc9..fb094e00f6 100644 --- a/engines/sci/engine/script.cpp +++ b/engines/sci/engine/script.cpp @@ -200,6 +200,9 @@ void Kernel::mapSelectors() { FIND_SELECTOR(points); FIND_SELECTOR(syncCue); FIND_SELECTOR(syncTime); + FIND_SELECTOR(printLang); + FIND_SELECTOR(subtitleLang); + FIND_SELECTOR(parseLang); } void Kernel::dumpScriptObject(char *data, int seeker, int objsize) { diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp index e35530700e..6bc9320050 100644 --- a/engines/sci/engine/state.cpp +++ b/engines/sci/engine/state.cpp @@ -126,4 +126,69 @@ uint16 EngineState::currentRoomNumber() const { return script_000->locals_block->_locals[13].toUint16(); } +kLanguage EngineState::charToLanguage(const char c) const { + switch (c) { + case 'F': + return K_LANG_FRENCH; + case 'S': + return K_LANG_SPANISH; + case 'I': + return K_LANG_ITALIAN; + case 'G': + return K_LANG_GERMAN; + case 'J': + case 'j': + return K_LANG_JAPANESE; + case 'P': + return K_LANG_PORTUGUESE; + default: + return K_LANG_NONE; + } +} + +Common::String EngineState::getLanguageString(const char *str, kLanguage lang) const { + kLanguage secondLang = K_LANG_NONE; + + const char *seeker = str; + while (*seeker) { + if ((*seeker == '%') || (*seeker == '#')) { + secondLang = charToLanguage(*(seeker + 1)); + + if (secondLang != K_LANG_NONE) + break; + } + + seeker++; + } + + if ((secondLang == K_LANG_JAPANESE) && (*(seeker + 1) == 'J')) { + // FIXME: Add Kanji support + lang = K_LANG_ENGLISH; + } + + if (secondLang == lang) + return Common::String(seeker + 2); + + if (seeker) + return Common::String(str, seeker - str); + else + return Common::String(str); +} + +Common::String EngineState::strSplit(const char *str, const char *sep) { + EngineState *s = this; + + kLanguage lang = (kLanguage)GET_SEL32V(s->game_obj, printLang); + kLanguage subLang = (kLanguage)GET_SEL32V(s->game_obj, subtitleLang); + + Common::String retval = getLanguageString(str, lang); + + if ((subLang != K_LANG_NONE) && (sep != NULL)) { + retval += sep; + retval += getLanguageString(str, subLang); + } + + return retval; +} + } // End of namespace Sci diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index 15c1c2e63e..ecfb9fe6f7 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -88,6 +88,18 @@ enum { SCI_GAME_WAS_RESTARTED_AT_LEAST_ONCE = 4 }; +/** Supported languages */ +enum kLanguage { + K_LANG_NONE = 0, + K_LANG_ENGLISH = 1, + K_LANG_FRENCH = 33, + K_LANG_SPANISH = 34, + K_LANG_ITALIAN = 39, + K_LANG_GERMAN = 49, + K_LANG_JAPANESE = 81, + K_LANG_PORTUGUESE = 351 +}; + struct drawn_pic_t { int nr; int palette; @@ -209,6 +221,16 @@ public: uint16 currentRoomNumber() const; + /** + * Processes a multilanguage string based on the current language settings and + * returns a string that is ready to be displayed. + * @param str the multilanguage string + * @param sep optional seperator between main language and subtitle language, + * if NULL is passed no subtitle will be added to the returned string + * @return processed string + */ + Common::String strSplit(const char *str, const char *sep = "\r----------\r"); + /* Debugger data: */ Breakpoint *bp_list; /**< List of breakpoints */ int have_bp; /**< Bit mask specifying which types of breakpoints are used in bp_list */ @@ -239,6 +261,10 @@ public: Kernel *_kernel; EngineState *successor; /**< Successor of this state: Used for restoring */ + +private: + kLanguage charToLanguage(const char c) const; + Common::String getLanguageString(const char *str, kLanguage lang) const; }; /** diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 379719a448..a3fabbe44b 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -198,7 +198,11 @@ struct selector_map_t { Selector points; /**< Used by AvoidPath() */ Selector syncCue; /**< Used by DoSync() */ - Selector syncTime; /**< Used by DoSync() */ + Selector syncTime; + + Selector printLang; /**< Used for i18n */ + Selector subtitleLang; + Selector parseLang; }; // A reference to an object's variable. -- cgit v1.2.3