diff options
-rw-r--r-- | kyra/kyra.cpp | 825 | ||||
-rw-r--r-- | kyra/kyra.h | 48 | ||||
-rw-r--r-- | kyra/screen.cpp | 156 | ||||
-rw-r--r-- | kyra/screen.h | 11 | ||||
-rw-r--r-- | kyra/script_v1.cpp | 55 | ||||
-rw-r--r-- | kyra/sprites.cpp | 235 | ||||
-rw-r--r-- | kyra/sprites.h | 24 |
7 files changed, 862 insertions, 492 deletions
diff --git a/kyra/kyra.cpp b/kyra/kyra.cpp index 9da78b8495..a1f5915bc2 100644 --- a/kyra/kyra.cpp +++ b/kyra/kyra.cpp @@ -285,7 +285,7 @@ int KyraEngine::init(GameDetector &detector) { _animStates = new AnimObject[31]; assert(_animStates); _charactersAnimState = &_animStates[0]; - _animObjects = &_animStates[5]; + _sprites->_animObjects = &_animStates[5]; _animItems = &_animStates[16]; _scriptInterpreter = new ScriptHelper(this); @@ -308,6 +308,8 @@ int KyraEngine::init(GameDetector &detector) { memset(_shapes, 0, sizeof(_shapes)); memset(_wsaObjects, 0, sizeof(_wsaObjects)); + memset(_flagsTable, 0, sizeof(_flagsTable)); + _fastMode = false; _talkCoords.y = 0x88; _talkCoords.x = 0; @@ -315,9 +317,9 @@ int KyraEngine::init(GameDetector &detector) { _talkMessageY = 0xC; _talkMessageH = 0; _talkMessagePrinted = false; - + _charSayUnk1 = -1; + _charSayUnk3 = -1; _mouseX = _mouseY = -1; - _needMouseUpdate = true; _brandonPosX = _brandonPosY = -1; _brandonDrawFrame = 113; @@ -326,13 +328,15 @@ int KyraEngine::init(GameDetector &detector) { memset(_exitList, 0xFFFF, sizeof(_exitList)); _exitListPtr = 0; _pathfinderFlag = 0; - + _lastFindWayRet = 0; _sceneChangeState = _loopFlag2 = 0; _movFacingTable = new int[150]; assert(_movFacingTable); _movFacingTable[0] = 8; + _configTalkspeed = 1; + return 0; } @@ -368,6 +372,7 @@ KyraEngine::~KyraEngine() { for (int i = 0; i < ARRAYSIZE(_sceneAnimTable); ++i) { free(_sceneAnimTable[i]); } + } void KyraEngine::errorString(const char *buf1, char *buf2) { @@ -390,11 +395,15 @@ int KyraEngine::go() { if (_features & GF_DEMO) { seq_demo(); } else { + setGameFlag(0xF3); + setGameFlag(0xFD); + setGameFlag(0xEF); seq_intro(); startup(); + resetGameFlag(0xEF); mainLoop(); } - res_unloadResources(); + quitGame(); return 0; } @@ -445,9 +454,8 @@ void KyraEngine::startup() { // XXX initAnimStateList(); setCharactersInDefaultScene(); - + _gameSpeed = 50; - memset(_flagsTable, 0, sizeof(_flagsTable)); if (!_scriptInterpreter->loadScript("_STARTUP.EMC", _npcScriptData, _opcodeTable, _opcodeTableSize, 0)) { error("Could not load \"_STARTUP.EMC\" script"); @@ -488,7 +496,6 @@ void KyraEngine::delay(uint32 amount) { case OSystem::EVENT_MOUSEMOVE: _mouseX = event.mouse.x; _mouseY = event.mouse.y; - _needMouseUpdate = true; break; case OSystem::EVENT_QUIT: _quitFlag = true; @@ -506,20 +513,27 @@ void KyraEngine::delay(uint32 amount) { void KyraEngine::mainLoop() { debug(9, "KyraEngine::mainLoop()"); + //enterNewScene(0x0, _currentCharacter->facing, 0, 0, 1); + while (!_quitFlag) { int32 frameTime = (int32)_system->getMillis(); - if (_needMouseUpdate) { - _screen->hideMouse(); - _screen->showMouse(); - _needMouseUpdate = false; - } - _screen->updateScreen(); + _sprites->updateSceneAnims(); + updateAllObjectShapes(); delay((frameTime + _gameSpeed) - _system->getMillis()); } } +void KyraEngine::quitGame() { + res_unloadResources(); + + for (int i = 0; i < 10; i++) + wsa_close(_wsaObjects[i]); + + _system->quit(); +} + void KyraEngine::loadPalette(const char *filename, uint8 *palData) { debug(9, "KyraEngine::loadPalette('%s' 0x%X)", filename, palData); uint32 fileSize = 0; @@ -529,6 +543,7 @@ void KyraEngine::loadPalette(const char *filename, uint8 *palData) { debug(9, "Loading a palette of size %i from '%s'", fileSize, filename); memcpy(palData, srcData, fileSize); } + delete[] srcData; } void KyraEngine::loadBitmap(const char *filename, int tempPage, int dstPage, uint8 *palData) { @@ -561,186 +576,6 @@ void KyraEngine::loadBitmap(const char *filename, int tempPage, int dstPage, uin delete[] srcData; } -void KyraEngine::setTalkCoords(uint16 y) { - debug(9, "KyraEngine::setTalkCoords(%d)", y); - _talkCoords.y = y; -} - -int KyraEngine::getCenterStringX(const char *str, int x1, int x2) { - debug(9, "KyraEngine::getCenterStringX('%s', %d, %d)", str, x1, x2); - _screen->_charWidth = -2; - Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); - int strWidth = _screen->getTextWidth(str); - _screen->setFont(curFont); - _screen->_charWidth = 0; - int w = x2 - x1 + 1; - return x1 + (w - strWidth) / 2; -} - -int KyraEngine::getCharLength(const char *str, int len) { - debug(9, "KyraEngine::getCharLength('%s', %d)", str, len); - int charsCount = 0; - if (*str) { - _screen->_charWidth = -2; - Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); - int i = 0; - while (i <= len && *str) { - i += _screen->getCharWidth(*str++); - ++charsCount; - } - _screen->setFont(curFont); - _screen->_charWidth = 0; - } - return charsCount; -} - -int KyraEngine::dropCRIntoString(char *str, int offs) { - debug(9, "KyraEngine::dropCRIntoString('%s', %d)", str, offs); - int pos = 0; - str += offs; - while (*str) { - if (*str == ' ') { - *str = '\r'; - return pos; - } - ++str; - ++pos; - } - return 0; -} - -char *KyraEngine::preprocessString(const char *str) { - debug(9, "KyraEngine::preprocessString('%s')", str); - assert(strlen(str) < sizeof(_talkBuffer) - 1); - strcpy(_talkBuffer, str); - char *p = _talkBuffer; - while (*p) { - if (*p == '\r') { - return _talkBuffer; - } - ++p; - } - p = _talkBuffer; - Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); - _screen->_charWidth = -2; - int textWidth = _screen->getTextWidth(p); - _screen->_charWidth = 0; - if (textWidth > 176) { - if (textWidth > 352) { - int count = getCharLength(p, textWidth / 3); - int offs = dropCRIntoString(p, count); - p += count + offs; - _screen->_charWidth = -2; - textWidth = _screen->getTextWidth(p); - _screen->_charWidth = 0; - count = getCharLength(p, textWidth / 2); - dropCRIntoString(p, count); - } else { - int count = getCharLength(p, textWidth / 2); - dropCRIntoString(p, count); - } - } - _screen->setFont(curFont); - return _talkBuffer; -} - -int KyraEngine::buildMessageSubstrings(const char *str) { - debug(9, "KyraEngine::buildMessageSubstrings('%s')", str); - int currentLine = 0; - int pos = 0; - while (*str) { - if (*str == '\r') { - assert(currentLine < TALK_SUBSTRING_NUM); - _talkSubstrings[currentLine * TALK_SUBSTRING_LEN + pos] = '\0'; - ++currentLine; - pos = 0; - } else { - _talkSubstrings[currentLine * TALK_SUBSTRING_LEN + pos] = *str; - ++pos; - if (pos > TALK_SUBSTRING_LEN - 2) { - pos = TALK_SUBSTRING_LEN - 2; - } - } - ++str; - } - _talkSubstrings[currentLine * TALK_SUBSTRING_LEN + pos] = '\0'; - return currentLine + 1; -} - -int KyraEngine::getWidestLineWidth(int linesCount) { - debug(9, "KyraEngine::getWidestLineWidth(%d)", linesCount); - int maxWidth = 0; - Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); - _screen->_charWidth = -2; - for (int l = 0; l < linesCount; ++l) { - int w = _screen->getTextWidth(&_talkSubstrings[l * TALK_SUBSTRING_LEN]); - if (maxWidth < w) { - maxWidth = w; - } - } - _screen->setFont(curFont); - _screen->_charWidth = 0; - return maxWidth; -} - -void KyraEngine::calcWidestLineBounds(int &x1, int &x2, int w, int cx) { - debug(9, "KyraEngine::calcWidestLineBounds(%d, %d)", w, cx); - x1 = cx - w / 2; - if (x1 + w >= Screen::SCREEN_W - 12) { - x1 = Screen::SCREEN_W - 12 - w - 1; - } else if (x1 < 12) { - x1 = 12; - } - x2 = x1 + w + 1; -} - -void KyraEngine::restoreTalkTextMessageBkgd(int srcPage, int dstPage) { - debug(9, "KyraEngine::restoreTalkTextMessageBkgd(%d, %d)", srcPage, dstPage); - if (_talkMessagePrinted) { - _talkMessagePrinted = false; - _screen->copyRegion(_talkCoords.x, _talkCoords.y, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, srcPage, dstPage); - } -} - -void KyraEngine::printTalkTextMessage(const char *text, int x, int y, uint8 color, int srcPage, int dstPage) { - debug(9, "KyraEngine::printTalkTextMessage('%s', %d, %d, %d, %d, %d)", text, x, y, color, srcPage, dstPage); - char *str = preprocessString(text); - int lineCount = buildMessageSubstrings(str); - int top = y - lineCount * 10; - if (top < 0) { - top = 0; - } - _talkMessageY = top; - _talkMessageH = lineCount * 10; - int w = getWidestLineWidth(lineCount); - int x1, x2; - calcWidestLineBounds(x1, x2, w, x); - _talkCoords.x = x1; - _talkCoords.w = w + 2; - _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkCoords.y, _talkCoords.w, _talkMessageH, srcPage, dstPage); - int curPage = _screen->_curPage; - _screen->_curPage = srcPage; - for (int i = 0; i < lineCount; ++i) { - top = i * 10 + _talkMessageY; - char *msg = &_talkSubstrings[i * TALK_SUBSTRING_LEN]; - int left = getCenterStringX(msg, x1, x2); - printText(msg, left, top, color, 0xC, 0); - } - _screen->_curPage = curPage; - _talkMessagePrinted = true; -} - -void KyraEngine::printText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2) { - uint8 colorMap[] = { 0, 15, 12, 12 }; - colorMap[3] = c1; - _screen->setTextColor(colorMap, 0, 3); - Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); - _screen->_charWidth = -2; - _screen->printText(str, x, y, c0, c2); - _screen->_charWidth = 0; - _screen->setFont(curFont); -} - void KyraEngine::waitTicks(int ticks) { debug(9, "KyraEngine::waitTicks(%d)", ticks); const uint32 end = _system->getMillis() + ticks * 1000 / 60; @@ -750,6 +585,7 @@ void KyraEngine::waitTicks(int ticks) { switch (event.type) { case OSystem::EVENT_QUIT: _quitFlag = true; + quitGame(); break; case OSystem::EVENT_KEYDOWN: if (event.kbd.flags == OSystem::KBD_CTRL) { @@ -1331,7 +1167,8 @@ void KyraEngine::enterNewScene(int sceneId, int facing, int unk1, int unk2, int char datFileNameBuffer[32]; strcpy(datFileNameBuffer, _roomFilenameTable[tableId]); strcat(datFileNameBuffer, ".DAT"); - _sprites->loadDAT(datFileNameBuffer); + _sprites->loadDAT(datFileNameBuffer, _sceneExits); + _sprites->setupSceneAnims(); _scriptInterpreter->unloadScript(_scriptClickData); loadSceneMSC(); @@ -1940,11 +1777,38 @@ void KyraEngine::initSceneObjectList(int brandonAlive) { } for (int i = 0; i < 11; ++i) { - curAnimState = &_animObjects[i]; - curAnimState->active = 0; - curAnimState->refreshFlag = 0; - curAnimState->bkgdChangeFlag = 0; - // XXX this needs the dat loader + curAnimState = &_sprites->_animObjects[i]; + + if (_sprites->_anims[i].play) { + curAnimState->active = 1; + curAnimState->refreshFlag = 1; + curAnimState->bkgdChangeFlag = 1; + } + else { + curAnimState->active = 0; + curAnimState->refreshFlag = 0; + curAnimState->bkgdChangeFlag = 0; + } + curAnimState->height = _sprites->_anims[i].height; + curAnimState->height2 = _sprites->_anims[i].height2; + curAnimState->width = _sprites->_anims[i].width + 1; + curAnimState->width2 = _sprites->_anims[i].width2; + curAnimState->drawY = _sprites->_anims[i].drawY; + curAnimState->x1 = curAnimState->x2 = _sprites->_anims[i].x; + curAnimState->y1 = curAnimState->y2 = _sprites->_anims[i].y; + curAnimState->background = _sprites->_anims[i].background; + curAnimState->sceneAnimPtr = _sprites->_sceneShapes[_sprites->_anims[i].sprite]; + + if(_sprites->_anims[i].unk2) + curAnimState->flags = 0x800; + else + curAnimState->flags = 0; + + if (_sprites->_anims[i].flipX) + curAnimState->flags |= 0x1; + + _objectQueue = objectQueue(_objectQueue, curAnimState); + } for (int i = 0; i < 12; ++i) { @@ -1991,11 +1855,509 @@ void KyraEngine::initSceneObjectList(int brandonAlive) { preserveAnyChangedBackgrounds(); prepDrawAllObjects(); _screen->hideMouse(); - // XXX game_unkScreen + initSceneScreen(brandonAlive); _screen->showMouse(); copyChangedObjectsForward(0); } +void KyraEngine::initSceneScreen(int brandonAlive) { + // XXX (Pointless?) Palette stuff + //_screen->shuffleScreen(8, 8, 0x130, 0x80, 2, 0, byte_2EE1C); + _screen->copyRegion(1, 8, 1, 8, 304, 0x80, 2, 0); + // XXX More (pointless?) palette stuff + + if (!_scriptInterpreter->startScript(_scriptClick, 2)) + error("Could not start script function 2 of scene script"); + + _scriptClick->variables[7] = brandonAlive; + + while (_scriptInterpreter->validScript(_scriptClick)) + _scriptInterpreter->runScript(_scriptClick); + + if (_currentCharacter->sceneId == 0xD2) { + // XXX + } +} + +#pragma mark - +#pragma mark - Item handling +#pragma mark - + +void KyraEngine::setTalkCoords(uint16 y) { + debug(9, "KyraEngine::setTalkCoords(%d)", y); + _talkCoords.y = y; +} + +int KyraEngine::getCenterStringX(const char *str, int x1, int x2) { + debug(9, "KyraEngine::getCenterStringX('%s', %d, %d)", str, x1, x2); + _screen->_charWidth = -2; + Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); + int strWidth = _screen->getTextWidth(str); + _screen->setFont(curFont); + _screen->_charWidth = 0; + int w = x2 - x1 + 1; + return x1 + (w - strWidth) / 2; +} + +int KyraEngine::getCharLength(const char *str, int len) { + debug(9, "KyraEngine::getCharLength('%s', %d)", str, len); + int charsCount = 0; + if (*str) { + _screen->_charWidth = -2; + Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); + int i = 0; + while (i <= len && *str) { + i += _screen->getCharWidth(*str++); + ++charsCount; + } + _screen->setFont(curFont); + _screen->_charWidth = 0; + } + return charsCount; +} + +int KyraEngine::dropCRIntoString(char *str, int offs) { + debug(9, "KyraEngine::dropCRIntoString('%s', %d)", str, offs); + int pos = 0; + str += offs; + while (*str) { + if (*str == ' ') { + *str = '\r'; + return pos; + } + ++str; + ++pos; + } + return 0; +} + +char *KyraEngine::preprocessString(const char *str) { + debug(9, "KyraEngine::preprocessString('%s')", str); + assert(strlen(str) < sizeof(_talkBuffer) - 1); + strcpy(_talkBuffer, str); + char *p = _talkBuffer; + while (*p) { + if (*p == '\r') { + return _talkBuffer; + } + ++p; + } + p = _talkBuffer; + Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); + _screen->_charWidth = -2; + int textWidth = _screen->getTextWidth(p); + _screen->_charWidth = 0; + if (textWidth > 176) { + if (textWidth > 352) { + int count = getCharLength(p, textWidth / 3); + int offs = dropCRIntoString(p, count); + p += count + offs; + _screen->_charWidth = -2; + textWidth = _screen->getTextWidth(p); + _screen->_charWidth = 0; + count = getCharLength(p, textWidth / 2); + dropCRIntoString(p, count); + } else { + int count = getCharLength(p, textWidth / 2); + dropCRIntoString(p, count); + } + } + _screen->setFont(curFont); + return _talkBuffer; +} + +int KyraEngine::buildMessageSubstrings(const char *str) { + debug(9, "KyraEngine::buildMessageSubstrings('%s')", str); + int currentLine = 0; + int pos = 0; + while (*str) { + if (*str == '\r') { + assert(currentLine < TALK_SUBSTRING_NUM); + _talkSubstrings[currentLine * TALK_SUBSTRING_LEN + pos] = '\0'; + ++currentLine; + pos = 0; + } else { + _talkSubstrings[currentLine * TALK_SUBSTRING_LEN + pos] = *str; + ++pos; + if (pos > TALK_SUBSTRING_LEN - 2) { + pos = TALK_SUBSTRING_LEN - 2; + } + } + ++str; + } + _talkSubstrings[currentLine * TALK_SUBSTRING_LEN + pos] = '\0'; + return currentLine + 1; +} + +int KyraEngine::getWidestLineWidth(int linesCount) { + debug(9, "KyraEngine::getWidestLineWidth(%d)", linesCount); + int maxWidth = 0; + Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); + _screen->_charWidth = -2; + for (int l = 0; l < linesCount; ++l) { + int w = _screen->getTextWidth(&_talkSubstrings[l * TALK_SUBSTRING_LEN]); + if (maxWidth < w) { + maxWidth = w; + } + } + _screen->setFont(curFont); + _screen->_charWidth = 0; + return maxWidth; +} + +void KyraEngine::calcWidestLineBounds(int &x1, int &x2, int w, int cx) { + debug(9, "KyraEngine::calcWidestLineBounds(%d, %d)", w, cx); + x1 = cx - w / 2; + if (x1 + w >= Screen::SCREEN_W - 12) { + x1 = Screen::SCREEN_W - 12 - w - 1; + } else if (x1 < 12) { + x1 = 12; + } + x2 = x1 + w + 1; +} + +void KyraEngine::restoreTalkTextMessageBkgd(int srcPage, int dstPage) { + debug(9, "KyraEngine::restoreTalkTextMessageBkgd(%d, %d)", srcPage, dstPage); + if (_talkMessagePrinted) { + _talkMessagePrinted = false; + _screen->copyRegion(_talkCoords.x, _talkCoords.y, _talkCoords.x, _talkMessageY, _talkCoords.w, _talkMessageH, srcPage, dstPage); + } +} + +void KyraEngine::printTalkTextMessage(const char *text, int x, int y, uint8 color, int srcPage, int dstPage) { + debug(9, "KyraEngine::printTalkTextMessage('%s', %d, %d, %d, %d, %d)", text, x, y, color, srcPage, dstPage); + char *str = preprocessString(text); + int lineCount = buildMessageSubstrings(str); + int top = y - lineCount * 10; + if (top < 0) { + top = 0; + } + _talkMessageY = top; + _talkMessageH = lineCount * 10; + int w = getWidestLineWidth(lineCount); + int x1, x2; + calcWidestLineBounds(x1, x2, w, x); + _talkCoords.x = x1; + _talkCoords.w = w + 2; + _screen->copyRegion(_talkCoords.x, _talkMessageY, _talkCoords.x, _talkCoords.y, _talkCoords.w, _talkMessageH, srcPage, dstPage); + int curPage = _screen->_curPage; + _screen->_curPage = srcPage; + for (int i = 0; i < lineCount; ++i) { + top = i * 10 + _talkMessageY; + char *msg = &_talkSubstrings[i * TALK_SUBSTRING_LEN]; + int left = getCenterStringX(msg, x1, x2); + printText(msg, left, top, color, 0xC, 0); + } + _screen->_curPage = curPage; + _talkMessagePrinted = true; +} + +void KyraEngine::printText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2) { + uint8 colorMap[] = { 0, 15, 12, 12 }; + colorMap[3] = c1; + _screen->setTextColor(colorMap, 0, 3); + Screen::FontId curFont = _screen->setFont(Screen::FID_8_FNT); + _screen->_charWidth = -2; + _screen->printText(str, x, y, c0, c2); + _screen->_charWidth = 0; + _screen->setFont(curFont); +} + +void KyraEngine::waitForChatToFinish(int16 chatDuration, char *chatStr, uint8 charNum) { + debug(9, "KyraEngine::waitForChatToFinish(%i, %s, %i)", chatDuration, chatStr, charNum); + bool hasUpdatedNPCs = false; + bool runLoop = true; + uint8 currPage; + OSystem::Event event; + uint8 tickLength = (uint8)(1000.0 / _gameSpeed); + + //while( towns_isEscKeyPressed() ) + //towns_getKey(); + + uint32 timeToEnd = strlen(chatStr) * 8 * tickLength + _system->getMillis(); + + if (chatDuration != -1 ) { + switch ( _configTalkspeed) { + case 0: chatDuration *= 2; + break; + case 2: chatDuration /= 4; + break; + case 3: chatDuration = -1; + } + } + + if (chatDuration != -1) + chatDuration *= tickLength; + + //disableTimer(0x13); + //disableTimer(0x0E); + //disableTimer(0x12); + //towns_flushKeyb(); + + uint32 timeAtStart = _system->getMillis(); + uint32 loopStart; + while (runLoop) { + loopStart = _system->getMillis(); + /* + if (_currentCharacter.sceneId == 0xD2) + if (seq_playEnd()) + break; + */ + + if( _system->getMillis() < timeToEnd && !hasUpdatedNPCs) { + hasUpdatedNPCs = true; + //disableTimer(0x0F); + _charSayUnk4 = 4; + animRefreshNPC(0); + animRefreshNPC(_charSayUnk1); + + if (_charSayUnk2 != -1) { + _sprites->_animObjects[_charSayUnk2].active = 0; + _sprites->_anims[_charSayUnk2].play = false; + _charSayUnk2 = -1; + } + } + + //updateGameTimers(); + _sprites->updateSceneAnims(); + restoreAllObjectBackgrounds(); + preserveAnyChangedBackgrounds(); + prepDrawAllObjects(); + + currPage = _screen->_curPage; + _screen->_curPage = 2; + printCharacterText(chatStr, charNum); + _screen->_curPage = currPage; + + copyChangedObjectsForward(0); + //processPalette(); + + if ((chatDuration < (int16)(_system->getMillis() - timeAtStart)) && chatDuration != -1) + break; + + while (_system->pollEvent(event)) { + switch (event.type) { + case OSystem::EVENT_KEYDOWN: + if (event.kbd.keycode == 0x20 || event.kbd.keycode == 0xC6) + runLoop = false; + break; + case OSystem::EVENT_QUIT: + quitGame(); + case OSystem::EVENT_LBUTTONDOWN: + runLoop = false; + break; + default: + break; + } + } + delay((loopStart + _gameSpeed) - _system->getMillis()); + } + + /*enableTimer(0x13); + enableTimer(0x0E); + enableTimer(0x12); + enableTimer(0x0F); + clearKyrandiaButtonIO();*/ +} + +void KyraEngine::endCharacterChat(int8 charNum, int16 convoInitialized) { + _charSayUnk3 = -1; + + if (charNum > 4 && charNum < 11) { + //TODO: weird _game_inventory stuff here + } + + if (convoInitialized != 0) { + _charSayUnk1 = -1; + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + updateAllObjectShapes(); + } +} + +void KyraEngine::restoreChatPartnerAnimFrame(int8 charNum) { + _charSayUnk1 = -1; + + if (charNum > 0 && charNum < 5) { + _characterList[charNum].currentAnimFrame = _currentChatPartnerBackupFrame; + animRefreshNPC(charNum); + } + + _currentCharacter->currentAnimFrame = 7; + animRefreshNPC(0); + updateAllObjectShapes(); +} + +void KyraEngine::backupChatPartnerAnimFrame(int8 charNum) { + _charSayUnk1 = 0; + + if (charNum < 5 && charNum > 0) + _currentChatPartnerBackupFrame = _characterList[charNum].currentAnimFrame; + + if (_scaleMode != 0) + _currentCharacter->currentAnimFrame = 7; + else + _currentCharacter->currentAnimFrame = _currentCharAnimFrame; + + animRefreshNPC(0); + updateAllObjectShapes(); +} + +int8 KyraEngine::getChatPartnerNum() { + uint8 sceneTable[] = {0x2, 0x5, 0x2D, 0x7, 0x1B, 0x8, 0x22, 0x9, 0x30, 0x0A}; + int pos = 0; + int partner = -1; + + for (int i = 1; i < 6; i++) { + if (_currentCharacter->sceneId == sceneTable[pos]) { + partner = sceneTable[pos+1]; + break; + } + pos += 2; + } + + for (int i = 1; i < 5; i++) { + if (_characterList[i].sceneId == _currentCharacter->sceneId) { + partner = i; + break; + } + } + return partner; +} + +int KyraEngine::initCharacterChat(int8 charNum) { + if (_charSayUnk1 == -1) { + _charSayUnk1 = 0; + + if (_scaleMode != 0) + _currentCharacter->currentAnimFrame = 7; + else + _currentCharacter->currentAnimFrame = 16; + + animRefreshNPC(0); + updateAllObjectShapes(); + } + + _charSayUnk2 = -1; + flagAllObjectsForBkgdChange(); + restoreAllObjectBackgrounds(); + + if( charNum > 4 && charNum < 11 ) { + // TODO: Fill in weird _game_inventory stuff here + } + + flagAllObjectsForRefresh(); + flagAllObjectsForBkgdChange(); + preserveAnyChangedBackgrounds(); + _charSayUnk3 = charNum; + + return 1; +} + +void KyraEngine::printCharacterText(char *text, int8 charNum) { + uint8 colorTable[] = {0x0F, 0x9, 0x0C9, 0x80, 0x5, 0x81, 0x0E, 0xD8, 0x55, 0x3A, 0x3a}; + int top, left, x1, x2, w, x; + char *msg; + + uint8 color = colorTable[charNum]; + text = preprocessString(text); + int lineCount = buildMessageSubstrings(text); + w = getWidestLineWidth(lineCount); + x = _characterList[charNum].x1; + calcWidestLineBounds(x1, x2, w, x); + + for (int i = 0; i < lineCount; ++i) { + top = i * 10 + _talkMessageY; + msg = &_talkSubstrings[i * TALK_SUBSTRING_LEN]; + left = getCenterStringX(msg, x1, x2); + printText(msg, left, top, color, 0xC, 0); + } +} + +void KyraEngine::characterSays(char *chatStr, int8 charNum, int8 chatDuration) { + debug(9, "KyraEngine:::characterSays('%s', %i, %d)", chatStr, charNum, chatDuration); + uint8 startAnimFrames[] = { 0x10, 0x32, 0x56, 0x0, 0x0, 0x0 }; + + uint16 chatTicks; + int16 convoInitialized; + int8 chatPartnerNum; + + if (_currentCharacter->sceneId == 0xD2) + return; + + convoInitialized = initCharacterChat(charNum); + chatPartnerNum = getChatPartnerNum(); + + if(chatPartnerNum != -1 && chatPartnerNum < 5) + backupChatPartnerAnimFrame(chatPartnerNum); + + if (charNum < 5) { + _characterList[charNum].currentAnimFrame = startAnimFrames[charNum]; + _charSayUnk3 = charNum; + _charSayUnk1 = charNum; + animRefreshNPC(charNum); + } + + char *processedString = preprocessString(chatStr); + int lineNum = buildMessageSubstrings(processedString); + + int16 YPos = _characterList[charNum].y1; + YPos -= _scaleTable[charNum] * _characterList[charNum].height; + YPos -= 8; + YPos -= lineNum * 10; + + if (YPos < 11) + YPos = 11; + + if (YPos > 100 ) + YPos = 100; + + _talkMessageY = YPos; + _talkMessageH = lineNum * 10; + restoreAllObjectBackgrounds(); + + _screen->copyRegion(1, _talkMessageY, 1, 136, 319, _talkMessageH, 2, 2); + _screen->hideMouse(); + + printCharacterText(processedString, charNum); + _screen->showMouse(); + + if (chatDuration == -2) + chatTicks = strlen(processedString) * 9; + else + chatTicks = chatDuration; + + waitForChatToFinish(chatTicks, chatStr, charNum); + + restoreAllObjectBackgrounds(); + + _screen->copyRegion(1, 136, 1, _talkMessageY, 319, _talkMessageH, 2, 2); + preserveAllBackgrounds(); + prepDrawAllObjects(); + _screen->hideMouse(); + + _screen->copyRegion(1, _talkMessageY, 1, _talkMessageY, 319, _talkMessageH, 2, 0); + _screen->showMouse(); + flagAllObjectsForRefresh(); + copyChangedObjectsForward(0); + + if (chatPartnerNum != -1 && chatPartnerNum < 5) + restoreChatPartnerAnimFrame(chatPartnerNum); + + endCharacterChat(charNum, convoInitialized); +} + +void KyraEngine::drawSentenceCommand(char *sentence, int unk1) { + _screen->hideMouse(); + _screen->fillRect(8, 143, 311, 152, 12); + // XXX: palette stuff + + printText(sentence, 8, 143, 0xFF, 12, 0); + _screen->showMouse(); + //setTextFadeTimerCountdown(_textFadeTimerCountdown); + //_palScrollEnabled = 0; +} + #pragma mark - #pragma mark - Item handling #pragma mark - @@ -2127,6 +2489,37 @@ void KyraEngine::placeItemInGenericMapScene(int item, int index) { #pragma mark - Animation specific code #pragma mark - +void KyraEngine::preserveAllBackgrounds() { + uint8 currPage = _screen->_curPage; + _screen->_curPage = 2; + + AnimObject *curObject = _objectQueue; + while (curObject) { + if (!curObject->active && curObject->flags) { + preserveOrRestoreBackground(curObject, false); + curObject->bkgdChangeFlag = 0; + } + curObject = curObject->nextAnimObject; + } + _screen->_curPage = currPage; +} + +void KyraEngine::flagAllObjectsForBkgdChange() { + AnimObject *curObject = _objectQueue; + while (curObject) { + curObject->bkgdChangeFlag = 1; + curObject = curObject->nextAnimObject; + } +} + +void KyraEngine::flagAllObjectsForRefresh() { + AnimObject *curObject = _objectQueue; + while (curObject) { + curObject->refreshFlag = 1; + curObject = curObject->nextAnimObject; + } +} + void KyraEngine::restoreAllObjectBackgrounds() { debug(9, "restoreAllObjectBackground()"); AnimObject *curObject = _objectQueue; @@ -2207,7 +2600,7 @@ void KyraEngine::prepDrawAllObjects() { flagUnk1 = 0x200; if (_brandonStatusBit & 0x40) flagUnk2 = 0x4000; - + while (curObject) { if (curObject->active) { int xpos = curObject->x1; @@ -2276,6 +2669,7 @@ void KyraEngine::prepDrawAllObjects() { void KyraEngine::copyChangedObjectsForward(int refreshFlag) { debug(9, "copyChangedObjectsForward(%d)", refreshFlag); AnimObject *curObject = _objectQueue; + while (curObject) { if (curObject->active) { if (curObject->refreshFlag || refreshFlag) { @@ -2291,6 +2685,7 @@ void KyraEngine::copyChangedObjectsForward(int refreshFlag) { } curObject = curObject->nextAnimObject; } + _screen->updateScreen(); } void KyraEngine::updateAllObjectShapes() { @@ -2299,15 +2694,13 @@ void KyraEngine::updateAllObjectShapes() { preserveAnyChangedBackgrounds(); prepDrawAllObjects(); copyChangedObjectsForward(0); - - _screen->updateScreen(); } void KyraEngine::animRefreshNPC(int character) { debug(9, "animRefreshNPC(%d)", character); AnimObject *animObj = &_charactersAnimState[character]; Character *ch = &_characterList[character]; - + animObj->refreshFlag = 1; animObj->bkgdChangeFlag = 1; int facing = ch->facing; @@ -2352,12 +2745,12 @@ void KyraEngine::animRefreshNPC(int character) { } animObj->width2 = 4; animObj->height2 = 3; - + _objectQueue = objectRemoveQueue(_objectQueue, animObj); if (_objectQueue) { - + _objectQueue = objectQueue(_objectQueue, animObj); } else { - _objectQueue = objectAddHead(_objectQueue, animObj); + _objectQueue = objectAddHead(0, animObj); } } @@ -2368,6 +2761,7 @@ void KyraEngine::animRefreshNPC(int character) { AnimObject *KyraEngine::objectRemoveQueue(AnimObject *queue, AnimObject *rem) { AnimObject *cur = queue; AnimObject *prev = queue; + while (cur != rem && cur) { AnimObject *temp = cur->nextAnimObject; if (!temp) @@ -2383,10 +2777,12 @@ AnimObject *KyraEngine::objectRemoveQueue(AnimObject *queue, AnimObject *rem) { } if (!cur->nextAnimObject) { - if (!prev) { - return 0; - } else { - prev->nextAnimObject = 0; + if (cur == rem) { + if (!prev) { + return 0; + } else { + prev->nextAnimObject = 0; + } } } else { if (cur == rem) { @@ -2424,7 +2820,7 @@ AnimObject *KyraEngine::objectQueue(AnimObject *queue, AnimObject *add) { cur->nextAnimObject = add; add->nextAnimObject = 0; } - return 0; + return queue; } #pragma mark - @@ -2937,7 +3333,8 @@ int KyraEngine::processSceneChange(int *table, int unk1, int frameReset) { if (!temp) continue; ++table; - // XXX updateAnimFlags + _sprites->updateSceneAnims(); + waitTicks(10); // XXX updateMousePointer // XXX updateGameTimers updateAllObjectShapes(); diff --git a/kyra/kyra.h b/kyra/kyra.h index e90aada5de..1fb409ff7e 100644 --- a/kyra/kyra.h +++ b/kyra/kyra.h @@ -87,7 +87,7 @@ struct AnimObject { uint32 flags; int16 drawY; uint8 *sceneAnimPtr; - uint16 animFrameNumber; + int16 animFrameNumber; uint8 *background; uint16 rectSize; int16 x1, y1; @@ -167,13 +167,12 @@ public: uint8 game() const { return _game; } uint32 features() const { return _features; } - SceneExits sceneExits() const { return _sceneExits; } - // ugly hack used by the dat loader - SceneExits &sceneExits() { return _sceneExits; } Common::RandomSource _rnd; int16 _northExitHeight; + Character *_currentCharacter; + typedef void (KyraEngine::*IntroProc)(); typedef int (KyraEngine::*OpcodeProc)(ScriptState *script); @@ -183,16 +182,18 @@ public: const char **seqTextsTable() { return (const char **)_seq_textsTable; } bool seq_skipSequence() const; - + void quitGame(); void loadBitmap(const char *filename, int tempPage, int dstPage, uint8 *palData); void snd_playTheme(int file, int track = 0); void snd_playTrack(int track); void snd_playVoiceFile(int id); bool snd_voicePlaying(); + void snd_playSoundEffect(int track); void printTalkTextMessage(const char *text, int x, int y, uint8 color, int srcPage, int dstPage); void restoreTalkTextMessageBkgd(int srcPage, int dstPage); + void drawSentenceCommand(char *sentence, int unk1); WSAMovieV1 *wsa_open(const char *filename, int offscreenDecode, uint8 *palBuf); void wsa_close(WSAMovieV1 *wsa); @@ -200,6 +201,11 @@ public: void wsa_play(WSAMovieV1 *wsa, int frameNum, int x, int y, int pageNum); void waitTicks(int ticks); + void updateAllObjectShapes(); + void flagAllObjectsForRefresh(); + void animRefreshNPC(int character); + int16 fetchAnimWidth(const uint8 *shape, int16 mult); + int8 fetchAnimHeight(const uint8 *shape, int8 mult); int mouseX() { return _mouseX; } int mouseY() { return _mouseY; } @@ -377,6 +383,15 @@ protected: int getWidestLineWidth(int linesCount); void calcWidestLineBounds(int &x1, int &x2, int w, int cx); void printText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2); + void characterSays(char *msg, int8 charNum, int8 chatDuration); + int initCharacterChat(int8 charNum); + int8 getChatPartnerNum(); + void backupChatPartnerAnimFrame(int8 charNum); + void restoreChatPartnerAnimFrame(int8 charNum); + void endCharacterChat(int8 charNum, int16 arg_4); + void waitForChatToFinish(int16 chatDuration, char *str, uint8 charNum); + void printCharacterText(char *text, int8 charNum); + void setCharacterDefaultFrame(int character); void setCharactersPositions(int character); void setCharactersHeight(); @@ -401,16 +416,15 @@ protected: byte findItemAtPos(int x, int y); void placeItemInGenericMapScene(int item, int index); void initSceneObjectList(int brandonAlive); + void initSceneScreen(int brandonAlive); + void preserveAllBackgrounds(); + void flagAllObjectsForBkgdChange(); void restoreAllObjectBackgrounds(); void preserveAnyChangedBackgrounds(); void preserveOrRestoreBackground(AnimObject *obj, bool restore); void prepDrawAllObjects(); void copyChangedObjectsForward(int refreshFlag); - void updateAllObjectShapes(); - void animRefreshNPC(int character); int findDuplicateItemShape(int shape); - int16 fetchAnimWidth(const uint8 *shape, int16 mult); - int8 fetchAnimHeight(const uint8 *shape, int8 mult); int findWay(int x, int y, int toX, int toY, int *moveTable, int moveTableSize); int findSubPath(int x, int y, int toX, int toY, int *moveTable, int start, int end); int getFacingFromPointToPoint(int x, int y, int toX, int toY); @@ -424,7 +438,7 @@ protected: AnimObject *objectRemoveQueue(AnimObject *queue, AnimObject *rem); AnimObject *objectAddHead(AnimObject *queue, AnimObject *head); AnimObject *objectQueue(AnimObject *queue, AnimObject *add); - + AnimObject *_animStates; void seq_demo(); void seq_intro(); void seq_introLogos(); @@ -438,7 +452,7 @@ protected: void snd_startTrack(); void snd_haltTrack(); void snd_setSoundEffectFile(int file); - void snd_playSoundEffect(int track); + static OpcodeProc _opcodeTable[]; static const int _opcodeTableSize; @@ -509,6 +523,9 @@ protected: int16 _brandonScaleX; int16 _brandonScaleY; int _brandonDrawFrame; + + uint16 _currentChatPartnerBackupFrame; + uint16 _currentCharAnimFrame; int8 *_sceneAnimTable[50]; @@ -528,10 +545,14 @@ protected: int _lastFindWayRet; int *_movFacingTable; + int8 _charSayUnk1; // this is byte_2EE24 + int8 _charSayUnk2; + int8 _charSayUnk3; // this is byte_2EE25 + int8 _charSayUnk4; // this is byte_2EE26 + + uint8 _configTalkspeed; AnimObject *_objectQueue; - AnimObject *_animStates; AnimObject *_charactersAnimState; - AnimObject *_animObjects; AnimObject *_animItems; int _curMusicTheme; @@ -553,7 +574,6 @@ protected: ScriptData *_scriptClickData; Character *_characterList; - Character *_currentCharacter; uint8 *_seq_Forest; uint8 *_seq_KallakWriting; diff --git a/kyra/screen.cpp b/kyra/screen.cpp index 342763dd4b..58eab34910 100644 --- a/kyra/screen.cpp +++ b/kyra/screen.cpp @@ -62,11 +62,6 @@ Screen::Screen(KyraEngine *vm, OSystem *system) _decodeShapeBufferSize = 0; _animBlockPtr = NULL; _animBlockSize = 0; - _mouseShape = NULL; - _mouseShapeSize = 0; - _mouseRect = NULL; - _mouseRectSize = 0; - _mouseDrawWidth = 0; } Screen::~Screen() { @@ -75,15 +70,13 @@ Screen::~Screen() { _pagePtrs[pageNum] = _pagePtrs[pageNum + 1] = 0; } for (int f = 0; f < ARRAYSIZE(_fonts); ++f) { - free(_fonts[f].fontData); + delete[] _fonts[f].fontData; _fonts[f].fontData = NULL; } free(_currentPalette); free(_screenPalette); free(_decodeShapeBuffer); free(_animBlockPtr); - free(_mouseShape); - free(_mouseRect); for (int i = 0; i < 3; ++i) { free(_palettes[i]); } @@ -305,6 +298,7 @@ void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint void Screen::copyCurPageBlock(int x, int y, int h, int w, uint8 *dst) { debug(9, "Screen::copyCurPageBlock(%d, %d, %d, %d, 0x%X)", x, y, w, h, dst); + assert(dst); if (x < 0) { x = 0; } else if (x >= 40) { @@ -389,6 +383,8 @@ void Screen::setAnimBlockPtr(int size) { debug(9, "Screen::setAnimBlockPtr(%d)", size); free(_animBlockPtr); _animBlockPtr = (uint8 *)malloc(size); + assert(_animBlockPtr); + memset(_animBlockPtr, 0, size); _animBlockSize = size; } @@ -1590,14 +1586,14 @@ void Screen::hideMouse() { debug(9, "hideMouse()"); // if mouseDisabled // return - restoreMouseRect(); + _system->showMouse(false); } void Screen::showMouse() { debug(9, "showMouse()"); // if mouseDisabled // return - copyMouseToScreen(); + _system->showMouse(true); } void Screen::setShapePages(int page1, int page2) { @@ -1606,140 +1602,30 @@ void Screen::setShapePages(int page1, int page2) { _shapePages[1] = _pagePtrs[page2]; } -byte *Screen::setMouseCursor(int x, int y, byte *shape) { +void Screen::setMouseCursor(int x, int y, byte *shape) { debug(9, "setMouseCursor(%d, %d, 0x%X)", x, y, shape); if (!shape) - return _mouseShape; + return; // if mouseDisabled // return _mouseShape - - restoreMouseRect(); - + if (_vm->features() & GF_TALKIE) shape += 2; - - int mouseRectSize = getRectSize((READ_LE_UINT16(shape + 3) >> 3) + 2, shape[5]); - if (_mouseRectSize < mouseRectSize) { - free(_mouseRect); - _mouseRect = (uint8*)malloc(mouseRectSize << 3); - assert(_mouseRect); - _mouseRectSize = mouseRectSize; - } - - int shapeSize = READ_LE_UINT16(shape + 8) + 10; - if (_vm->features() & GF_TALKIE) - shapeSize += 2; - if (READ_LE_UINT16(shape) & 1) - shapeSize += 16; - - if (_mouseShapeSize < shapeSize) { - free(_mouseShape); - _mouseShape = (uint8*)malloc(shapeSize); - assert(_mouseShape); - _mouseShapeSize = shapeSize; - } - - byte *dst = _mouseShape; - byte *src = shape; - if (_vm->features() & GF_TALKIE) - dst += 2; - - if (!(READ_LE_UINT16(shape) & 2)) { - uint16 newFlags = 0; - newFlags = READ_LE_UINT16(src) | 2; src += 2; - WRITE_LE_UINT16(dst, newFlags); dst += 2; - memcpy(dst, src, 6); - dst += 6; - src += 6; - int size = READ_LE_UINT16(src); src += 2; - WRITE_LE_UINT16(dst, size); dst += 2; - if (newFlags & 1) { - memcpy(dst, src, 8); - dst += 16; - src += 16; - } - decodeFrame4(src, _animBlockPtr, size); - memcpy(dst, _animBlockPtr, size); - } else { - int size = READ_LE_UINT16(shape + 6); - memcpy(dst, src, size); - } - - _mouseXOffset = x; _mouseYOffset = y; - if (_vm->features() & GF_TALKIE) { - _mouseHeight = _mouseShape[7]; - _mouseWidth = (READ_LE_UINT16(_mouseShape + 5) >> 3) + 2; - } else { - _mouseHeight = _mouseShape[5]; - _mouseWidth = (READ_LE_UINT16(_mouseShape + 3) >> 3) + 2; - } - - copyMouseToScreen(); - - return _mouseShape; -} -void Screen::restoreMouseRect() { - debug(9, "restoreMouseRect()"); - // if disableMouse - // return + int mouseHeight = *(shape+2); + int mouseWidth = (READ_LE_UINT16(shape + 3)) + 2; - if (_mouseDrawWidth && _mouseRect) { - copyScreenFromRect(_mouseDrawX, _mouseDrawY, _mouseDrawWidth, _mouseDrawHeight, _mouseRect); - } - _mouseDrawWidth = 0; -} + uint8 *cursor = (uint8 *)malloc(mouseHeight * mouseWidth); + fillRect(0, 0, mouseWidth, mouseHeight, 0, 3); + drawShape(3, shape, 0, 0, 0, 0); + + copyRegionToBuffer(3, 0, 0, mouseWidth, mouseHeight, cursor); + _system->setMouseCursor(cursor, mouseWidth, mouseHeight, 0, 0, 0); + _system->showMouse(true); + free(cursor); + + return; -void Screen::copyMouseToScreen() { - debug(9, "copyMouseToScreen()"); - // if disableMouse - // return - - restoreMouseRect(); - - int width = _mouseWidth; - int height = _mouseHeight; - int xpos = _vm->mouseX() - _mouseXOffset; - int ypos = _vm->mouseY() - _mouseYOffset; - if (xpos < -1 || ypos < -1) { - return; - } - - int xposTemp = xpos; - int yposTemp = ypos; - - if (xposTemp < 0) { - xposTemp = 0; - } - if (yposTemp < 0) { - height += ypos; - yposTemp = 0; - } - - xposTemp >>= 3; - _mouseDrawX = xposTemp; - _mouseDrawY = yposTemp; - - xposTemp += width; - xposTemp -= 40; - if (xposTemp >= 0) { - width -= xposTemp; - } - - yposTemp += height; - yposTemp -= 200; - if (yposTemp >= 0) { - height -= yposTemp; - } - - _mouseDrawWidth = width; - _mouseDrawHeight = height; - - if (_mouseRect) { - copyScreenToRect(_mouseDrawX, _mouseDrawY, width, height, _mouseRect); - } - - drawShape(0, _mouseShape, xpos, ypos, 0, 0, 0); } void Screen::copyScreenFromRect(int x, int y, int w, int h, uint8 *ptr) { diff --git a/kyra/screen.h b/kyra/screen.h index 67bf4f138c..1933382fa7 100644 --- a/kyra/screen.h +++ b/kyra/screen.h @@ -123,7 +123,7 @@ public: void hideMouse(); void showMouse(); void setShapePages(int page1, int page2); - byte *setMouseCursor(int x, int y, byte *shape); + void setMouseCursor(int x, int y, byte *shape); uint8 *getPalette(int num); byte getShapeFlag1(int x, int y); @@ -152,15 +152,6 @@ private: int _decodeShapeBufferSize; uint8 *_animBlockPtr; int _animBlockSize; - - uint8 *_mouseShape; - uint8 *_mouseRect; - int _mouseShapeSize; - int _mouseRectSize; - int _mouseDrawX, _mouseDrawY; - int _mouseDrawWidth, _mouseDrawHeight; - int _mouseWidth, _mouseHeight; - int _mouseXOffset, _mouseYOffset; OSystem *_system; KyraEngine *_vm; diff --git a/kyra/script_v1.cpp b/kyra/script_v1.cpp index caaecfaf51..ce5dcd28c4 100644 --- a/kyra/script_v1.cpp +++ b/kyra/script_v1.cpp @@ -122,7 +122,7 @@ void ScriptHelper::c1_execOpcode() { } void ScriptHelper::c1_ifNotJmp() { - if (_curScript->stack[++_curScript->sp-1] != 0) { + if (!_curScript->stack[_curScript->sp++]) { _parameter &= 0x7FFF; _curScript->ip = _curScript->dataPtr->data + (_parameter << 1); } @@ -296,6 +296,7 @@ void ScriptHelper::c1_setRetAndJmp() { #pragma mark - #define stackPos(x) script->stack[script->sp+x] +#define stackPosString(x) (char *)&script->dataPtr->text[READ_BE_UINT16( &((uint16 *)script->dataPtr->text)[stackPos(x)])] int KyraEngine::cmd_magicInMouseItem(ScriptState *script) { warning("STUB: cmd_magicInMouseItem"); @@ -303,7 +304,16 @@ int KyraEngine::cmd_magicInMouseItem(ScriptState *script) { } int KyraEngine::cmd_characterSays(ScriptState *script) { - warning("STUB: cmd_characterSays"); + debug(9, "cmd_characterSays(0x%X)", script); + // Japanese version? + /*const char *str1 = "âuâëâôââôüAé?é¢ùêé¢é+é®üH"; + const char *str2 = "âuâëâôâ\\âôüAé?é¢ùêé¢é+é®üH"; + + if (strcmp(stackPosString(0), str1) == 0) + characterSays((char *)str2, stackPos(1), stackPos(2)); + else*/ + characterSays(stackPosString(0), stackPos(1), stackPos(2)); + return 0; } @@ -314,7 +324,7 @@ int KyraEngine::cmd_pauseTicks(ScriptState *script) { int KyraEngine::cmd_drawSceneAnimShape(ScriptState *script) { debug(9, "cmd_drawSceneAnimShape(0x%X)", script); - _screen->drawShape(stackPos(4), _sprites->getSceneShape(stackPos(0)), stackPos(1), stackPos(2), 0, stackPos(3)); + _screen->drawShape(stackPos(4), _sprites->_sceneShapes[stackPos(0)], stackPos(1), stackPos(2), 0, stackPos(3)); return 0; } @@ -417,13 +427,13 @@ int KyraEngine::cmd_savePageToDisk(ScriptState *script) { int KyraEngine::cmd_sceneAnimOn(ScriptState *script) { debug(9, "cmd_sceneAnimOn(0x%X)", script); - _sprites->enableAnim(stackPos(0)); + _sprites->_anims[stackPos(0)].play = true; return 0; } int KyraEngine::cmd_sceneAnimOff(ScriptState *script) { debug(9, "cmd_sceneAnimOff(0x%X)", script); - _sprites->disableAnim(stackPos(0)); + _sprites->_anims[stackPos(0)].play = false; return 0; } @@ -530,7 +540,8 @@ int KyraEngine::cmd_magicOutMouseItem(ScriptState *script) { } int KyraEngine::cmd_internalAnimOn(ScriptState *script) { - warning("STUB: cmd_internalAnimOn"); + debug(9, "cmd_internalAnimOn(0x%X)", script); + _sprites->_animObjects[stackPos(0)].active = 1; return 0; } @@ -552,11 +563,8 @@ int KyraEngine::cmd_setScaleMode(ScriptState *script) { int KyraEngine::cmd_openWSAFile(ScriptState *script) { debug(9, "cmd_openWSAFile(0x%X)", script); - int wsaIndex = stackPos(0); - uint16 offset = READ_BE_UINT16(&script->dataPtr->text[wsaIndex]); - char *filename = (char*)&script->dataPtr->text[offset]; - - wsaIndex = stackPos(1); + char *filename = stackPosString(0); + int wsaIndex = stackPos(1); // stackPos(2) is NOT used whyever int offscreenDecode = 0; if (!stackPos(3)) { @@ -646,7 +654,8 @@ int KyraEngine::cmd_popBrandonIntoScene(ScriptState *script) { } int KyraEngine::cmd_restoreAllObjectBackgrounds(ScriptState *script) { - warning("STUB: cmd_restoreAllObjectBackgrounds"); + debug(9, "cmd_restoreAllObjectBackgrounds(0x%X)", script); + restoreAllObjectBackgrounds(); return 0; } @@ -747,7 +756,8 @@ int KyraEngine::cmd_drawCharacterStanding(ScriptState *script) { } int KyraEngine::cmd_internalAnimOff(ScriptState *script) { - warning("STUB: cmd_internalAnimOff"); + debug(9, "cmd_internalAnimOff(0x%X)", script); + _sprites->_animObjects[stackPos(0)].active = 0; return 0; } @@ -916,7 +926,7 @@ int KyraEngine::cmd_walkCharacterToPoint(ScriptState *script) { ++curPos; // XXX waitTicks(10); - // XXX updateAnimFlags(); + _sprites->updateSceneAnims(); // XXX updateMouseCursor(); // XXX updateGameTimers(); updateAllObjectShapes(); @@ -951,13 +961,17 @@ int KyraEngine::cmd_preserveAllObjectBackgrounds(ScriptState *script) { } int KyraEngine::cmd_updateSceneAnimations(ScriptState *script) { - warning("STUB: cmd_updateSceneAnimations"); + debug(9, "cmd_updateSceneAnimations(0x%X)", script); + if (stackPos(0)) { + _sprites->updateSceneAnims(); + updateAllObjectShapes(); + } return 0; } int KyraEngine::cmd_sceneAnimationActive(ScriptState *script) { - warning("STUB: cmd_sceneAnimationActive"); - return 0; + debug(9, "cmd_sceneAnimationActive(0x%X)", script); + return _sprites->_anims[stackPos(0)].play; } int KyraEngine::cmd_setCharactersMovementDelay(ScriptState *script) { @@ -1062,7 +1076,9 @@ int KyraEngine::cmd_createAmuletJewel(ScriptState *script) { } int KyraEngine::cmd_setSceneAnimCurrXY(ScriptState *script) { - warning("STUB: cmd_setSceneAnimCurrXY"); + debug(9, "cmd_setSceneAnimCurrXY(0x%X)", script); + _sprites->_anims[stackPos(0)].x = stackPos(1); + _sprites->_anims[stackPos(0)].y = stackPos(2); return 0; } @@ -1218,7 +1234,8 @@ int KyraEngine::cmd_setScaleDepthTableValue(ScriptState *script) { } int KyraEngine::cmd_message(ScriptState *script) { - warning("STUB: cmd_message"); + debug(9, "cmd_message(0x%X)", script); + drawSentenceCommand(stackPosString(0), stackPos(1)); return 0; } diff --git a/kyra/sprites.cpp b/kyra/sprites.cpp index 8f95789459..bea98591b9 100644 --- a/kyra/sprites.cpp +++ b/kyra/sprites.cpp @@ -46,82 +46,99 @@ Sprites::Sprites(KyraEngine *engine, OSystem *system) { Sprites::~Sprites() { delete[] _dat; freeSceneShapes(); -} - -uint8 *Sprites::getSceneShape(uint8 sceneShapeID) { - assert( sceneShapeID < ARRAYSIZE(_sceneShapes)); - return _sceneShapes[sceneShapeID]; -} - -void Sprites::drawSprites(uint8 srcPage, uint8 dstPage) { - int flags; - for (int i = 0; i < MAX_NUM_ANIMS; i++) { - if (_anims[i].script == 0 || !_anims[i].play) - break; - if (_anims[i].sprite >= 0) { - assert( _anims[i].sprite < ARRAYSIZE(_sceneShapes)); - uint8 *sprite = _sceneShapes[_anims[i].sprite]; - - //debug(1, "Drawing from X %i, Y %i, to X %i, Y %i, width %i, height %i, srcPage %i, dstPage %i", - // sprite.x, sprite.y, _anims[i].x, _anims[i].y, sprite.width, sprite.height, srcPage, dstPage); - flags = Screen::CR_CLIPPED; - if (_anims[i].flipX) - flags |= Screen::CR_X_FLIPPED; - - //_screen->copyRegion(sprite.x, sprite.y, _anims[i].x, _anims[i].y, sprite.width, sprite.height, srcPage, dstPage, flags); - _screen->drawShape(0, sprite, _anims[i].x, _anims[i].y, 0, 0, 0); - } + if (_anims[i].background) + free(_anims[i].background); } } -void Sprites::doAnims() { - debug(9, "Sprites::doAnims()"); - uint32 currTime = _system->getMillis(); - for (int i = 0; i < MAX_NUM_ANIMS; i++) { - if (_anims[i].script == 0 || !_anims[i].play || _anims[i].nextRun != 0 && _anims[i].nextRun > currTime) - continue; +void Sprites::setupSceneAnims() { + debug(9, "Sprites::setupSceneAnims()"); + uint8 *data; - uint8 *data; + for (int i = 0; i < MAX_NUM_ANIMS; i++) { + if (_anims[i].background) { + free(_anims[i].background); + _anims[i].background = 0; + } - if (_anims[i].reentry == 0) { + if (_anims[i].script != 0) { data = _anims[i].script; - //debug(1, "---Start of anim script---"); assert( READ_LE_UINT16(data) == 0xFF86 ); + data += 4; + + //sceneUnk16[i] = READ_LE_UINT16(data); + data += 4; + _anims[i].unk2 = READ_LE_UINT16(data); + data += 4; + + if (_engine->_northExitHeight > READ_LE_UINT16(data)) + _anims[i].drawY = _engine->_northExitHeight; + else + _anims[i].drawY = READ_LE_UINT16(data); + data += 4; + + //sceneUnk2[i] = READ_LE_UINT16(data); + data += 4; + + _anims[i].x = READ_LE_UINT16(data); + data += 4; + _anims[i].y = READ_LE_UINT16(data); + data += 4; + _anims[i].width = *(data); + data += 4; + _anims[i].height = *(data); + data += 4; + _anims[i].sprite = READ_LE_UINT16(data); + data += 4; + _anims[i].flipX = READ_LE_UINT16(data); + data += 4; + _anims[i].width2 = *(data); + data += 4; + _anims[i].height2 = *(data); + data += 4; + _anims[i].unk1 = READ_LE_UINT16(data); + data += 4; + _anims[i].play = READ_LE_UINT16(data); data += 2; - //debug(1, "Default X of sprite: %i", READ_LE_UINT16(data + 0x12) ); - _anims[i].x = READ_LE_UINT16(data + 0x12); - //debug(1, "Default Y of sprite: %i", READ_LE_UINT16(data + 0x16) ); - _anims[i].y = READ_LE_UINT16(data + 0x16); + _anims[i].script = data; - //debug(1, "Anim %i flags: 22h: %i, 1ah: %i", i, READ_LE_UINT16(data + 0x22), READ_LE_UINT16(data + 0x1a)); + int bkgdWidth = _anims[i].width; + int bkgdHeight = _anims[i].height; - /* - debug(1, "Anim %i data: 0h: %i, 2h: %i,4h: %i,6h: %i,8h: %i,ah: %i,ch: %i", i, READ_LE_UINT16(data + 0x0), - READ_LE_UINT16(data + 0x2), READ_LE_UINT16(data + 0x4),READ_LE_UINT16(data + 0x6),READ_LE_UINT16(data + 0x8), - READ_LE_UINT16(data + 0xa),READ_LE_UINT16(data + 0xc)); + if (_anims[i].width2) + bkgdWidth += (_anims[i].width2 >> 3) + 1; - debug(1, "Anim %i data: eh: %i, 10h: %i,12h: %i,14h: %i,16h: %i,18h: %i,1ah: %i", i, READ_LE_UINT16(data + 0xe), - READ_LE_UINT16(data + 0x10), READ_LE_UINT16(data + 0x12),READ_LE_UINT16(data + 0x14),READ_LE_UINT16(data + 0x16), - READ_LE_UINT16(data + 0x18),READ_LE_UINT16(data + 0x1a)); + if (_anims[i].height2) + bkgdHeight += _anims[i].height2; - debug(1, "Anim %i data: 1ch: %i, 1fh: %i,22h: %i,24h: %i,26h: %i,28h: %i,2ah: %i", i, READ_LE_UINT16(data + 0x1c), - READ_LE_UINT16(data + 0x1f), READ_LE_UINT16(data + 0x22),READ_LE_UINT16(data + 0x24),READ_LE_UINT16(data + 0x26), - READ_LE_UINT16(data + 0x28),READ_LE_UINT16(data + 0x2a)); - */ + _anims[i].background = (uint8 *)malloc(_screen->getRectSize(bkgdWidth + 1, bkgdHeight)); + //_anims[i].background = (uint8 *)malloc(100*100); + assert(_anims[i].background); + } + } +} + +void Sprites::updateSceneAnims() { + debug(9, "Sprites::updateSceneAnims()"); + uint32 currTime = _system->getMillis(); + uint8 *data; + bool endLoop; + for (int i = 0; i < MAX_NUM_ANIMS; i++) { + if (_anims[i].script == 0 || !_anims[i].play || _anims[i].nextRun != 0 && _anims[i].nextRun > currTime) + continue; - // TODO: Find out what the rest of this data (next 38h bytes) does. - data += 0x38; + if (_anims[i].reentry == 0) { + data = _anims[i].script; } else { data = _anims[i].reentry; _anims[i].reentry = 0; } - bool endLoop = false; - + endLoop = false; while (READ_LE_UINT16(data) != 0xFF87 && !endLoop) { uint16 rndNr; uint16 anim; @@ -142,6 +159,7 @@ void Sprites::doAnims() { _anims[i].y = READ_LE_UINT16(data); data += 2; _anims[i].flipX = false; + refreshSceneAnimObject(i, _anims[i].sprite, _anims[i].x, _anims[i].y, _anims[i].flipX, _anims[i].unk1); break; case 0xFF8D: data += 2; @@ -158,6 +176,7 @@ void Sprites::doAnims() { _anims[i].y = READ_LE_UINT16(data); data += 2; _anims[i].flipX = true; + refreshSceneAnimObject(i, _anims[i].sprite, _anims[i].x, _anims[i].y, _anims[i].flipX, _anims[i].unk1); break; case 0xFF8A: data += 2; @@ -174,7 +193,7 @@ void Sprites::doAnims() { data += 2; debug(5, "Maximum time %i", READ_LE_UINT16(data)); data += 2; - _anims[i].nextRun = _system->getMillis() + rndNr * _animDelay; + _anims[i].nextRun = _system->getMillis() + rndNr * _animDelay; break; case 0xFF8C: data += 2; @@ -185,11 +204,13 @@ void Sprites::doAnims() { break; case 0xFF99: data += 2; - debug(1, "TODO func: Set value of animation property 32h to 1"); + debug(1, "func: Set value of unknown animation property to 1"); + _anims[i].unk1 = 1; break; case 0xFF9A: data += 2; - debug(1, "TODO func: Set value of animation property 32h to 0"); + debug(1, "func: Set value of unknown animation property to 0"); + _anims[i].unk1 = 0; break; case 0xFF97: data += 2; @@ -234,6 +255,7 @@ void Sprites::doAnims() { _anims[i].sprite = READ_LE_UINT16(data); _anims[i].flipX = false; data += 2; + refreshSceneAnimObject(i, _anims[i].sprite, _anims[i].x, _anims[i].y, _anims[i].flipX, _anims[i].unk1); break; case 0xFF91: data += 2; @@ -242,6 +264,7 @@ void Sprites::doAnims() { _anims[i].sprite = READ_LE_UINT16(data); _anims[i].flipX = true; data += 2; + refreshSceneAnimObject(i, _anims[i].sprite, _anims[i].x, _anims[i].y, _anims[i].flipX, _anims[i].unk1); break; case 0xFF92: data += 2; @@ -279,8 +302,6 @@ void Sprites::doAnims() { data += 2; _anims[anim].play = false; _anims[anim].sprite = -1; - //debug(1, "Arg2 %i", READ_LE_UINT16(data)); - //data += 2; break; /* case 0xFF97: data += 2; @@ -288,20 +309,23 @@ void Sprites::doAnims() { break;*/ case 0xFFAD: data += 2; - debug(1, "TODO func: Set Brandon's X coordinate"); - debug(1, "X %i", READ_LE_UINT16(data)); + debug(5, "func: Set Brandon's X coordinate"); + debug(5, "X %i", READ_LE_UINT16(data)); + _engine->_currentCharacter->x1 = READ_LE_UINT16(data); data += 2; break; case 0xFFAE: data += 2; - debug(1, "TODO func: Set Brandon's Y coordinate"); - debug(1, "Y %i", READ_LE_UINT16(data)); + debug(5, "func: Set Brandon's Y coordinate"); + debug(5, "Y %i", READ_LE_UINT16(data)); + _engine->_currentCharacter->y1 = READ_LE_UINT16(data); data += 2; break; case 0xFFAF: data += 2; - debug(1, "TODO func: Set Brandon's X sprite"); - debug(1, "Sprite %i", READ_LE_UINT16(data)); + debug(5, "func: Set Brandon's sprite"); + debug(5, "Sprite %i", READ_LE_UINT16(data)); + _engine->_currentCharacter->currentAnimFrame = READ_LE_UINT16(data); data += 2; break; case 0xFFAA: @@ -310,28 +334,36 @@ void Sprites::doAnims() { break; case 0xFFAB: data += 2; - debug(1, "TODO func: Update Brandon's sprite"); + debug(5, "func: Update Brandon's sprite"); + _engine->animRefreshNPC(0); + _engine->flagAllObjectsForRefresh(); + _engine->updateAllObjectShapes(); break; case 0xFFB0: data += 2; - debug(1, "TODO func: Play sound"); - debug(1, "Sound index %i", READ_LE_UINT16(data)); + debug(5, "func: Play sound"); + debug(5, "Sound index %i", READ_LE_UINT16(data)); + _engine->snd_playSoundEffect(READ_LE_UINT16(data)); data += 2; break; case 0xFFB1: data += 2; - debug(1, "TODO func: Set unknown global bit"); + debug(1, "TODO func: Set animator beacon flag"); break; case 0xFFB2: data += 2; - debug(1, "TODO func: Reset unknown global bit"); + debug(1, "TODO func: Reset animator beacon flag"); break; case 0xFFB4: data += 2; - debug(1, "TODO func: Play (at random) a certain sound at a certain percentage of time"); - debug(1, "Sound index %i", READ_LE_UINT16(data)); + debug(5, "func: Play (at random) a certain sound at a certain percentage of time"); + debug(5, "Sound index %i", READ_LE_UINT16(data)); + int sound = READ_LE_UINT16(data); data += 2; - debug(1, "Percentage %i", READ_LE_UINT16(data)); + debug(5, "Percentage %i", READ_LE_UINT16(data)); + rndNr = _rnd.getRandomNumber(100); + if (rndNr <= READ_LE_UINT16(data)) + _engine->snd_playSoundEffect(sound); data += 2; break; case 0xFFA7: @@ -341,7 +373,7 @@ void Sprites::doAnims() { data += 2; break; default: - debug(1, "Unsupported anim command %X", READ_LE_UINT16(data)); + debug(1, "Unsupported anim command %X in script %i", READ_LE_UINT16(data), i); //endLoop = true; data += 1; break; @@ -350,21 +382,19 @@ void Sprites::doAnims() { if (READ_LE_UINT16(data) == 0xFF87) _anims[i].play = false; - - //debug(1, "---End of anim script---"); } } -void Sprites::loadDAT(const char *filename) { +void Sprites::loadDAT(const char *filename, SceneExits &exits) { debug(9, "Sprites::loadDat('%s')", filename); uint32 fileSize; - uint8 spritesLoaded = 0; delete[] _dat; + _spriteDefStart = 0; _dat = _res->fileData(filename, &fileSize); - memset(_anims, 0, sizeof(Anim) * MAX_NUM_ANIMS); + memset(_anims, 0, sizeof(_anims)); uint8 nextAnim = 0; assert(fileSize > 0x6D); @@ -380,8 +410,6 @@ void Sprites::loadDAT(const char *filename) { uint16 length = READ_LE_UINT16(data); data += 2; - //debug(1, "DAT body length: %i, filesize %i, current spot %i", length, fileSize, data - _dat); - if (length > 2) { assert( length < fileSize); uint8 *animstart; @@ -440,14 +468,8 @@ void Sprites::loadDAT(const char *filename) { data += 2; } - debug(1, "Room DAT file loaded. Found %i sprite and %i animation scripts.", spritesLoaded, nextAnim); - - //debug(1, "Remainder after script: %i", fileSize - (data - _dat)); assert(fileSize - (data - _dat) == 0xC); - //TODO: Read in character entry coords here - SceneExits &exits = _engine->sceneExits(); - exits.northXPos = READ_LE_UINT16(data) & 0xFFFC; data += 2; exits.northYPos = *data++ & 0xFFFE; exits.eastXPos = READ_LE_UINT16(data) & 0xFFFC; data += 2; @@ -459,9 +481,11 @@ void Sprites::loadDAT(const char *filename) { } void Sprites::freeSceneShapes() { - for (int i = 0; i < ARRAYSIZE(_sceneShapes); i++ ) + debug(9, "Sprites::freeSceneShapes()"); + for (int i = 0; i < ARRAYSIZE(_sceneShapes); i++ ) { free(_sceneShapes[i]); - + _sceneShapes[i] = 0; + } } void Sprites::loadSceneShapes() { @@ -469,11 +493,15 @@ void Sprites::loadSceneShapes() { uint8 *data = _spriteDefStart; int spriteNum, x, y, width, height; - assert(_spriteDefStart); - freeSceneShapes(); memset( _sceneShapes, 0, sizeof(_sceneShapes)); + if (_spriteDefStart == 0) + return; + + int bakPage = _screen->_curPage; + _screen->_curPage = 3; + while (READ_LE_UINT16(data) != 0xFF85) { spriteNum = READ_LE_UINT16(data); assert(spriteNum < ARRAYSIZE(_sceneShapes)); @@ -486,8 +514,31 @@ void Sprites::loadSceneShapes() { data += 2; height = READ_LE_UINT16(data); data += 2; - _sceneShapes[spriteNum] = _screen->encodeShape(x, y, width, height, 0); + _sceneShapes[spriteNum] = _screen->encodeShape(x, y, width, height, 2); + debug(9, "Sprite %i is at (%i, %i), width %i, height %i", spriteNum, x, y, width, height); } + _screen->_curPage = bakPage; +} + +void Sprites::refreshSceneAnimObject(uint8 animNum, uint8 shapeNum, uint16 x, uint16 y, bool flipX, bool unkFlag) { + debug(9, "Sprites::refreshSceneAnimObject(%i, %i, %i, %i, %i, %i", animNum, shapeNum, x, y, flipX, unkFlag); + _animObjects[animNum].refreshFlag = 1; + _animObjects[animNum].bkgdChangeFlag = 1; + + if (unkFlag) + _animObjects[animNum].flags |= 0x0200; + else + _animObjects[animNum].flags &= 0xFD00; + + if (flipX) + _animObjects[animNum].flags |= 1; + else + _animObjects[animNum].flags &= 0xFE; + + _animObjects[animNum].sceneAnimPtr = _sceneShapes[shapeNum]; + _animObjects[animNum].animFrameNumber = -1; + _animObjects[animNum].x1 = x; + _animObjects[animNum].y1 = y; } } // end of namespace Kyra diff --git a/kyra/sprites.h b/kyra/sprites.h index c64bf045cc..8f4102e7eb 100644 --- a/kyra/sprites.h +++ b/kyra/sprites.h @@ -45,6 +45,14 @@ struct Anim { uint8 *reentry; uint32 nextRun; bool play; + uint16 width; + uint16 height; + uint16 width2; + uint16 height2; + uint16 unk1; + uint16 drawY; + uint16 unk2; + uint8 *background; }; class Sprites { @@ -53,14 +61,16 @@ public: Sprites(KyraEngine *engine, OSystem *system); ~Sprites(); - void doAnims(); - void loadDAT(const char *filename); - uint8 *getSceneShape(uint8 sceneShapeID); - void drawSprites(uint8 srcPage, uint8 dstPage); + void updateSceneAnims(); + void setupSceneAnims(); + void loadDAT(const char *filename, SceneExits &exits); void loadSceneShapes(); - void enableAnim(uint8 anim) { _anims[anim].play = true; } - void disableAnim(uint8 anim) { _anims[anim].play = false; } + Anim _anims[MAX_NUM_ANIMS]; + AnimObject *_animObjects; + uint8 *_sceneShapes[50]; + + void refreshSceneAnimObject(uint8 animNum, uint8 shapeNum, uint16 x, uint16 y, bool flipX, bool unkFlag); protected: void freeSceneShapes(); @@ -69,9 +79,7 @@ protected: Resource *_res; OSystem *_system; Screen *_screen; - uint8 *_sceneShapes[50]; uint8 *_dat; - Anim _anims[MAX_NUM_ANIMS]; Common::RandomSource _rnd; uint8 _animDelay; uint8 *_spriteDefStart; |