SCUMM: Support Lokalizator plugin.
This was used by Russian translation of Pajama Sam 2 and Spy Fox 3
This commit is contained in:
parent
cc375694be
commit
5c91fb8d6a
8 changed files with 202 additions and 9 deletions
122
engines/scumm/he/localizer.cpp
Normal file
122
engines/scumm/he/localizer.cpp
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/endian.h"
|
||||||
|
#include "scumm/he/localizer.h"
|
||||||
|
#include "common/file.h"
|
||||||
|
#include "common/debug.h"
|
||||||
|
|
||||||
|
namespace Scumm {
|
||||||
|
|
||||||
|
Localizer::Localizer() {
|
||||||
|
Common::File _file;
|
||||||
|
|
||||||
|
if (!_file.open("lokalizator.big"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint _fileSize = _file.size();
|
||||||
|
if (_fileSize < 0x18)
|
||||||
|
return;
|
||||||
|
byte *lkBig = new byte[_fileSize];
|
||||||
|
_file.read(lkBig, _fileSize);
|
||||||
|
// Obfuscation round 1
|
||||||
|
for (uint i = 0; i < _fileSize; i++)
|
||||||
|
lkBig[i] ^= (214013 * i + 2531011) >> 16;
|
||||||
|
|
||||||
|
uint32 numFiles = READ_LE_UINT32(lkBig + 0x14);
|
||||||
|
uint32 localeMsgOffset = 0, localeMsgSize = 0;
|
||||||
|
uint32 talkieDatOffset = 0, talkieDatSize = 0;
|
||||||
|
|
||||||
|
for (uint i = 0; i < numFiles; i++) {
|
||||||
|
byte *fileHdr = lkBig + 0x18 + 0x4c * i;
|
||||||
|
if (strcmp((char *) fileHdr, "locale.msg") == 0) {
|
||||||
|
localeMsgOffset = READ_LE_UINT32(fileHdr + 0x48);
|
||||||
|
localeMsgSize = READ_LE_UINT32(fileHdr + 0x44);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcmp((char *) fileHdr, "talkie.dat") == 0) {
|
||||||
|
talkieDatOffset = READ_LE_UINT32(fileHdr + 0x48);
|
||||||
|
talkieDatSize = READ_LE_UINT32(fileHdr + 0x44);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isValid = true;
|
||||||
|
|
||||||
|
if (localeMsgSize > 4) {
|
||||||
|
uint32 msgCount = READ_LE_UINT32(lkBig + localeMsgOffset);
|
||||||
|
// Obfuscation round 2
|
||||||
|
uint32 st = 0x12345678;
|
||||||
|
for (uint i = 0; i < localeMsgSize - 4; i++) {
|
||||||
|
byte x = 0;
|
||||||
|
switch (i & 3) {
|
||||||
|
case 0:
|
||||||
|
x = st;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
x = st + 35;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
x = st + 70;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
x = st + 105;
|
||||||
|
st += 45707404;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lkBig[i + localeMsgOffset + 4] ^= x;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 cur = localeMsgOffset + 4;
|
||||||
|
|
||||||
|
for (uint i = 0; i < msgCount && cur < localeMsgOffset + localeMsgSize; i++) {
|
||||||
|
cur += 4; // Domain id or something like this, always zero
|
||||||
|
uint32 lenOrig = READ_LE_UINT32(lkBig + cur); cur += 4;
|
||||||
|
Common::String orig((char *) lkBig + cur, (char *) lkBig + cur + lenOrig);
|
||||||
|
cur += lenOrig;
|
||||||
|
uint32 lenTrans = READ_LE_UINT32(lkBig + cur); cur += 4;
|
||||||
|
Common::String trans((char *) lkBig + cur, (char *) lkBig + cur + lenTrans);
|
||||||
|
cur += lenTrans;
|
||||||
|
_translationMap[orig] = trans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 cur = talkieDatOffset; cur < talkieDatOffset + talkieDatSize; cur += 16) {
|
||||||
|
_talkMap[READ_LE_UINT32(lkBig+cur+4)] = READ_LE_UINT32(lkBig+cur+12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String Localizer::translate(const Common::String &orig) {
|
||||||
|
if (_translationMap.contains(orig)) {
|
||||||
|
return _translationMap[orig];
|
||||||
|
}
|
||||||
|
return orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Localizer::mapTalk(uint32 orig) {
|
||||||
|
if (_talkMap.contains(orig)) {
|
||||||
|
return _talkMap[orig];
|
||||||
|
}
|
||||||
|
return orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
engines/scumm/he/localizer.h
Normal file
48
engines/scumm/he/localizer.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SCUMM_LOCALIZER_H
|
||||||
|
#define SCUMM_LOCALIZER_H
|
||||||
|
|
||||||
|
#include "common/str.h"
|
||||||
|
#include "common/hashmap.h"
|
||||||
|
#include "common/hash-str.h"
|
||||||
|
|
||||||
|
namespace Scumm {
|
||||||
|
|
||||||
|
class Localizer {
|
||||||
|
public:
|
||||||
|
Localizer();
|
||||||
|
Common::String translate(const Common::String &original);
|
||||||
|
uint32 mapTalk(uint32 orig);
|
||||||
|
bool isValid() {
|
||||||
|
return _isValid;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
Common::HashMap<Common::String, Common::String> _translationMap;
|
||||||
|
Common::HashMap<uint32, uint32> _talkMap;
|
||||||
|
bool _isValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -31,6 +31,7 @@
|
||||||
#include "scumm/dialogs.h"
|
#include "scumm/dialogs.h"
|
||||||
#include "scumm/file.h"
|
#include "scumm/file.h"
|
||||||
#include "scumm/he/intern_he.h"
|
#include "scumm/he/intern_he.h"
|
||||||
|
#include "scumm/he/localizer.h"
|
||||||
#include "scumm/object.h"
|
#include "scumm/object.h"
|
||||||
#include "scumm/resource.h"
|
#include "scumm/resource.h"
|
||||||
#include "scumm/scumm.h"
|
#include "scumm/scumm.h"
|
||||||
|
@ -317,6 +318,7 @@ void ScummEngine_v72he::decodeScriptString(byte *dst, bool scriptString) {
|
||||||
int args[31];
|
int args[31];
|
||||||
int num, len, val;
|
int num, len, val;
|
||||||
byte chr, string[1024];
|
byte chr, string[1024];
|
||||||
|
byte *dst0 = dst;
|
||||||
memset(args, 0, sizeof(args));
|
memset(args, 0, sizeof(args));
|
||||||
memset(string, 0, sizeof(string));
|
memset(string, 0, sizeof(string));
|
||||||
|
|
||||||
|
@ -335,6 +337,10 @@ void ScummEngine_v72he::decodeScriptString(byte *dst, bool scriptString) {
|
||||||
len = resStrLen(string) + 1;
|
len = resStrLen(string) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_localizer) {
|
||||||
|
strncpy((char *) string, _localizer->translate((char *) string).c_str(), sizeof(string) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
// Decode string
|
// Decode string
|
||||||
num = 0;
|
num = 0;
|
||||||
val = 0;
|
val = 0;
|
||||||
|
@ -372,6 +378,10 @@ void ScummEngine_v72he::decodeScriptString(byte *dst, bool scriptString) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*dst = 0;
|
*dst = 0;
|
||||||
|
|
||||||
|
if (_localizer) {
|
||||||
|
strncpy((char *) dst0, _localizer->translate((char *) dst0).c_str(), sizeof(string) - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ScummEngine_v72he::findObject(int x, int y, int num, int *args) {
|
int ScummEngine_v72he::findObject(int x, int y, int num, int *args) {
|
||||||
|
|
|
@ -333,13 +333,6 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co
|
||||||
return Common::kUnsupportedGameidError;
|
return Common::kUnsupportedGameidError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't support yet the
|
|
||||||
// the full game.
|
|
||||||
if (!strcmp(res.game.gameid, "pajama2") && !strcmp(res.extra, "Russobit")) {
|
|
||||||
GUIErrorMessage(_("The Russian version of Pajama Sam 2 is not supported yet due to incomplete code."));
|
|
||||||
return Common::kUnsupportedGameidError;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the GUI options were updated, we catch this here and update them in the users config
|
// If the GUI options were updated, we catch this here and update them in the users config
|
||||||
// file transparently.
|
// file transparently.
|
||||||
Common::updateGameGUIOptions(res.game.guioptions, getGameGUIOptionsDescriptionLanguage(res.language));
|
Common::updateGameGUIOptions(res.game.guioptions, getGameGUIOptionsDescriptionLanguage(res.language));
|
||||||
|
|
|
@ -137,6 +137,7 @@ MODULE_OBJS += \
|
||||||
he/script_v100he.o \
|
he/script_v100he.o \
|
||||||
he/sprite_he.o \
|
he/sprite_he.o \
|
||||||
he/wiz_he.o \
|
he/wiz_he.o \
|
||||||
|
he/localizer.o \
|
||||||
he/logic/baseball2001.o \
|
he/logic/baseball2001.o \
|
||||||
he/logic/basketball.o \
|
he/logic/basketball.o \
|
||||||
he/logic/football.o \
|
he/logic/football.o \
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
#include "scumm/scumm_v8.h"
|
#include "scumm/scumm_v8.h"
|
||||||
#include "scumm/sound.h"
|
#include "scumm/sound.h"
|
||||||
#include "scumm/imuse/sysex.h"
|
#include "scumm/imuse/sysex.h"
|
||||||
|
#include "scumm/he/localizer.h"
|
||||||
#include "scumm/he/sprite_he.h"
|
#include "scumm/he/sprite_he.h"
|
||||||
#include "scumm/he/cup_player_he.h"
|
#include "scumm/he/cup_player_he.h"
|
||||||
#include "scumm/util.h"
|
#include "scumm/util.h"
|
||||||
|
@ -124,6 +125,8 @@ ScummEngine::ScummEngine(OSystem *syst, const DetectorResult &dr)
|
||||||
_rnd("scumm")
|
_rnd("scumm")
|
||||||
{
|
{
|
||||||
|
|
||||||
|
_localizer = nullptr;
|
||||||
|
|
||||||
#ifdef USE_RGB_COLOR
|
#ifdef USE_RGB_COLOR
|
||||||
if (_game.features & GF_16BIT_COLOR) {
|
if (_game.features & GF_16BIT_COLOR) {
|
||||||
if (_game.platform == Common::kPlatformPCEngine)
|
if (_game.platform == Common::kPlatformPCEngine)
|
||||||
|
@ -1337,6 +1340,14 @@ Common::Error ScummEngine::init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_HE
|
||||||
|
Localizer *loc = new Localizer();
|
||||||
|
if (!loc->isValid())
|
||||||
|
delete loc;
|
||||||
|
else
|
||||||
|
_localizer = loc;
|
||||||
|
#endif
|
||||||
|
|
||||||
_outputPixelFormat = _system->getScreenFormat();
|
_outputPixelFormat = _system->getScreenFormat();
|
||||||
|
|
||||||
setupScumm();
|
setupScumm();
|
||||||
|
|
|
@ -90,6 +90,7 @@ class Player_Towns;
|
||||||
class ScummEngine;
|
class ScummEngine;
|
||||||
class ScummDebugger;
|
class ScummDebugger;
|
||||||
class Sound;
|
class Sound;
|
||||||
|
class Localizer;
|
||||||
|
|
||||||
struct Box;
|
struct Box;
|
||||||
struct BoxCoords;
|
struct BoxCoords;
|
||||||
|
@ -1108,6 +1109,8 @@ protected:
|
||||||
|
|
||||||
int _nextLeft, _nextTop;
|
int _nextLeft, _nextTop;
|
||||||
|
|
||||||
|
Localizer *_localizer;
|
||||||
|
|
||||||
void restoreCharsetBg();
|
void restoreCharsetBg();
|
||||||
void clearCharsetMask();
|
void clearCharsetMask();
|
||||||
void clearTextSurface();
|
void clearTextSurface();
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "scumm/imuse_digi/dimuse.h"
|
#include "scumm/imuse_digi/dimuse.h"
|
||||||
#ifdef ENABLE_HE
|
#ifdef ENABLE_HE
|
||||||
#include "scumm/he/intern_he.h"
|
#include "scumm/he/intern_he.h"
|
||||||
|
#include "scumm/he/localizer.h"
|
||||||
#endif
|
#endif
|
||||||
#include "scumm/resource.h"
|
#include "scumm/resource.h"
|
||||||
#include "scumm/scumm.h"
|
#include "scumm/scumm.h"
|
||||||
|
@ -336,7 +337,11 @@ bool ScummEngine::handleNextCharsetCode(Actor *a, int *code) {
|
||||||
talk_sound_b = buffer[8] | (buffer[9] << 8) | (buffer[12] << 16) | (buffer[13] << 24);
|
talk_sound_b = buffer[8] | (buffer[9] << 8) | (buffer[12] << 16) | (buffer[13] << 24);
|
||||||
buffer += 14;
|
buffer += 14;
|
||||||
if (_game.heversion >= 60) {
|
if (_game.heversion >= 60) {
|
||||||
|
#ifdef ENABLE_HE
|
||||||
|
((SoundHE *)_sound)->startHETalkSound(_localizer ? _localizer->mapTalk(talk_sound_a) : talk_sound_a);
|
||||||
|
#else
|
||||||
((SoundHE *)_sound)->startHETalkSound(talk_sound_a);
|
((SoundHE *)_sound)->startHETalkSound(talk_sound_a);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
_sound->talkSound(talk_sound_a, talk_sound_b, 2);
|
_sound->talkSound(talk_sound_a, talk_sound_b, 2);
|
||||||
}
|
}
|
||||||
|
@ -406,7 +411,7 @@ bool ScummEngine_v72he::handleNextCharsetCode(Actor *a, int *code) {
|
||||||
}
|
}
|
||||||
value[i] = 0;
|
value[i] = 0;
|
||||||
//talk_sound_b = atoi(value);
|
//talk_sound_b = atoi(value);
|
||||||
((SoundHE *)_sound)->startHETalkSound(talk_sound_a);
|
((SoundHE *)_sound)->startHETalkSound(_localizer ? _localizer->mapTalk(talk_sound_a) : talk_sound_a);
|
||||||
break;
|
break;
|
||||||
case 104:
|
case 104:
|
||||||
_haveMsg = 0;
|
_haveMsg = 0;
|
||||||
|
@ -429,7 +434,7 @@ bool ScummEngine_v72he::handleNextCharsetCode(Actor *a, int *code) {
|
||||||
value[i] = 0;
|
value[i] = 0;
|
||||||
talk_sound_a = atoi(value);
|
talk_sound_a = atoi(value);
|
||||||
//talk_sound_b = 0;
|
//talk_sound_b = 0;
|
||||||
((SoundHE *)_sound)->startHETalkSound(talk_sound_a);
|
((SoundHE *)_sound)->startHETalkSound(_localizer ? _localizer->mapTalk(talk_sound_a) : talk_sound_a);
|
||||||
break;
|
break;
|
||||||
case 119:
|
case 119:
|
||||||
_haveMsg = 0xFF;
|
_haveMsg = 0xFF;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue