aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
authorJohannes Schickel2008-04-19 22:22:00 +0000
committerJohannes Schickel2008-04-19 22:22:00 +0000
commit03caed6ce3303150d75185ca94334759901fe344 (patch)
tree7aaf11c318a273591df2b04d17dd5328cbe8f340 /engines/kyra
parent4f4eb8d77165c0fecfe5d9bd8f4773cd60e44ac7 (diff)
downloadscummvm-rg350-03caed6ce3303150d75185ca94334759901fe344.tar.gz
scummvm-rg350-03caed6ce3303150d75185ca94334759901fe344.tar.bz2
scummvm-rg350-03caed6ce3303150d75185ca94334759901fe344.zip
Implemented some kyra opcodes and some chat handling code, now Malcolm should say something after crawling out of the dump.
svn-id: r31581
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/animator_v3.cpp32
-rw-r--r--engines/kyra/kyra_v3.cpp79
-rw-r--r--engines/kyra/kyra_v3.h81
-rw-r--r--engines/kyra/resource.cpp2
-rw-r--r--engines/kyra/script_v3.cpp98
-rw-r--r--engines/kyra/text.h2
-rw-r--r--engines/kyra/text_v2.cpp2
-rw-r--r--engines/kyra/text_v3.cpp333
-rw-r--r--engines/kyra/text_v3.h8
9 files changed, 626 insertions, 11 deletions
diff --git a/engines/kyra/animator_v3.cpp b/engines/kyra/animator_v3.cpp
index f9137d4c7e..8a88f24b3c 100644
--- a/engines/kyra/animator_v3.cpp
+++ b/engines/kyra/animator_v3.cpp
@@ -289,6 +289,12 @@ void KyraEngine_v3::refreshAnimObjectsIfNeed() {
}
}
+void KyraEngine_v3::flagAnimObjsForRefresh() {
+ debugC(9, kDebugLevelAnimator, "KyraEngine_v3::flagAnimObjsForRefresh()");
+ for (AnimObj *curEntry = _animList; curEntry; curEntry = curEntry->nextObject)
+ curEntry->needRefresh = true;
+}
+
void KyraEngine_v3::updateCharacterAnim(int charId) {
debugC(9, kDebugLevelAnimator, "KyraEngine_v3::updateCharacterAnim(%d)", charId);
@@ -388,4 +394,30 @@ void KyraEngine_v3::removeSceneAnimObject(int anim, int refresh) {
_sceneAnimMovie[anim]->close();
}
+void KyraEngine_v3::setCharacterAnimDim(int w, int h) {
+ debugC(9, kDebugLevelAnimator, "KyraEngine_v3::setCharacterAnimDim(%d, %d)", w, h);
+ restorePage3();
+ _charBackUpWidth = _animObjects[0].width;
+ _charBackUpWidth2 = _animObjects[0].width2;
+ _charBackUpHeight = _animObjects[0].height;
+ _charBackUpHeight2 = _animObjects[0].height2;
+
+ _animObjects[0].width2 = (w - _charBackUpWidth) / 2;
+ _animObjects[0].height2 = h - _charBackUpHeight;
+ _animObjects[0].width = w;
+ _animObjects[0].height = h;
+}
+
+void KyraEngine_v3::resetCharacterAnimDim() {
+ debugC(9, kDebugLevelAnimator, "KyraEngine_v3::resetCharacterAnimDim()");
+ restorePage3();
+ _animObjects[0].width2 = _charBackUpWidth2;
+ _animObjects[0].height2 = _charBackUpHeight2;
+ _animObjects[0].width = _charBackUpWidth;
+ _animObjects[0].height = _charBackUpHeight;
+ _charBackUpWidth2 = _charBackUpHeight2 = -1;
+ _charBackUpWidth = _charBackUpHeight = -1;
+}
+
} // end of namespace Kyra
+
diff --git a/engines/kyra/kyra_v3.cpp b/engines/kyra/kyra_v3.cpp
index ebf958d556..b61f82f9dc 100644
--- a/engines/kyra/kyra_v3.cpp
+++ b/engines/kyra/kyra_v3.cpp
@@ -61,7 +61,7 @@ KyraEngine_v3::KyraEngine_v3(OSystem *system, const GameFlags &flags) : KyraEngi
_sceneList = 0;
memset(&_mainCharacter, 0, sizeof(_mainCharacter));
_mainCharacter.sceneId = 9;
- _mainCharacter.unk4 = 0x4C;
+ _mainCharacter.height = 0x4C;
_mainCharacter.facing = 5;
_mainCharacter.animFrame = 0x57;
_mainCharacter.walkspeed = 5;
@@ -96,6 +96,16 @@ KyraEngine_v3::KyraEngine_v3(OSystem *system, const GameFlags &flags) : KyraEngi
_lastProcessedSceneScript = 0;
_specialSceneScriptRunFlag = false;
_pathfinderFlag = 0;
+ _talkObjectList = 0;
+ _chatText = 0;
+ _chatObject = -1;
+ memset(&_chatScriptState, 0, sizeof(_chatScriptState));
+ memset(&_chatScriptData, 0, sizeof(_chatScriptData));
+ _voiceSoundChannel = -1;
+ _charBackUpWidth2 = _charBackUpHeight2 = -1;
+ _charBackUpWidth = _charBackUpHeight = -1;
+ _useActorBuffer = false;
+ _curStudioSFX = 283;
}
KyraEngine_v3::~KyraEngine_v3() {
@@ -138,6 +148,7 @@ KyraEngine_v3::~KyraEngine_v3() {
delete _wsaSlots[i];
delete [] _sceneStrings;
+ delete [] _talkObjectList;
}
int KyraEngine_v3::init() {
@@ -401,6 +412,42 @@ void KyraEngine_v3::playSoundEffect(int item, int volume) {
}
}
+void KyraEngine_v3::playVoice(int high, int low) {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::playVoice(%d, %d)", high, low);
+ snd_playVoiceFile(high * 1000 + low);
+}
+
+void KyraEngine_v3::snd_playVoiceFile(int file) {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::snd_playVoiceFile(%d)", file);
+ char filename[16];
+ snprintf(filename, 16, "%u.AUD", (uint)file);
+
+ Common::SeekableReadStream *stream = _res->getFileStream(filename);
+ if (stream)
+ _voiceSoundChannel = _soundDigital->playSound(stream, SoundDigital::kSoundTypeSpeech, 255);
+}
+
+bool KyraEngine_v3::snd_voiceIsPlaying() {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::snd_voiceIsPlaying()");
+ return _soundDigital->isPlaying(_voiceSoundChannel);
+}
+
+void KyraEngine_v3::snd_stopVoice() {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::snd_stopVoice()");
+ _soundDigital->stopSound(_voiceSoundChannel);
+}
+
+void KyraEngine_v3::playStudioSFX() {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::playStudioSFX()");
+ if (_rnd.getRandomNumberRng(1, 2) != 2)
+ return;
+
+ playSoundEffect(_curStudioSFX++, 128);
+
+ if (_curStudioSFX > 291)
+ _curStudioSFX = 283;
+}
+
#pragma mark -
void KyraEngine_v3::preinit() {
@@ -491,7 +538,10 @@ void KyraEngine_v3::startup() {
_screen->_curPage = 0;
- //XXX
+ _talkObjectList = new TalkObject[88];
+ memset(_talkObjectList, 0, sizeof(TalkObject)*88);
+ for (int i = 0; i < 88; ++i)
+ _talkObjectList[i].unk14 = -1;
musicUpdate(0);
updateMalcolmShapes();
@@ -941,6 +991,31 @@ void KyraEngine_v3::update() {
_screen->updateScreen();
}
+void KyraEngine_v3::updateWithText() {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::update()");
+ updateInput();
+
+ musicUpdate(0);
+ updateMouse();
+ //XXX
+ updateSpecialSceneScripts();
+ updateCommandLine();
+ //XXX
+ musicUpdate(0);
+
+ restorePage3();
+ drawAnimObjects();
+ if (textEnabled() && _chatText) {
+ int curPage = _screen->_curPage;
+ _screen->_curPage = 2;
+ objectChatPrintText(_chatText, _chatObject);
+ _screen->_curPage = curPage;
+ }
+ refreshAnimObjects(0);
+
+ _screen->updateScreen();
+}
+
void KyraEngine_v3::updateMouse() {
debugC(9, kDebugLevelMain, "KyraEngine_v3::updateMouse()");
int shape = 0, offsetX = 0, offsetY = 0;
diff --git a/engines/kyra/kyra_v3.h b/engines/kyra/kyra_v3.h
index 3641aeb838..739da1ee9c 100644
--- a/engines/kyra/kyra_v3.h
+++ b/engines/kyra/kyra_v3.h
@@ -43,12 +43,14 @@ class TextDisplayer_v3;
struct Button;
class KyraEngine_v3 : public KyraEngine {
+friend class TextDisplayer_v3;
public:
KyraEngine_v3(OSystem *system, const GameFlags &flags);
~KyraEngine_v3();
Screen *screen() { return _screen; }
SoundDigital *soundDigital() { return _soundDigital; }
+ int language() const { return _lang; }
int go();
@@ -74,6 +76,7 @@ private:
void handleInput(int x, int y);
void update();
+ void updateWithText();
void updateMouse();
void delay(uint32 millis, bool update = false, bool isMainLoop = false);
@@ -127,7 +130,15 @@ private:
static const char *_sfxFileList[];
static const int _sfxFileListSize;
- void snd_playVoiceFile(int) {}
+ int _voiceSoundChannel;
+
+ void playVoice(int high, int low);
+ void snd_playVoiceFile(int file);
+ bool snd_voiceIsPlaying();
+ void snd_stopVoice();
+
+ int _curStudioSFX;
+ void playStudioSFX();
// main menu
void initMainMenu();
@@ -199,12 +210,20 @@ private:
void refreshAnimObjects(int force);
void refreshAnimObjectsIfNeed();
+ void flagAnimObjsForRefresh();
+
bool _loadingState;
void updateCharacterAnim(int charId);
void updateSceneAnim(int anim, int newFrame);
void removeSceneAnimObject(int anim, int refresh);
+ int _charBackUpWidth2, _charBackUpHeight2;
+ int _charBackUpWidth, _charBackUpHeight;
+
+ void setCharacterAnimDim(int w, int h);
+ void resetCharacterAnimDim();
+
// interface
uint8 *_interface;
uint8 *_interfaceCommandLine;
@@ -373,7 +392,7 @@ private:
struct Character {
uint16 sceneId;
uint16 dlgIndex;
- uint8 unk4;
+ uint8 height;
uint8 facing;
uint16 animFrame;
//uint8 unk8, unk9;
@@ -407,12 +426,66 @@ private:
int _lastCharPalLayer;
bool _charPalUpdate;
+
+ // talk object
+ struct TalkObject {
+ char filename[13];
+ int8 unkD;
+ int8 unkE;
+ int16 x, y;
+ uint8 color;
+ int8 unk14;
+ };
+
+ TalkObject *_talkObjectList;
+
+ // chat
+ int _vocHigh;
+
+ const char *_chatText;
+ int _chatObject;
+ uint32 _chatEndTime;
+ int _chatVocHigh, _chatVocLow;
+
+ ScriptData _chatScriptData;
+ ScriptState _chatScriptState;
+
+ int chatGetType(const char *text);
+ int chatCalcDuration(const char *text);
+
+ void objectChat(const char *text, int object, int vocHigh, int vocLow);
+ void objectChatInit(const char *text, int object, int vocHigh, int vocLow);
+ void objectChatPrintText(const char *text, int object);
+ void objectChatProcess(const char *script);
+ void objectChatWaitToFinish();
+
+ // special script code
+ bool _temporaryScriptExecBit;
+ bool _useFrameTable;
+
+ Common::Array<const Opcode *> _opcodesTemporary;
+
+ int o3t_defineNewShapes(ScriptState *script);
+ int o3t_setCurrentFrame(ScriptState *script);
+ int o3t_playSoundEffect(ScriptState *script);
+ int o3t_getMalcolmShapes(ScriptState *script);
+
+ // special shape code
+ char _newShapeFilename[13];
+ int _newShapeLastEntry;
+ int _newShapeWidth, _newShapeHeight;
+ int _newShapeXAdd, _newShapeYAdd;
+
+ int _newShapeAnimFrame;
+ int _newShapeDelay;
+
// unk
uint8 *_unkBuffer1040Bytes;
uint8 *_costPalBuffer;
uint8 *_screenBuffer;
uint8 *_gfxBackUpRect;
uint8 *_paletteOverlay;
+ bool _useActorBuffer;
int _unk3, _unk4, _unk5;
@@ -422,8 +495,10 @@ private:
// opcodes
int o3_setCharacterPos(ScriptState *script);
+ int o3_defineObject(ScriptState *script);
int o3_refreshCharacter(ScriptState *script);
int o3_showSceneFileMessage(ScriptState *script);
+ int o3_objectChat(ScriptState *script);
int o3_defineItem(ScriptState *script);
int o3_queryGameFlag(ScriptState *script);
int o3_resetGameFlag(ScriptState *script);
@@ -446,6 +521,8 @@ private:
int o3_setHiddenItemsEntry(ScriptState *script);
int o3_getHiddenItemsEntry(ScriptState *script);
int o3_removeSceneAnimObject(ScriptState *script);
+ int o3_setVocHigh(ScriptState *script);
+ int o3_getVocHigh(ScriptState *script);
int o3_dummy(ScriptState *script);
// misc
diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp
index 9d15100b65..8d09e2fa59 100644
--- a/engines/kyra/resource.cpp
+++ b/engines/kyra/resource.cpp
@@ -714,7 +714,7 @@ bool ResLoaderTlk::loadFile(const Common::String &filename, Common::SeekableRead
entry.offset = resOffset+4;
char realFilename[20];
- snprintf(realFilename, 20, "%.08u.AUD", resFilename);
+ snprintf(realFilename, 20, "%u.AUD", resFilename);
uint32 curOffset = stream.pos();
stream.seek(entry.offset+2, SEEK_SET);
diff --git a/engines/kyra/script_v3.cpp b/engines/kyra/script_v3.cpp
index 789d2bf06e..b7f0e80acc 100644
--- a/engines/kyra/script_v3.cpp
+++ b/engines/kyra/script_v3.cpp
@@ -48,6 +48,20 @@ int KyraEngine_v3::o3_setCharacterPos(ScriptState *script) {
return 0;
}
+int KyraEngine_v3::o3_defineObject(ScriptState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3_defineObject(%p) (%d, '%s', %d, %d, %d, %d, %d, %d)", (const void *)script,
+ stackPos(0), stackPosString(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ TalkObject &obj = _talkObjectList[stackPos(0)];
+ strcpy(obj.filename, stackPosString(1));
+ obj.unkD = stackPos(2);
+ obj.unkE = stackPos(3);
+ obj.x = stackPos(4);
+ obj.y = stackPos(5);
+ obj.color = stackPos(6);
+ obj.unk14 = stackPos(7);
+ return 0;
+}
+
int KyraEngine_v3::o3_refreshCharacter(ScriptState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3_refreshCharacter(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
const int frame = stackPos(0);
@@ -75,6 +89,17 @@ int KyraEngine_v3::o3_showSceneFileMessage(ScriptState *script) {
return 0;
}
+int KyraEngine_v3::o3_objectChat(ScriptState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3_objectChat(%p) (%d)", (const void *)script, stackPos(0));
+ int id = stackPos(0);
+ const char *str = (const char*)getTableEntry(_useActorBuffer ? _actorFile : _sceneStrings, id);
+ if (str) {
+ objectChat(str, 0, _vocHigh, id);
+ playStudioSFX();
+ }
+ return 0;
+}
+
int KyraEngine_v3::o3_defineItem(ScriptState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3_defineItem(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
int freeItem = findFreeItem();
@@ -312,11 +337,62 @@ int KyraEngine_v3::o3_removeSceneAnimObject(ScriptState *script) {
return 0;
}
+int KyraEngine_v3::o3_setVocHigh(ScriptState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3_setVocHigh(%p) (%d)", (const void *)script, stackPos(0));
+ _vocHigh = stackPos(0);
+ return 0;
+}
+
+int KyraEngine_v3::o3_getVocHigh(ScriptState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3_getVocHigh(%p) ()", (const void *)script);
+ return _vocHigh;
+}
+
int KyraEngine_v3::o3_dummy(ScriptState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3_dummy(%p) ()", (const void *)script);
return 0;
}
+#pragma mark -
+
+int KyraEngine_v3::o3t_defineNewShapes(ScriptState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3t_defineNewShapes(%p) ('%s', %d, %d, %d, %d, %d)", (const void *)script,
+ stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ strcpy(_newShapeFilename, stackPosString(0));
+ _newShapeLastEntry = stackPos(1);
+ _newShapeWidth = stackPos(2);
+ _newShapeHeight = stackPos(3);
+ _newShapeXAdd = stackPos(4);
+ _newShapeYAdd = stackPos(5);
+ return 0;
+}
+
+int KyraEngine_v3::o3t_setCurrentFrame(ScriptState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3t_setCurrentFrame(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
+ static const uint8 frameTable[] = {
+ 0x58, 0xD8, 0xD8, 0x98, 0x78, 0x78, 0xB8, 0xB8
+ };
+
+ _newShapeAnimFrame = stackPos(0);
+ if (_useFrameTable)
+ _newShapeAnimFrame += frameTable[_mainCharacter.facing];
+
+ _newShapeDelay = stackPos(1);
+ _temporaryScriptExecBit = true;
+ return 0;
+}
+
+int KyraEngine_v3::o3t_playSoundEffect(ScriptState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3t_playSoundEffect(%p) (%d)", (const void *)script, stackPos(0));
+ playSoundEffect(stackPos(0), 200);
+ return 0;
+}
+
+int KyraEngine_v3::o3t_getMalcolmShapes(ScriptState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v3::o3t_getMalcolmShapes(%p) ()", (const void *)script);
+ return _malcolmShapes;
+}
+
typedef Functor1Mem<ScriptState*, int, KyraEngine_v3> OpcodeV3;
#define Opcode(x) OpcodeV3(this, &KyraEngine_v3::x)
#define OpcodeUnImpl() OpcodeV3(this, 0)
@@ -325,7 +401,7 @@ void KyraEngine_v3::setupOpcodeTable() {
// 0x00
OpcodeUnImpl(),
Opcode(o3_setCharacterPos),
- OpcodeUnImpl(),
+ Opcode(o3_defineObject),
Opcode(o3_refreshCharacter),
// 0x04
OpcodeUnImpl(),
@@ -361,7 +437,7 @@ void KyraEngine_v3::setupOpcodeTable() {
OpcodeUnImpl(),
OpcodeUnImpl(),
OpcodeUnImpl(),
- OpcodeUnImpl(),
+ Opcode(o3_objectChat),
// 0x20
OpcodeUnImpl(),
Opcode(o3_dummy),
@@ -531,9 +607,9 @@ void KyraEngine_v3::setupOpcodeTable() {
OpcodeUnImpl(),
OpcodeUnImpl(),
OpcodeUnImpl(),
- OpcodeUnImpl(),
+ Opcode(o3_setVocHigh),
// 0xa8
- OpcodeUnImpl(),
+ Opcode(o3_getVocHigh),
OpcodeUnImpl(),
OpcodeUnImpl(),
OpcodeUnImpl(),
@@ -546,6 +622,20 @@ void KyraEngine_v3::setupOpcodeTable() {
for (int i = 0; i < ARRAYSIZE(opcodeTable); ++i)
_opcodes.push_back(&opcodeTable[i]);
+
+ static const OpcodeV3 tempOpcodeTable[] = {
+ Opcode(o3t_defineNewShapes),
+ Opcode(o3t_setCurrentFrame),
+ Opcode(o3t_playSoundEffect),
+ Opcode(o3_dummy),
+ // 0x0a
+ OpcodeUnImpl(),
+ Opcode(o3_getRand),
+ Opcode(o3_dummy)
+ };
+
+ for (int i = 0; i < ARRAYSIZE(tempOpcodeTable); ++i)
+ _opcodesTemporary.push_back(&tempOpcodeTable[i]);
}
} // end of namespace Kyra
diff --git a/engines/kyra/text.h b/engines/kyra/text.h
index d7cc5e9f81..5ae37e32ef 100644
--- a/engines/kyra/text.h
+++ b/engines/kyra/text.h
@@ -68,7 +68,7 @@ protected:
enum {
TALK_SUBSTRING_LEN = 80,
- TALK_SUBSTRING_NUM = 5
+ TALK_SUBSTRING_NUM = 6
};
char _talkBuffer[1040];
diff --git a/engines/kyra/text_v2.cpp b/engines/kyra/text_v2.cpp
index c857a806e3..828371407d 100644
--- a/engines/kyra/text_v2.cpp
+++ b/engines/kyra/text_v2.cpp
@@ -48,7 +48,7 @@ void TextDisplayer_v2::restoreScreen() {
_vm->restorePage3();
_vm->drawAnimObjects();
_screen->hideMouse();
- _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, 2, 0);
+ _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, 2, 0, Screen::CR_NO_P_CHECK);
_screen->showMouse();
_vm->flagAnimObjsForRefresh();
_vm->refreshAnimObjects(0);
diff --git a/engines/kyra/text_v3.cpp b/engines/kyra/text_v3.cpp
index b02599faa4..fd621b879d 100644
--- a/engines/kyra/text_v3.cpp
+++ b/engines/kyra/text_v3.cpp
@@ -33,6 +33,101 @@ TextDisplayer_v3::TextDisplayer_v3(KyraEngine_v3 *vm, Screen_v3 *screen)
: TextDisplayer(vm, screen), _vm(vm), _screen(screen) {
}
+char *TextDisplayer_v3::preprocessString(const char *str) {
+ debugC(9, kDebugLevelMain, "TextDisplayer_v3::preprocessString('%s')", str);
+ strcpy(_talkBuffer, str);
+
+ char *p = _talkBuffer;
+ while (*p) {
+ if (*p++ == '\r')
+ return _talkBuffer;
+ }
+
+ p = _talkBuffer;
+ Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT);
+ _screen->_charWidth = -2;
+
+ const int maxTextWidth = (_vm->language() == 0) ? 176 : 240;
+ int textWidth = _screen->getTextWidth(p);
+
+ if (textWidth > maxTextWidth) {
+ int count = 0, offs = 0;
+ if (textWidth > (3*maxTextWidth)) {
+ count = getCharLength(p, textWidth/4);
+ offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count);
+ p += count + offs;
+ }
+
+ if (textWidth > (2*maxTextWidth)) {
+ count = getCharLength(p, textWidth/3);
+ offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count);
+ p += count + offs;
+ textWidth = _screen->getTextWidth(p);
+ }
+
+ count = getCharLength(p, textWidth/2);
+ offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count);
+ p += count + offs;
+ textWidth = _screen->getTextWidth(p);
+
+ if (textWidth > maxTextWidth) {
+ count = getCharLength(p, textWidth/2);
+ offs = dropCRIntoString(p, getCharLength(p, maxTextWidth), count);
+ }
+ }
+
+ _screen->setFont(curFont);
+ return _talkBuffer;
+}
+
+int TextDisplayer_v3::dropCRIntoString(char *str, int minOffs, int maxOffs) {
+ debugC(9, kDebugLevelMain, "TextDisplayer_v3::dropCRIntoString('%s', %d, %d)", str, maxOffs, minOffs);
+
+ int offset = 0;
+ char *proc = str + minOffs;
+
+ for (int i = minOffs; i < maxOffs; ++i) {
+ if (*proc == ' ') {
+ *proc = '\r';
+ return offset;
+ } else if (*proc == '-') {
+ memmove(proc+1, proc, strlen(proc)+1);
+ *(++proc) = '\r';
+ ++offset;
+ return offset;
+ }
+
+ ++offset;
+ ++proc;
+
+ if (!*proc)
+ return 0;
+ }
+
+ offset = 0;
+ proc = str + minOffs;
+ for (int i = minOffs; i >= 0; --i) {
+ if (*proc == ' ') {
+ *proc = '\r';
+ return offset;
+ } else if (*proc == '-') {
+ memmove(proc+1, proc, strlen(proc)+1);
+ *(++proc) = '\r';
+ ++offset;
+ return offset;
+ }
+
+ --offset;
+ --proc;
+
+ if (!*proc)
+ return 0;
+ }
+
+ *(str + minOffs) = '\r';
+ return 0;
+}
+
void TextDisplayer_v3::printText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2, Screen::FontId font) {
debugC(9, kDebugLevelMain, "TextDisplayer_v3::printText('%s', %d, %d, %d, %d, %d)", str, x, y, c0, c1, c2);
uint8 colorMap[] = { 0, 255, 240, 240 };
@@ -45,4 +140,242 @@ void TextDisplayer_v3::printText(const char *str, int x, int y, uint8 c0, uint8
_screen->setFont(curFont);
}
+void TextDisplayer_v3::restoreScreen() {
+ debugC(9, kDebugLevelMain, "TextDisplayer_v3::restoreScreen()");
+ _vm->restorePage3();
+ _vm->drawAnimObjects();
+ _screen->hideMouse();
+ _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->showMouse();
+ _vm->flagAnimObjsForRefresh();
+ _vm->refreshAnimObjects(0);
+}
+
+void TextDisplayer_v3::calcWidestLineBounds(int &x1, int &x2, int w, int x) {
+ debugC(9, kDebugLevelMain, "TextDisplayer_v3::calcWidestLineBounds(%d, %d)", w, x);
+ x1 = x;
+ x1 -= (w >> 1);
+ x2 = x1 + w + 1;
+
+ if (x1 + w >= 311)
+ x1 = 311 - w - 1;
+
+ if (x1 < 8)
+ x1 = 8;
+
+ x2 = x1 + w + 1;
+}
+
+#pragma mark -
+
+int KyraEngine_v3::chatGetType(const char *str) {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::chatGetType('%s')", str);
+ while (*str)
+ ++str;
+ --str;
+ switch (*str) {
+ case '!':
+ return 2;
+
+ case ')':
+ return 3;
+
+ case '?':
+ return 1;
+
+ case '.':
+ default:
+ return 0;
+ }
+}
+
+int KyraEngine_v3::chatCalcDuration(const char *str) {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::chatCalcDuration('%s')", str);
+ return MAX<int>(120, strlen(str)*6);
+}
+
+void KyraEngine_v3::objectChat(const char *str, int object, int vocHigh, int vocLow) {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::objectChat('%s', %d, %d, %d)", str, object, vocHigh, vocLow);
+
+ if (_mainCharacter.animFrame == 87 || _mainCharacter.animFrame == 0xFFFF || _mainCharacter.x1 <= 0 || _mainCharacter.y1 <= 0)
+ return;
+
+ _chatVocLow = _chatVocHigh = -1;
+ objectChatInit(str, object, vocHigh, vocLow);
+ _chatText = str;
+ _chatObject = object;
+ int chatType = chatGetType(str);
+
+ if (_mainCharacter.facing > 7)
+ _mainCharacter.facing = 5;
+
+ static const uint8 talkScriptTable[] = {
+ 0x10, 0x11, 0x12, 0x13,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x04, 0x05, 0x06, 0x07,
+ 0x00, 0x01, 0x02, 0x03,
+ 0x00, 0x01, 0x02, 0x03,
+ 0x08, 0x09, 0x0A, 0x0B,
+ 0x08, 0x09, 0x0A, 0x0B
+ };
+
+ static const char *talkFilenameTable[] = {
+ "MTFL00S.EMC", "MTFL00Q.EMC", "MTFL00E.EMC", "MTFL00T.EMC",
+ "MTFR00S.EMC", "MTFR00Q.EMC", "MTFR00E.EMC", "MTRF00T.EMC",
+ "MTL00S.EMC", "MTL00Q.EMC", "MTL00E.EMC", "MTL00T.EMC",
+ "MTR00S.EMC", "MTR00Q.EMC", "MTR00E.EMC", "MTR00T.EMC",
+ "MTA00S.EMC", "MTA00Q.EMC", "MTA00Q.EMC", "MTA00T.EMC"
+ };
+
+ int chat = talkScriptTable[chatType + _mainCharacter.facing * 4];
+ objectChatProcess(talkFilenameTable[chat]);
+ _text->restoreScreen();
+ _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing];
+ updateCharacterAnim(0);
+ _chatText = 0;
+ _chatObject = -1;
+ //setNextIdleAnimTimer();
+}
+
+void KyraEngine_v3::objectChatInit(const char *str, int object, int vocHigh, int vocLow) {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::objectChatInit('%s', %d, %d, %d)", str, object, vocHigh, vocLow);
+ str = _text->preprocessString(str);
+ int lineNum = _text->buildMessageSubstrings(str);
+
+ int xPos = 0, yPos = 0;
+
+ if (!object) {
+ int scale = getScale(_mainCharacter.x1, _mainCharacter.y1);
+ yPos = _mainCharacter.y1 - ((_mainCharacter.height * scale) >> 8) - 8;
+ xPos = _mainCharacter.x1;
+ } else {
+ yPos = _talkObjectList[object].y;
+ xPos = _talkObjectList[object].x;
+ }
+
+ yPos -= lineNum * 10;
+ yPos = MAX(yPos, 0);
+ _text->_talkMessageY = yPos;
+ _text->_talkMessageH = lineNum*10;
+
+ int width = _text->getWidestLineWidth(lineNum);
+ _text->calcWidestLineBounds(xPos, yPos, width, xPos);
+ _text->_talkCoords.x = xPos;
+ _text->_talkCoords.w = width + 2;
+
+ restorePage3();
+
+ _screen->hideMouse();
+
+ if (textEnabled()) {
+ objectChatPrintText(str, object);
+ _chatEndTime = _system->getMillis() + chatCalcDuration(str) * _tickLength;
+ } else {
+ _chatEndTime = _system->getMillis();
+ }
+
+ if (speechEnabled()) {
+ _chatVocHigh = vocHigh;
+ _chatVocLow = vocLow;
+ } else {
+ _chatVocHigh = _chatVocLow = -1;
+ }
+
+ _screen->showMouse();
+}
+
+void KyraEngine_v3::objectChatPrintText(const char *str, int object) {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::objectChatPrintText('%s', %d)", str, object);
+ int c1 = _talkObjectList[object].color;
+ str = _text->preprocessString(str);
+ int lineNum = _text->buildMessageSubstrings(str);
+ int maxWidth = _text->getWidestLineWidth(lineNum);
+ int x = (object == 0) ? _mainCharacter.x1 : _talkObjectList[object].x;
+ int cX1 = 0, cX2 = 0;
+ _text->calcWidestLineBounds(cX1, cX2, maxWidth, x);
+
+ for (int i = 0; i < lineNum; ++i) {
+ str = &_text->_talkSubstrings[i*_text->maxSubstringLen()];
+
+ int y = _text->_talkMessageY + i * 10;
+ x = _text->getCenterStringX(str, cX1, cX2);
+
+ _text->printText(str, x, y, c1, 0xF0, 0);
+ }
+}
+
+void KyraEngine_v3::objectChatProcess(const char *script) {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::objectChatProcess('%s')", script);
+
+ memset(&_chatScriptData, 0, sizeof(_chatScriptData));
+ memset(&_chatScriptState, 0, sizeof(_chatScriptState));
+
+ _scriptInterpreter->loadScript(script, &_chatScriptData, &_opcodesTemporary);
+ _scriptInterpreter->initScript(&_chatScriptState, &_chatScriptData);
+ _scriptInterpreter->startScript(&_chatScriptState, 0);
+ while (_scriptInterpreter->validScript(&_chatScriptState))
+ _scriptInterpreter->runScript(&_chatScriptState);
+
+ if (_chatVocHigh >= 0) {
+ playVoice(_chatVocHigh, _chatVocLow);
+ _chatVocHigh = _chatVocLow = -1;
+ }
+
+ _useFrameTable = true;
+ objectChatWaitToFinish();
+ _useFrameTable = false;
+
+ _scriptInterpreter->unloadScript(&_chatScriptData);
+}
+
+void KyraEngine_v3::objectChatWaitToFinish() {
+ debugC(9, kDebugLevelMain, "KyraEngine_v3::objectChatWaitToFinish()");
+ int charAnimFrame = _mainCharacter.animFrame;
+ setCharacterAnimDim(_newShapeWidth, _newShapeHeight);
+
+ _scriptInterpreter->initScript(&_chatScriptState, &_chatScriptData);
+ _scriptInterpreter->startScript(&_chatScriptState, 1);
+
+ bool running = true;
+ const uint32 endTime = _chatEndTime;
+ resetSkipFlag();
+
+ while (running && !_quitFlag) {
+ if (!_scriptInterpreter->validScript(&_chatScriptState))
+ _scriptInterpreter->startScript(&_chatScriptState, 1);
+
+ _temporaryScriptExecBit = false;
+ while (!_temporaryScriptExecBit && _scriptInterpreter->validScript(&_chatScriptState)) {
+ musicUpdate(0);
+ _scriptInterpreter->runScript(&_chatScriptState);
+ }
+
+ int curFrame = _newShapeAnimFrame;
+ uint32 delayTime = _newShapeDelay;
+
+ _mainCharacter.animFrame = curFrame;
+ updateCharacterAnim(0);
+
+ uint32 nextFrame = _system->getMillis() + delayTime * _tickLength;
+
+ while (_system->getMillis() < nextFrame && !_quitFlag) {
+ updateWithText();
+
+ const uint32 curTime = _system->getMillis();
+ if ((textEnabled() && !speechEnabled() && curTime > endTime) || (speechEnabled() && !snd_voiceIsPlaying()) || skipFlag()) {
+ resetSkipFlag();
+ nextFrame = curTime;
+ running = false;
+ }
+
+ delay(10);
+ }
+ }
+
+ _mainCharacter.animFrame = charAnimFrame;
+ updateCharacterAnim(0);
+ resetCharacterAnimDim();
+}
+
} // end of namespace Kyra
diff --git a/engines/kyra/text_v3.h b/engines/kyra/text_v3.h
index c8c9be8e46..9271c6b520 100644
--- a/engines/kyra/text_v3.h
+++ b/engines/kyra/text_v3.h
@@ -33,10 +33,18 @@
namespace Kyra {
class TextDisplayer_v3 : public TextDisplayer {
+friend class KyraEngine_v3;
public:
TextDisplayer_v3(KyraEngine_v3 *vm, Screen_v3 *screen);
+ char *preprocessString(const char *str);
+ int dropCRIntoString(char *str, int minOffs, int maxOffs);
+
void printText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2, Screen::FontId font=Screen::FID_8_FNT);
+
+ void restoreScreen();
+
+ void calcWidestLineBounds(int &x1, int &x2, int w, int x);
protected:
KyraEngine_v3 *_vm;
Screen_v3 *_screen;