aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorWalter van Niftrik2009-06-24 19:12:45 +0000
committerWalter van Niftrik2009-06-24 19:12:45 +0000
commit06144864e13fb2fb9ed32c68e8a612a68103317c (patch)
treec84961a1f0ebf5668ab2a45aa154893fdb7b219d /engines/sci
parent6c049f6b29591262a30864d0570f2a6128f1594d (diff)
downloadscummvm-rg350-06144864e13fb2fb9ed32c68e8a612a68103317c.tar.gz
scummvm-rg350-06144864e13fb2fb9ed32c68e8a612a68103317c.tar.bz2
scummvm-rg350-06144864e13fb2fb9ed32c68e8a612a68103317c.zip
SCI: Partial support for dual-language games.
svn-id: r41833
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/engine/kgraphics.cpp24
-rw-r--r--engines/sci/engine/script.cpp3
-rw-r--r--engines/sci/engine/state.cpp65
-rw-r--r--engines/sci/engine/state.h26
-rw-r--r--engines/sci/engine/vm.h6
-rw-r--r--engines/sci/gfx/gfx_gui.cpp10
-rw-r--r--engines/sci/gfx/gfx_gui.h10
7 files changed, 123 insertions, 21 deletions
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.
diff --git a/engines/sci/gfx/gfx_gui.cpp b/engines/sci/gfx/gfx_gui.cpp
index f73a13d6dd..fb05c0fe29 100644
--- a/engines/sci/gfx/gfx_gui.cpp
+++ b/engines/sci/gfx/gfx_gui.cpp
@@ -266,7 +266,7 @@ static rect_t _move_and_extend_rect(rect_t rect, Common::Point point, int yplus)
return gfx_rect(rect.x + point.x, rect.y + point.y, rect.width + 1, rect.height + yplus);
}
-GfxList *_sciw_add_text_to_list(GfxList *list, GfxPort *port, rect_t zone, char *text,
+GfxList *_sciw_add_text_to_list(GfxList *list, GfxPort *port, rect_t zone, const char *text,
int font, gfx_alignment_t align, char framed, char inverse, int flags, char gray_text) {
gfx_color_t *color1, *color2, *bgcolor;
@@ -294,7 +294,7 @@ GfxList *_sciw_add_text_to_list(GfxList *list, GfxPort *port, rect_t zone, char
return list;
}
-GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone, char *text, int font, char selected, char inverse, char grayed_out) {
+GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone, const char *text, int font, char selected, char inverse, char grayed_out) {
gfx_color_t *frame_col = (inverse) ? &(port->_bgcolor) : &(port->_color);
GfxList *list;
@@ -332,7 +332,7 @@ GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone, char *tex
return list;
}
-GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone, char *text, int font,
+GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone, const char *text, int font,
gfx_alignment_t align, char framed, char inverse) {
GfxList *list = gfxw_new_list(_move_and_extend_rect(zone, Common::Point(port->zone.x, port->zone.y), 2), 0);
@@ -344,7 +344,7 @@ GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone, char *text,
return _sciw_add_text_to_list(list, port, zone, text, font, align, framed, inverse, 0, port->gray_text);
}
-GfxList *sciw_new_edit_control(GfxPort *port, reg_t ID, rect_t zone, char *text, int font, unsigned int cursor,
+GfxList *sciw_new_edit_control(GfxPort *port, reg_t ID, rect_t zone, const char *text, int font, unsigned int cursor,
char inverse) {
GfxText *text_handle;
@@ -440,7 +440,7 @@ GfxList *sciw_new_icon_control(GfxPort *port, reg_t ID, rect_t zone, int view, i
return list;
}
-GfxList *sciw_new_list_control(GfxPort *port, reg_t ID, rect_t zone, int font_nr, char **entries_list,
+GfxList *sciw_new_list_control(GfxPort *port, reg_t ID, rect_t zone, int font_nr, const char **entries_list,
int entries_nr, int list_top, int selection, char inverse) {
GfxList *list;
diff --git a/engines/sci/gfx/gfx_gui.h b/engines/sci/gfx/gfx_gui.h
index a13c4c4fa4..68342aa0c0 100644
--- a/engines/sci/gfx/gfx_gui.h
+++ b/engines/sci/gfx/gfx_gui.h
@@ -113,7 +113,7 @@ GfxPort *sciw_new_window(EngineState *s, rect_t area, int font,
* @return The button
*/
GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone,
- char *text, int font, char selected, char inverse, char gray);
+ const char *text, int font, char selected, char inverse, char gray);
/**
* Creates a new text control list.
@@ -129,7 +129,7 @@ GfxList *sciw_new_button_control(GfxPort *port, reg_t ID, rect_t zone,
* @return The text control widget list
*/
GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone,
- char *text, int font, gfx_alignment_t align, char frame,
+ const char *text, int font, gfx_alignment_t align, char frame,
char inverse);
/**
@@ -145,7 +145,7 @@ GfxList *sciw_new_text_control(GfxPort *port, reg_t ID, rect_t zone,
* @return An appropriate widget list
*/
GfxList *sciw_new_edit_control(GfxPort *port, reg_t ID, rect_t zone,
- char *text, int font, unsigned int cursor, char inverse);
+ const char *text, int font, unsigned int cursor, char inverse);
/**
* Creates a new icon control list.
@@ -178,8 +178,8 @@ GfxList *sciw_new_icon_control(GfxPort *port, reg_t ID, rect_t zone,
* @return An appropriate widget list
*/
GfxList *sciw_new_list_control(GfxPort *port, reg_t ID, rect_t zone,
- int font_nr, char **entries_list, int entries_nr, int list_top,
- int selection, char inverse);
+ int font_nr, const char **entries_list, int entries_nr,
+ int list_top, int selection, char inverse);
/** @} */
/** @name Menubar widgets */