diff options
-rw-r--r-- | engines/agos/agos.cpp | 44 | ||||
-rw-r--r-- | engines/agos/agos.h | 46 | ||||
-rw-r--r-- | engines/agos/charset.cpp | 10 | ||||
-rw-r--r-- | engines/agos/draw.cpp | 207 | ||||
-rw-r--r-- | engines/agos/event.cpp | 25 | ||||
-rw-r--r-- | engines/agos/gfx.cpp | 830 | ||||
-rw-r--r-- | engines/agos/input.cpp | 1 | ||||
-rw-r--r-- | engines/agos/saveload.cpp | 10 | ||||
-rw-r--r-- | engines/agos/script_e1.cpp | 14 | ||||
-rw-r--r-- | engines/agos/script_e2.cpp | 2 | ||||
-rw-r--r-- | engines/agos/subroutine.cpp | 2 | ||||
-rw-r--r-- | engines/agos/verb.cpp | 12 | ||||
-rw-r--r-- | engines/agos/vga.cpp | 138 | ||||
-rw-r--r-- | engines/agos/vga.h | 3 | ||||
-rw-r--r-- | engines/agos/vga_e2.cpp | 44 | ||||
-rw-r--r-- | engines/agos/vga_s1.cpp | 11 | ||||
-rw-r--r-- | engines/agos/vga_ww.cpp | 21 | ||||
-rw-r--r-- | engines/agos/window.cpp | 14 |
18 files changed, 1009 insertions, 425 deletions
diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp index 78634c81e2..b3e615bfec 100644 --- a/engines/agos/agos.cpp +++ b/engines/agos/agos.cpp @@ -199,6 +199,9 @@ AGOSEngine::AGOSEngine(OSystem *syst) _copyPartialMode = 0; _fastMode = 0; _useBackGround = 0; + + _oldDrawMethod = 0; + _backFlag = 0; _debugMode = 0; _startMainScript = false; @@ -291,6 +294,7 @@ AGOSEngine::AGOSEngine(OSystem *syst) _leftButtonDown = 0; _rightButtonDown = 0; + _clickOnly = 0; _noRightClick = false; _leftButton = 0; @@ -477,6 +481,17 @@ AGOSEngine::AGOSEngine(OSystem *syst) _backBuf = 0; _scaleBuf = 0; + _window3Flag = 0; + _window4Flag = 0; + _window6Flag = 0; + _window4BackScn = 0; + _window6BackScn = 0; + + _moveXMin = 0; + _moveYMin = 0; + _moveXMax = 0; + _moveYMax = 0; + _vc10BasePtrOld = 0; memcpy (_hebrewCharWidths, "\x5\x5\x4\x6\x5\x3\x4\x5\x6\x3\x5\x5\x4\x6\x5\x3\x4\x6\x5\x6\x6\x6\x5\x5\x5\x6\x5\x6\x6\x6\x6\x6", 32); @@ -511,6 +526,12 @@ int AGOSEngine::init() { return -1; } + // TODO: Enable for Simon the Sorcerer 1/2 when complete + if (getGameType() == GType_WW || getGameType() == GType_ELVIRA2 || + getGameType() == GType_ELVIRA1) { + _oldDrawMethod = true; + } + if (getGameId() == GID_DIMP) { _screenWidth = 496; _screenHeight = 400; @@ -562,9 +583,25 @@ int AGOSEngine::init() { // allocate buffers _backGroundBuf = (byte *)calloc(_screenWidth * _screenHeight, 1); _frontBuf = (byte *)calloc(_screenWidth * _screenHeight, 1); - _backBuf = (byte *)calloc(_screenWidth * _screenHeight, 1); - if (getGameType() == GType_FF || getGameType() == GType_PP) + + if (getGameType() == GType_FF || getGameType() == GType_PP) { _scaleBuf = (byte *)calloc(_screenWidth * _screenHeight, 1); + } + + if (!_oldDrawMethod) { + _backBuf = (byte *)calloc(_screenWidth * _screenHeight, 1); + } else { + if (getGameType() == GType_SIMON2) { + _window4BackScn = (byte *)calloc(_screenWidth * _screenHeight, 1); + } else if (getGameType() == GType_SIMON1) { + _window4BackScn = (byte *)calloc(_screenWidth * 134, 1); + } else if (getGameType() == GType_WW || getGameType() == GType_ELVIRA2) { + _window4BackScn = (byte *)calloc(224 * 127, 1); + } else if (getGameType() == GType_ELVIRA1) { + _window4BackScn = (byte *)calloc(224 * 127, 1); + _window6BackScn = (byte *)calloc(48 * 80, 1); + } + } setupGame(); @@ -851,6 +888,9 @@ AGOSEngine::~AGOSEngine() { free(_backBuf); free(_scaleBuf); + free(_window4BackScn); + free(_window6BackScn); + free(_variableArray); free(_variableArray2); diff --git a/engines/agos/agos.h b/engines/agos/agos.h index cf1bc8e7b4..af28cd2729 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -83,9 +83,9 @@ struct VgaPointersEntry { struct VgaSprite { uint16 id; - uint16 image; + int16 image; uint16 palette; - uint16 x, y; /* actually signed numbers */ + int16 x, y; uint16 flags; uint16 priority; uint16 windowNum, zoneNum; @@ -108,6 +108,17 @@ struct VgaTimerEntry { VgaTimerEntry() { memset(this, 0, sizeof(*this)); } }; +struct AnimTable { + const byte *srcPtr; + int16 x; + int16 y; + uint16 width; + uint16 height; + uint16 window; + uint16 id; + AnimTable() { memset(this, 0, sizeof(*this)); } +}; + enum SIMONGameType { GType_ELVIRA1 = 0, GType_ELVIRA2 = 1, @@ -262,6 +273,9 @@ protected: bool _fastMode; bool _useBackGround; + bool _oldDrawMethod; + bool _backFlag; + uint16 _debugMode; uint16 _language; bool _copyProtection; @@ -361,6 +375,7 @@ protected: byte _leftButtonDown; byte _leftButton, _leftButtonCount, _leftButtonOld; byte _rightButtonDown; + bool _clickOnly; bool _noRightClick; Item *_dummyItem1; @@ -450,10 +465,11 @@ protected: HitArea _hitAreas[250]; + AnimTable _screenAnim1[60]; VgaPointersEntry _vgaBufferPointers[450]; VgaSprite _vgaSprites[200]; - VgaSleepStruct _waitSyncTable[60]; VgaSleepStruct _waitEndTable[60]; + VgaSleepStruct _waitSyncTable[60]; const uint16 *_pathFindArray[100]; @@ -472,6 +488,15 @@ protected: byte _videoBuf1[32000]; uint16 _videoWindows[128]; + uint16 _window3Flag; + uint16 _window4Flag; + uint16 _window6Flag; + byte *_window4BackScn; + byte *_window6BackScn; + + uint16 _moveXMin, _moveYMin; + uint16 _moveXMax, _moveYMax; + VgaTimerEntry _vgaTimerList[205]; WindowBlock *_windowList; @@ -1025,6 +1050,10 @@ protected: void drawImage_init(int16 image, uint16 palette, uint16 x, uint16 y, uint16 flags); virtual void drawImage(VC10_state *state); + void drawBackGroundImage(VC10_state *state); + void drawVertImage(VC10_state *state); + + void setMoveRect(uint16 x, uint16 y, uint16 width, uint16 height); void horizontalScroll(VC10_state *state); void verticalScroll(VC10_state *state); @@ -1041,7 +1070,9 @@ protected: void checkScrollY(int16 y, int16 ypos); void centreScroll(); - void clearWindow(uint windowNum, uint color); + void clearVideoWindow(uint windowNum, uint color); + void clearVideoBackGround(uint windowNum, uint color); + void setPaletteSlot(uint srcOffs, uint dstOffs); void checkWaitEndTable(); @@ -1100,6 +1131,11 @@ protected: void animateSpritesDebug(); void animateSpritesByY(); + void dirtyClips(); + void dirtyBackGround(); + void restoreBackGround(); + void saveBackGround(VgaSprite *vsp); + void clearSurfaces(uint num_lines); void updateScreen(); @@ -1416,6 +1452,8 @@ protected: const OpcodeEntrySimon1 *_opcodesSimon1; virtual void drawImage(VC10_state *state); + void drawMaskedImage(VC10_state *state); + void draw32ColorImage(VC10_state *state); virtual void drawIcon(WindowBlock *window, uint icon, uint x, uint y); diff --git a/engines/agos/charset.cpp b/engines/agos/charset.cpp index 874108e872..2dbf8277af 100644 --- a/engines/agos/charset.cpp +++ b/engines/agos/charset.cpp @@ -703,12 +703,16 @@ void AGOSEngine_Feeble::windowNewLine(WindowBlock *window) { } void AGOSEngine::windowNewLine(WindowBlock *window) { - if (window->textRow != window->height) - window->textRow++; - window->textColumn = 0; window->textColumnOffset = 0; window->textLength = 0; + + if (window->textRow == window->height) { + // TODO + debug(0, "Window Scroll"); + } else { + window->textRow++; + } } #ifdef PALMOS_68K diff --git a/engines/agos/draw.cpp b/engines/agos/draw.cpp index 701a6af5f2..c2183bffc2 100644 --- a/engines/agos/draw.cpp +++ b/engines/agos/draw.cpp @@ -69,8 +69,15 @@ void AGOSEngine::animateSprites() { return; } - vsp = _vgaSprites; + if (_oldDrawMethod) { + if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { + dirtyClips(); + } + restoreBackGround(); + } + + vsp = _vgaSprites; while (vsp->id != 0) { vsp->windowNum &= 0x7FFF; @@ -82,17 +89,119 @@ void AGOSEngine::animateSprites() { _vgaCurSpriteId = vsp->id; _vgaCurSpritePriority = vsp->priority; - drawImage_init(vsp->image, vsp->palette, vsp->x, vsp->y, vsp->flags); + if (_oldDrawMethod) { + saveBackGround(vsp); + } + drawImage_init(vsp->image, vsp->palette, vsp->x, vsp->y, vsp->flags); vsp++; } if (_drawImagesDebug) memset(_backBuf, 0, _screenWidth * _screenHeight); + if (_window6Flag == 1) + _window6Flag++; + + if (_window4Flag == 1) + _window4Flag++; + _updateScreen = true; } +void AGOSEngine::dirtyClips() { + // TODO +} + +void AGOSEngine::restoreBackGround() { + AnimTable *animTable; + uint images = 0; + + animTable = _screenAnim1; + while (animTable->srcPtr) { + animTable++; + images++; + } + + while (images--) { + animTable--; + + if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) && + !(animTable->window & 0x8000)) { + //continue; + } + + animTable->window &= 0x7FFF; + _windowNum = animTable->window; + + VC10_state state; + state.srcPtr = animTable->srcPtr; + state.height = state.draw_height = animTable->height; + state.width = state.draw_width = animTable->width; + state.y = animTable->y; + state.x = animTable->x; + state.palette = 0; + state.paletteMod = 0; + state.flags = kDFNonTrans; + + _backFlag = 1; + drawImage(&state); + + //if (getGameType() != GType_SIMON1 && getGameType() != GType_SIMON2) { + animTable->srcPtr = 0; + //} + } + _backFlag = 0; + + if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { + AnimTable *animTableTmp; + + animTable = animTableTmp = _screenAnim1; + while (animTable->srcPtr != 0) { + if (!(animTable->window & 8000)) { + memcpy(animTableTmp, animTable, sizeof(AnimTable)); + animTableTmp++; + } + animTable++; + } + animTableTmp->id = 0; + } +} + +void AGOSEngine::saveBackGround(VgaSprite *vsp) { + if ((vsp->flags & 4) || !vsp->image) + return; + + AnimTable *animTable = _screenAnim1; + + while (animTable->srcPtr) + animTable++; + + const byte *ptr = _curVgaFile2 + vsp->image * 8; + int16 x = vsp->x - _scrollX; + int16 y = vsp->y - _scrollY; + + if (_window3Flag == 1) { + animTable->srcPtr = (const byte *)_window4BackScn; + } else { + uint xoffs = (_videoWindows[vsp->windowNum * 4 + 0] * 2 + x) * 8; + uint yoffs = (_videoWindows[vsp->windowNum * 4 + 1] + y); + animTable->srcPtr = getBackGround() + xoffs + yoffs * _screenWidth; + } + + animTable->x = x; + animTable->y = y; + + animTable->width = READ_BE_UINT16(ptr + 6) / 16; + if (vsp->flags & 40) { + animTable->width++; + } + + animTable->height = ptr[5]; + animTable->window = vsp->windowNum; + animTable->id = vsp->id; +} + void AGOSEngine::animateSpritesDebug() { VgaSprite *vsp; VgaPointersEntry *vpe; @@ -289,10 +398,16 @@ void AGOSEngine::displayBoxStars() { } void AGOSEngine::scrollScreen() { - byte *dst = getFrontBuf(); + byte *dst; const byte *src; uint x, y; + if (!_oldDrawMethod) { + dst = getFrontBuf(); + } else { + dst = getBackGround(); + } + if (_scrollXMax == 0) { uint screenSize = 8 * _screenWidth; if (_scrollFlag < 0) { @@ -340,8 +455,16 @@ void AGOSEngine::scrollScreen() { _scrollX += _scrollFlag; vcWriteVar(251, _scrollX); - memcpy(_backBuf, _frontBuf, _screenWidth * _screenHeight); - memcpy(_backGroundBuf, _backBuf, _scrollHeight * _screenWidth); + if (!_oldDrawMethod) { + memcpy(_backBuf, _frontBuf, _screenWidth * _screenHeight); + memcpy(_backGroundBuf, _backBuf, _scrollHeight * _screenWidth); + } else { + memcpy(_window4BackScn, _backGroundBuf, _scrollHeight * _screenWidth); + } + + setMoveRect(0, 0, 320, _scrollHeight); + + _window4Flag = 1; } _scrollFlag = 0; @@ -390,6 +513,20 @@ void AGOSEngine::fillBackGroundFromBack(uint lines) { memcpy(_backGroundBuf, _backBuf, lines * _screenWidth); } +void AGOSEngine::setMoveRect(uint16 x, uint16 y, uint16 width, uint16 height) { + if (x < _moveXMin) + _moveXMin = x; + + if (y < _moveYMin) + _moveYMin = y; + + if (width > _moveXMax) + _moveXMax = width; + + if (height > _moveYMax) + _moveYMax = height; +} + void AGOSEngine::updateScreen() { if (_fastFadeInFlag == 0 && _paletteFlag == 1) { _paletteFlag = 0; @@ -399,11 +536,63 @@ void AGOSEngine::updateScreen() { } } - _system->copyRectToScreen(getBackBuf(), _screenWidth, 0, 0, _screenWidth, _screenHeight); - _system->updateScreen(); + if (_oldDrawMethod) { + if (_window4Flag == 2) { + _window4Flag = 0; + + uint16 srcWidth, width, height; + byte *dst = getFrontBuf(); + + const byte *src = _window4BackScn; + if (_window3Flag == 1) { + src = getBackGround(); + } - if (getGameId() != GID_DIMP) - memcpy(getBackBuf(), getFrontBuf(), _screenWidth * _screenHeight); + dst += (_moveYMin + _videoWindows[17]) * _screenWidth; + dst += (_videoWindows[16] * 16) + _moveXMin; + + src += (_videoWindows[18] * 16 * _moveYMin); + src += _moveXMin; + + srcWidth = _videoWindows[18] * 16; + + width = _moveXMax - _moveXMin; + height = _moveYMax - _moveYMin; + + for (; height > 0; height--) { + memcpy(dst, src, width); + dst += _screenWidth; + src += srcWidth; + } + + _moveXMin = 0xFFFF; + _moveYMin = 0xFFFF; + _moveXMax = 0; + _moveYMax = 0; + } + + if (_window6Flag == 2) { + _window6Flag = 0; + + byte *src = _window6BackScn; + byte *dst = getFrontBuf() + 16320; + for (int i = 0; i < 80; i++) { + memcpy(dst, src, 48); + dst += _screenWidth; + src += 48; + } + } + + _system->copyRectToScreen(getFrontBuf(), _screenWidth, 0, 0, _screenWidth, _screenHeight); + _system->updateScreen(); + } else { + _system->copyRectToScreen(getBackBuf(), _screenWidth, 0, 0, _screenWidth, _screenHeight); + _system->updateScreen(); + + if (getGameId() != GID_DIMP) + memcpy(getBackBuf(), getFrontBuf(), _screenWidth * _screenHeight); + + } if (getGameType() == GType_FF && _scrollFlag) { scrollScreen(); diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp index 93ab997e64..579837833d 100644 --- a/engines/agos/event.cpp +++ b/engines/agos/event.cpp @@ -123,6 +123,7 @@ void AGOSEngine::killAllTimers() { next = cur->next; delTimeEvent(cur); } + _clickOnly = 0; } bool AGOSEngine::kickoffTimeEvents() { @@ -164,32 +165,30 @@ bool AGOSEngine::isVgaQueueEmpty() { } void AGOSEngine::haltAnimation() { - VgaTimerEntry *vte = _vgaTimerList; + if (_lockWord & 0x10) + return; _lockWord |= 0x10; - while (vte->delay) { - vte->delay += 10; + if (_updateScreen != false) { + updateScreen(); + _updateScreen = false; } } void AGOSEngine::restartAnimation() { + if (!(_lockWord & 0x10)) + return; + + updateScreen(); _lockWord &= ~0x10; + + // Check picture queue } void AGOSEngine::addVgaEvent(uint16 num, const byte *code_ptr, uint16 cur_sprite, uint16 curZoneNum) { VgaTimerEntry *vte; - // When Simon talks to the Golum about stew in French version of - // Simon the Sorcerer 1 the code_ptr is at wrong location for - // sprite 200. This was a bug in the original game, which - // caused several glitches in this scene. - // We work around the problem by correcting the code_ptr for sprite - // 200 in this scene, if it is wrong. - if (getGameType() == GType_SIMON1 && _language == Common::FR_FRA && - (code_ptr - _vgaBufferPointers[curZoneNum].vgaFile1 == 4) && (cur_sprite == 200) && (curZoneNum == 2)) - code_ptr += 0x66; - _lockWord |= 1; for (vte = _vgaTimerList; vte->delay; vte++) { diff --git a/engines/agos/gfx.cpp b/engines/agos/gfx.cpp index 5f7ec849f8..607c07d2b3 100644 --- a/engines/agos/gfx.cpp +++ b/engines/agos/gfx.cpp @@ -224,6 +224,70 @@ bool AGOSEngine::drawImage_clip(VC10_state *state) { return 1; } +void AGOSEngine_Feeble::scaleClip(int16 h, int16 w, int16 y, int16 x, int16 scrollY) { + Common::Rect srcRect, dstRect; + float factor, xscale; + + srcRect.left = 0; + srcRect.top = 0; + srcRect.right = w; + srcRect.bottom = h; + + if (scrollY > _baseY) + factor = 1 + ((scrollY - _baseY) * _scale); + else + factor = 1 - ((_baseY - scrollY) * _scale); + + xscale = ((w * factor) / 2); + + dstRect.left = (int16)(x - xscale); + if (dstRect.left > _screenWidth - 1) + return; + dstRect.top = (int16)(y - (h * factor)); + if (dstRect.top > _screenHeight - 1) + return; + + dstRect.right = (int16)(x + xscale); + dstRect.bottom = y; + + _feebleRect = dstRect; + + _variableArray[20] = _feebleRect.top; + _variableArray[21] = _feebleRect.left; + _variableArray[22] = _feebleRect.bottom; + _variableArray[23] = _feebleRect.right; + + debug(5, "Left %d Right %d Top %d Bottom %d", dstRect.left, dstRect.right, dstRect.top, dstRect.bottom); + + // Unlike normal rectangles in ScummVM, it seems that in the case of + // the destination rectangle the bottom and right coordinates are + // considered to be inside the rectangle. For the source rectangle, + // I believe that they are not. + + int scaledW = dstRect.width() + 1; + int scaledH = dstRect.height() + 1; + + byte *src = getScaleBuf(); + byte *dst = getBackBuf(); + + dst += _dxSurfacePitch * dstRect.top + dstRect.left; + + for (int dstY = 0; dstY < scaledH; dstY++) { + if (dstRect.top + dstY >= 0 && dstRect.top + dstY < _screenHeight) { + int srcY = (dstY * h) / scaledH; + byte *srcPtr = src + _dxSurfacePitch * srcY; + byte *dstPtr = dst + _dxSurfacePitch * dstY; + for (int dstX = 0; dstX < scaledW; dstX++) { + if (dstRect.left + dstX >= 0 && dstRect.left + dstX < _screenWidth) { + int srcX = (dstX * w) / scaledW; + if (srcPtr[srcX]) + dstPtr[dstX] = srcPtr[srcX]; + } + } + } + } +} + void AGOSEngine_Feeble::drawImage(VC10_state *state) { if (state->flags & kDFCompressed) { if (state->flags & kDFScaled) { @@ -387,304 +451,285 @@ void AGOSEngine_Feeble::drawImage(VC10_state *state) { } } -void AGOSEngine_Simon1::drawImage(VC10_state *state) { - const uint16 *vlut = &_videoWindows[_windowNum * 4]; - - if (drawImage_clip(state) == 0) - return; +void AGOSEngine_Simon1::drawMaskedImage(VC10_state *state) { + if (getFeatures() & GF_32COLOR) { + const byte *mask = state->srcPtr + (state->width * state->y_skip * 16) + (state->x_skip * 8); + byte *src = state->surf2_addr; + byte *dst = state->surf_addr; - if (getFeatures() & GF_32COLOR) - state->palette = 0xC0; + state->draw_width *= 2; - uint xoffs, yoffs; - if (getGameType() == GType_SIMON1 && (_subroutine == 2923 || _subroutine == 2926)) { - // Allow one section of Simon the Sorcerer 1 introduction to be displayed - // in lower half of screen - xoffs = state->x * 8; - yoffs = state->y; - } else { - xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; - yoffs = (vlut[1] - _videoWindows[17] + state->y); - } + uint h = state->draw_height; + do { + for (uint i = 0; i != state->draw_width; i++) { + if (getGameType() == GType_SIMON1 && getBitFlag(88)) { + /* transparency */ + if (mask[i] && (dst[i] & 16)) + dst[i] = src[i]; + } else { + /* no transparency */ + if (mask[i]) + dst[i] = src[i]; + } + } + dst += state->surf_pitch; + src += state->surf2_pitch; + mask += state->width * 16; + } while (--h); + } else if (state->flags & kDFCompressed) { + byte *mask, *src, *dst; + byte h; + uint w; - state->surf2_addr += xoffs + yoffs * state->surf_pitch; - state->surf_addr += xoffs + yoffs * state->surf2_pitch; + state->x_skip *= 4; + state->dl = state->width; + state->dh = state->height; - if (state->flags & kDFMasked) { - if (getFeatures() & GF_32COLOR) { - const byte *mask = state->srcPtr + (state->width * state->y_skip * 16) + (state->x_skip * 8); - byte *src = state->surf2_addr; - byte *dst = state->surf_addr; + vc10_skip_cols(state); - state->draw_width *= 2; + w = 0; + do { + mask = vc10_depackColumn(state); /* esi */ + src = state->surf2_addr + w * 2; /* ebx */ + dst = state->surf_addr + w * 2; /* edi */ - uint h = state->draw_height; + h = state->draw_height; do { - for (uint i = 0; i != state->draw_width; i++) { - if (getGameType() == GType_SIMON1 && getBitFlag(88)) { - /* transparency */ - if (mask[i] && (dst[i] & 16)) - dst[i] = src[i]; - } else { - /* no transparency */ - if (mask[i]) - dst[i] = src[i]; - } + if (getGameType() == GType_SIMON1 && getBitFlag(88)) { + /* transparency */ + if ((mask[0] & 0xF0) && (dst[0] & 0x0F0) == 0x20) + dst[0] = src[0]; + if ((mask[0] & 0x0F) && (dst[1] & 0x0F0) == 0x20) + dst[1] = src[1]; + } else { + /* no transparency */ + if (mask[0] & 0xF0) + dst[0] = src[0]; + if (mask[0] & 0x0F) + dst[1] = src[1]; } + mask++; dst += state->surf_pitch; src += state->surf2_pitch; - mask += state->width * 16; } while (--h); - } else if (state->flags & kDFCompressed) { - byte *mask, *src, *dst; - byte h; - uint w; - - state->x_skip *= 4; - state->dl = state->width; - state->dh = state->height; - - vc10_skip_cols(state); - - w = 0; - do { - mask = vc10_depackColumn(state); /* esi */ - src = state->surf2_addr + w * 2; /* ebx */ - dst = state->surf_addr + w * 2; /* edi */ - - h = state->draw_height; - do { - if (getGameType() == GType_SIMON1 && getBitFlag(88)) { - /* transparency */ - if ((mask[0] & 0xF0) && (dst[0] & 0x0F0) == 0x20) - dst[0] = src[0]; - if ((mask[0] & 0x0F) && (dst[1] & 0x0F0) == 0x20) - dst[1] = src[1]; - } else { - /* no transparency */ - if (mask[0] & 0xF0) - dst[0] = src[0]; - if (mask[0] & 0x0F) - dst[1] = src[1]; - } - mask++; - dst += state->surf_pitch; - src += state->surf2_pitch; - } while (--h); - } while (++w != state->draw_width); - } else { - const byte *src, *mask; - byte *dst; - uint count; + } while (++w != state->draw_width); + } else { + const byte *src, *mask; + byte *dst; + uint count; - mask = state->srcPtr + (state->width * state->y_skip) * 8; - src = state->surf2_addr; - dst = state->surf_addr; + mask = state->srcPtr + (state->width * state->y_skip) * 8; + src = state->surf2_addr; + dst = state->surf_addr; - state->x_skip *= 4; + state->x_skip *= 4; - do { - for (count = 0; count != state->draw_width; count++) { - if (getGameType() == GType_SIMON1 && getBitFlag(88)) { - /* transparency */ - if (mask[count + state->x_skip] & 0xF0) - if ((dst[count * 2] & 0xF0) == 0x20) - dst[count * 2] = src[count * 2]; - if (mask[count + state->x_skip] & 0x0F) - if ((dst[count * 2 + 1] & 0x0F) == 0x20) - dst[count * 2 + 1] = src[count * 2 + 1]; - } else { - /* no transparency */ - if (mask[count + state->x_skip] & 0xF0) + do { + for (count = 0; count != state->draw_width; count++) { + if (getGameType() == GType_SIMON1 && getBitFlag(88)) { + /* transparency */ + if (mask[count + state->x_skip] & 0xF0) + if ((dst[count * 2] & 0xF0) == 0x20) dst[count * 2] = src[count * 2]; - if (mask[count + state->x_skip] & 0x0F) + if (mask[count + state->x_skip] & 0x0F) + if ((dst[count * 2 + 1] & 0x0F) == 0x20) dst[count * 2 + 1] = src[count * 2 + 1]; - } + } else { + /* no transparency */ + if (mask[count + state->x_skip] & 0xF0) + dst[count * 2] = src[count * 2]; + if (mask[count + state->x_skip] & 0x0F) + dst[count * 2 + 1] = src[count * 2 + 1]; } - src += _screenWidth; - dst += _screenWidth; - mask += state->width * 8; - } while (--state->draw_height); - } - } else if (((_lockWord & 0x20) && state->palette == 0) || state->palette == 0xC0) { - const byte *src; - byte *dst; - uint h, i; + } + src += _screenWidth; + dst += _screenWidth; + mask += state->width * 8; + } while (--state->draw_height); + } +} + +void AGOSEngine_Simon1::draw32ColorImage(VC10_state *state) { + const byte *src; + byte *dst; + uint h, i; + + if (state->flags & kDFCompressed) { + byte *dstPtr = state->surf_addr; + src = state->srcPtr; + /* AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE + * aaaaabbb bbcccccd ddddeeee efffffgg ggghhhhh + */ - if (state->flags & kDFCompressed) { - byte *dstPtr = state->surf_addr; - src = state->srcPtr; - /* AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE - * aaaaabbb bbcccccd ddddeeee efffffgg ggghhhhh - */ + do { + uint count = state->draw_width / 4; + dst = dstPtr; do { - uint count = state->draw_width / 4; + uint32 bits = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | (src[3]); + byte color; - dst = dstPtr; - do { - uint32 bits = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | (src[3]); - byte color; + color = (byte)((bits >> (32 - 5)) & 31); + if ((state->flags & kDFNonTrans) || color) + dst[0] = color; + color = (byte)((bits >> (32 - 10)) & 31); + if ((state->flags & kDFNonTrans) || color) + dst[1] = color; + color = (byte)((bits >> (32 - 15)) & 31); + if ((state->flags & kDFNonTrans) || color) + dst[2] = color; + color = (byte)((bits >> (32 - 20)) & 31); + if ((state->flags & kDFNonTrans) || color) + dst[3] = color; + color = (byte)((bits >> (32 - 25)) & 31); + if ((state->flags & kDFNonTrans) || color) + dst[4] = color; + color = (byte)((bits >> (32 - 30)) & 31); + if ((state->flags & kDFNonTrans) || color) + dst[5] = color; - color = (byte)((bits >> (32 - 5)) & 31); - if ((state->flags & kDFNonTrans) || color) - dst[0] = color; - color = (byte)((bits >> (32 - 10)) & 31); - if ((state->flags & kDFNonTrans) || color) - dst[1] = color; - color = (byte)((bits >> (32 - 15)) & 31); - if ((state->flags & kDFNonTrans) || color) - dst[2] = color; - color = (byte)((bits >> (32 - 20)) & 31); - if ((state->flags & kDFNonTrans) || color) - dst[3] = color; - color = (byte)((bits >> (32 - 25)) & 31); - if ((state->flags & kDFNonTrans) || color) - dst[4] = color; - color = (byte)((bits >> (32 - 30)) & 31); - if ((state->flags & kDFNonTrans) || color) - dst[5] = color; - - bits = (bits << 8) | src[4]; - - color = (byte)((bits >> (40 - 35)) & 31); - if ((state->flags & kDFNonTrans) || color) - dst[6] = color; - color = (byte)((bits) & 31); - if ((state->flags & kDFNonTrans) || color) - dst[7] = color; - - dst += 8; - src += 5; - } while (--count); - dstPtr += _screenWidth; - } while (--state->draw_height); - } else { - src = state->srcPtr + (state->width * state->y_skip * 16) + (state->x_skip * 8); - dst = state->surf_addr; + bits = (bits << 8) | src[4]; - state->draw_width *= 2; + color = (byte)((bits >> (40 - 35)) & 31); + if ((state->flags & kDFNonTrans) || color) + dst[6] = color; + color = (byte)((bits) & 31); + if ((state->flags & kDFNonTrans) || color) + dst[7] = color; - h = state->draw_height; - do { - for (i = 0; i != state->draw_width; i++) - if ((state->flags & kDFNonTrans) || src[i]) - dst[i] = src[i]; - dst += _screenWidth; - src += state->width * 16; - } while (--h); - } + dst += 8; + src += 5; + } while (--count); + dstPtr += _screenWidth; + } while (--state->draw_height); } else { - if (getGameType() == GType_SIMON2 && state->flags & kDFUseFrontBuf && getBitFlag(171)) { - state->surf_addr = state->surf2_addr; - state->surf_pitch = state->surf2_pitch; + src = state->srcPtr + (state->width * state->y_skip * 16) + (state->x_skip * 8); + dst = state->surf_addr; + + state->draw_width *= 2; + + h = state->draw_height; + do { + for (i = 0; i != state->draw_width; i++) + if ((state->flags & kDFNonTrans) || src[i]) + dst[i] = src[i]; + dst += _screenWidth; + src += state->width * 16; + } while (--h); + } +} + +void AGOSEngine_Simon1::drawImage(VC10_state *state) { + const uint16 *vlut = &_videoWindows[_windowNum * 4]; + + if (drawImage_clip(state) == 0) + return; + + if (getFeatures() & GF_32COLOR) + state->palette = 0xC0; + + uint16 xoffs, yoffs; + if (!_oldDrawMethod) { + if (getGameType() == GType_SIMON1 && (_subroutine == 2923 || _subroutine == 2926)) { + // Allow one section of Simon the Sorcerer 1 introduction to be displayed + // in lower half of screen + xoffs = state->x * 8; + yoffs = state->y; + } else { + xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; + yoffs = (vlut[1] - _videoWindows[17] + state->y); } + } else if (getGameType() == GType_SIMON2) { + state->surf2_addr = getBackGround(); + state->surf2_pitch = _screenWidth; - if (state->flags & kDFCompressed) { - uint w, h; - byte *src, *dst, *dstPtr; + state->surf_addr = _window4BackScn; + state->surf_pitch = _screenWidth; - state->x_skip *= 4; /* reached */ + xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; + yoffs = (vlut[1] - _videoWindows[17] + state->y); - state->dl = state->width; - state->dh = state->height; + uint xmax = (xoffs + state->draw_width * 2); + uint ymax = (yoffs + state->draw_height); + setMoveRect(xoffs, yoffs, xmax, ymax); - vc10_skip_cols(state); + _window4Flag = 1; + } else if (getGameType() == GType_SIMON1) { + if (_windowNum == 3 || _windowNum == 4 || _windowNum >= 10) { + if (_windowNum == 3) { + state->surf2_addr = getBackGround(); + state->surf2_pitch = _screenWidth; - dstPtr = state->surf_addr; - if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ - dstPtr += vcReadVar(252); + state->surf_addr = getBackGround(); + state->surf_pitch = _screenWidth; + } else { + state->surf2_addr = getBackGround(); + state->surf2_pitch = _screenWidth; + + state->surf_addr = _window4BackScn; + state->surf_pitch = _screenWidth; } - w = 0; - do { - byte color; - src = vc10_depackColumn(state); - dst = dstPtr; + xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; + yoffs = (vlut[1] - _videoWindows[17] + state->y); - h = 0; - do { - color = (*src / 16); - if ((state->flags & kDFNonTrans) || color != 0) - dst[0] = color | state->palette; - color = (*src & 15); - if ((state->flags & kDFNonTrans) || color != 0) - dst[1] = color | state->palette; - dst += _screenWidth; - src++; - } while (++h != state->draw_height); - dstPtr += 2; - } while (++w != state->draw_width); + uint xmax = (xoffs + state->draw_width * 2); + uint ymax = (yoffs + state->draw_height); + setMoveRect(xoffs, yoffs, xmax, ymax); + + _window4Flag = 1; } else { - const byte *src; - byte *dst; - uint count; + state->surf2_addr = getBackGround(); + state->surf2_pitch = _screenWidth; - src = state->srcPtr + (state->width * state->y_skip) * 8; - dst = state->surf_addr; - state->x_skip *= 4; + state->surf_addr = getFrontBuf(); + state->surf_pitch = _screenWidth; - do { - for (count = 0; count != state->draw_width; count++) { - byte color; - color = (src[count + state->x_skip] / 16); - if ((state->flags & kDFNonTrans) || color) - dst[count * 2] = color | state->palette; - color = (src[count + state->x_skip] & 15); - if ((state->flags & kDFNonTrans) || color) - dst[count * 2 + 1] = color | state->palette; - } - dst += _screenWidth; - src += state->width * 8; - } while (--state->draw_height); + xoffs = (vlut[0] * 2 + state->x) * 8; + yoffs = vlut[1] + state->y; } } + + state->surf_addr += xoffs + yoffs * state->surf_pitch; + state->surf2_addr += xoffs + yoffs * state->surf2_pitch; + + if (_backFlag == 1) { + drawBackGroundImage(state); + } else if (state->flags & kDFMasked) { + drawMaskedImage(state); + } else if (((_lockWord & 0x20) && state->palette == 0) || state->palette == 0xC0) { + draw32ColorImage(state); + } else { + drawVertImage(state); + } } -void AGOSEngine::drawImage(VC10_state *state) { - const uint16 *vlut = &_videoWindows[_windowNum * 4]; +void AGOSEngine::drawBackGroundImage(VC10_state *state) { + const byte *src; + byte *dst; + uint h, i; - if (drawImage_clip(state) == 0) - return; + src = state->srcPtr + (_screenWidth * state->y_skip) + (state->x_skip * 8); + dst = state->surf_addr; - uint xoffs = 0, yoffs = 0; - if (getGameType() == GType_ELVIRA1) { - //if (_windowNum != 2 && _windowNum != 3 && _windowNum != 6) { - // xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; - // yoffs = (vlut[1] - _videoWindows[17] + state->y); - //} else { - xoffs = (vlut[0] * 2 + state->x) * 8; - yoffs = vlut[1] + state->y; - //} - } else if (getGameType() == GType_ELVIRA2) { - //if (_windowNum == 4 || _windowNum >= 10) { - // xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; - // yoffs = (vlut[1] - _videoWindows[17] + state->y); - //} else { - xoffs = (vlut[0] * 2 + state->x) * 8; - yoffs = vlut[1] + state->y; - //} - } else if (getGameType() == GType_WW) { - //if (_windowNum == 4 || (_windowNum >= 10 && _windowNum < 28)) { - // xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; - // yoffs = (vlut[1] - _videoWindows[17] + state->y); - //} else { - xoffs = (vlut[0] * 2 + state->x) * 8; - yoffs = vlut[1] + state->y; - //} - } + state->draw_width *= 2; - state->surf_addr += xoffs + yoffs * state->surf_pitch; - state->surf2_addr += xoffs + yoffs * state->surf2_pitch; + h = state->draw_height; + do { + for (i = 0; i != state->draw_width; i++) + dst[i] = src[i] + state->paletteMod; + dst += state->surf_pitch; + src += _screenWidth; + } while (--h); +} - if (state->flags & kDFUseFrontBuf) { +void AGOSEngine::drawVertImage(VC10_state *state) { + if (getGameType() == GType_SIMON2 && (state->flags & kDFUseFrontBuf) && getBitFlag(171) && + !_oldDrawMethod) { state->surf_addr = state->surf2_addr; state->surf_pitch = state->surf2_pitch; } - if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) - state->palette = state->surf_addr[0] & 0xF0; - if (state->flags & kDFCompressed) { uint w, h; byte *src, *dst, *dstPtr; @@ -697,6 +742,9 @@ void AGOSEngine::drawImage(VC10_state *state) { vc10_skip_cols(state); dstPtr = state->surf_addr; + if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */ + dstPtr += vcReadVar(252); + } w = 0; do { byte color; @@ -712,7 +760,7 @@ void AGOSEngine::drawImage(VC10_state *state) { color = (*src & 15); if ((state->flags & kDFNonTrans) || color != 0) dst[1] = color | state->palette; - dst += _screenWidth; + dst += state->surf_pitch; src++; } while (++h != state->draw_height); dstPtr += 2; @@ -726,26 +774,112 @@ void AGOSEngine::drawImage(VC10_state *state) { dst = state->surf_addr; state->x_skip *= 4; - uint8 extraPal = 0; - if (getGameType() == GType_ELVIRA1 && (state->flags & kDFNonTrans) && yoffs > 133) - extraPal = 16; - do { for (count = 0; count != state->draw_width; count++) { byte color; - color = (src[count + state->x_skip] / 16) + extraPal; + color = (src[count + state->x_skip] / 16) + state->paletteMod; if ((state->flags & kDFNonTrans) || color) dst[count * 2] = color | state->palette; - color = (src[count + state->x_skip] & 15) + extraPal; + color = (src[count + state->x_skip] & 15) + state->paletteMod; if ((state->flags & kDFNonTrans) || color) dst[count * 2 + 1] = color | state->palette; } - dst += _screenWidth; + dst += state->surf_pitch; src += state->width * 8; } while (--state->draw_height); } } +void AGOSEngine::drawImage(VC10_state *state) { + const uint16 *vlut = &_videoWindows[_windowNum * 4]; + + if (drawImage_clip(state) == 0) + return; + + uint16 xoffs, yoffs; + if (getGameType() == GType_WW) { + if (_windowNum == 4 || (_windowNum >= 10 && _windowNum <= 27)) { + state->surf_addr = _window4BackScn; + state->surf_pitch = _videoWindows[18] * 16; + + xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; + yoffs = (vlut[1] - _videoWindows[17] + state->y); + + uint xmax = (xoffs + state->draw_width * 2); + uint ymax = (yoffs + state->draw_height); + setMoveRect(xoffs, yoffs, xmax, ymax); + + _window4Flag = 1; + } else { + state->surf_addr = getFrontBuf(); + state->surf_pitch = _screenWidth; + + xoffs = (vlut[0] * 2 + state->x) * 8; + yoffs = vlut[1] + state->y; + } + } else if (getGameType() == GType_ELVIRA2) { + if (_windowNum == 4 || _windowNum >= 10) { + state->surf_addr = _window4BackScn; + state->surf_pitch = _videoWindows[18] * 16; + + xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; + yoffs = (vlut[1] - _videoWindows[17] + state->y); + + uint xmax = (xoffs + state->draw_width * 2); + uint ymax = (yoffs + state->draw_height); + setMoveRect(xoffs, yoffs, xmax, ymax); + + _window4Flag = 1; + } else { + state->surf_addr = getFrontBuf(); + state->surf_pitch = _screenWidth; + + xoffs = (vlut[0] * 2 + state->x) * 8; + yoffs = vlut[1] + state->y; + } + } else if (getGameType() == GType_ELVIRA1) { + if (_windowNum == 6) { + state->surf_addr = _window6BackScn; + state->surf_pitch = 48; + + xoffs = state->x * 8; + yoffs = state->y; + } else if (_windowNum == 2 || _windowNum == 3) { + state->surf_addr = getFrontBuf(); + state->surf_pitch = _screenWidth; + + xoffs = (vlut[0] * 2 + state->x) * 8; + yoffs = vlut[1] + state->y; + + } else { + state->surf_addr = _window4BackScn; + state->surf_pitch = _videoWindows[18] * 16; + + xoffs = ((vlut[0] - _videoWindows[16]) * 2 + state->x) * 8; + yoffs = (vlut[1] - _videoWindows[17] + state->y); + + uint xmax = (xoffs + state->draw_width * 2); + uint ymax = (yoffs + state->draw_height); + setMoveRect(xoffs, yoffs, xmax, ymax); + + _window4Flag = 1; + } + } + + state->surf_addr += xoffs + yoffs * state->surf_pitch; + + if (getGameType() == GType_ELVIRA1 && (state->flags & kDFNonTrans) && yoffs > 133) + state->paletteMod = 16; + + if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) + state->palette = state->surf_addr[0] & 0xF0; + + if (_backFlag == 1) { + drawBackGroundImage(state); + } else { + drawVertImage(state); + } +} void AGOSEngine::horizontalScroll(VC10_state *state) { const byte *src; @@ -766,7 +900,11 @@ void AGOSEngine::horizontalScroll(VC10_state *state) { vcWriteVar(251, _scrollX); - dst = getBackBuf(); + if (!_oldDrawMethod) { + dst = getBackBuf(); + } else { + dst = _window4BackScn; + } if (getGameType() == GType_FF) src = state->srcPtr + _scrollX / 2; @@ -778,6 +916,10 @@ void AGOSEngine::horizontalScroll(VC10_state *state) { dst += 8; src += 4; } + + setMoveRect(0, 0, 320, _scrollHeight); + + _window4Flag = 1; } void AGOSEngine::verticalScroll(VC10_state *state) { @@ -806,70 +948,6 @@ void AGOSEngine::verticalScroll(VC10_state *state) { } } -void AGOSEngine_Feeble::scaleClip(int16 h, int16 w, int16 y, int16 x, int16 scrollY) { - Common::Rect srcRect, dstRect; - float factor, xscale; - - srcRect.left = 0; - srcRect.top = 0; - srcRect.right = w; - srcRect.bottom = h; - - if (scrollY > _baseY) - factor = 1 + ((scrollY - _baseY) * _scale); - else - factor = 1 - ((_baseY - scrollY) * _scale); - - xscale = ((w * factor) / 2); - - dstRect.left = (int16)(x - xscale); - if (dstRect.left > _screenWidth - 1) - return; - dstRect.top = (int16)(y - (h * factor)); - if (dstRect.top > _screenHeight - 1) - return; - - dstRect.right = (int16)(x + xscale); - dstRect.bottom = y; - - _feebleRect = dstRect; - - _variableArray[20] = _feebleRect.top; - _variableArray[21] = _feebleRect.left; - _variableArray[22] = _feebleRect.bottom; - _variableArray[23] = _feebleRect.right; - - debug(5, "Left %d Right %d Top %d Bottom %d", dstRect.left, dstRect.right, dstRect.top, dstRect.bottom); - - // Unlike normal rectangles in ScummVM, it seems that in the case of - // the destination rectangle the bottom and right coordinates are - // considered to be inside the rectangle. For the source rectangle, - // I believe that they are not. - - int scaledW = dstRect.width() + 1; - int scaledH = dstRect.height() + 1; - - byte *src = getScaleBuf(); - byte *dst = getBackBuf(); - - dst += _dxSurfacePitch * dstRect.top + dstRect.left; - - for (int dstY = 0; dstY < scaledH; dstY++) { - if (dstRect.top + dstY >= 0 && dstRect.top + dstY < _screenHeight) { - int srcY = (dstY * h) / scaledH; - byte *srcPtr = src + _dxSurfacePitch * srcY; - byte *dstPtr = dst + _dxSurfacePitch * dstY; - for (int dstX = 0; dstX < scaledW; dstX++) { - if (dstRect.left + dstX >= 0 && dstRect.left + dstX < _screenWidth) { - int srcX = (dstX * w) / scaledW; - if (srcPtr[srcX]) - dstPtr[dstX] = srcPtr[srcX]; - } - } - } - } -} - void AGOSEngine::paletteFadeOut(byte *palPtr, uint num, uint size) { byte *p = palPtr; @@ -1074,6 +1152,9 @@ void AGOSEngine::setImage(uint16 vga_res_id, bool vgaScript) { b += sizeof(ImageHeader_Simon); } assert(READ_BE_UINT16(&((ImageHeader_Simon *) b)->id) == vga_res_id); + + if (!vgaScript && _oldDrawMethod) + clearVideoWindow(_windowNum, READ_BE_UINT16(&((ImageHeader_Simon *) b)->color)); } else { b = bb + READ_BE_UINT16(bb + 10); b += 20; @@ -1089,7 +1170,7 @@ void AGOSEngine::setImage(uint16 vga_res_id, bool vgaScript) { assert(READ_BE_UINT16(&((ImageHeader_WW *) b)->id) == vga_res_id); if (!vgaScript) - clearWindow(_windowNum, READ_BE_UINT16(&((ImageHeader_WW *) b)->color)); + clearVideoWindow(_windowNum, READ_BE_UINT16(&((ImageHeader_WW *) b)->color)); } if (_startVgaScript) { @@ -1117,6 +1198,8 @@ void AGOSEngine::setImage(uint16 vga_res_id, bool vgaScript) { } void AGOSEngine::setWindowImageEx(uint16 mode, uint16 vga_res) { + _window3Flag = 0; + if (mode == 4) { vc29_stopAllSounds(); @@ -1151,10 +1234,10 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vga_res_id) { vc27_resetSprite(); } - if (vga_res_id == 0) { + if (!vga_res_id) { if (getGameType() == GType_SIMON1) { _unkPalFlag = true; - } else if (getGameType() == GType_SIMON2) { + } else if (getGameType() == GType_SIMON2 && !_oldDrawMethod) { _useBackGround = true; _restoreWindow6 = true; } @@ -1187,7 +1270,7 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vga_res_id) { fillFrontFromBack(0, 0, _screenWidth, _screenHeight); fillBackGroundFromBack(_screenHeight); _syncFlag2 = 1; - } else if (getGameType() == GType_SIMON2) { + } else if (getGameType() == GType_SIMON2 && !_oldDrawMethod) { if (!_useBackGround) { num_lines = _windowNum == 4 ? 134 : 200; _boxStarHeight = num_lines; @@ -1196,7 +1279,7 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vga_res_id) { _syncFlag2 = 1; } _useBackGround = false; - } else if (getGameType() == GType_SIMON1) { + } else if (getGameType() == GType_SIMON1 && !_oldDrawMethod) { // Allow one section of Simon the Sorcerer 1 introduction to be displayed // in lower half of screen if (_subroutine == 2923 || _subroutine == 2926) @@ -1209,21 +1292,90 @@ void AGOSEngine::setWindowImage(uint16 mode, uint16 vga_res_id) { _syncFlag2 = 1; _timer5 = 0; } else { - num_lines = _windowNum == 4 ? 134 : 200; - fillFrontFromBack(0, 0, _screenWidth, num_lines); - fillBackGroundFromBack(num_lines); - _syncFlag2 = 1; - _timer5 = 0; - } + if (_window3Flag == 1) { + clearVideoBackGround(3, 0); // (window, color) + } - if (getGameType() == GType_ELVIRA1 && updateWindow == 3 && _bottomPalette != 0) { - byte *dst = getBackBuf() + 42560; - int size = 21440; + uint xoffs = _videoWindows[updateWindow * 4 + 0] * 16; + uint yoffs = _videoWindows[updateWindow * 4 + 1]; + uint width = _videoWindows[updateWindow * 4 + 2] * 16; + uint height = _videoWindows[updateWindow * 4 + 3]; + + byte *dst = getBackGround() + xoffs + yoffs * _screenWidth; + byte *src; + uint srcWidth; + + if (getGameType() == GType_SIMON2) { + src = _window4BackScn + xoffs + yoffs * 320; + srcWidth = 320; + } else if (getGameType() == GType_SIMON1) { + if (updateWindow == 4) { + src = _window4BackScn; + srcWidth = _videoWindows[18] * 16; + } else if (updateWindow >= 10) { + src = _window4BackScn + xoffs + yoffs * 320; + srcWidth = _videoWindows[18] * 16; + } else if (updateWindow == 0) { + src = getFrontBuf() + xoffs + yoffs * _screenWidth; + srcWidth = _screenWidth; + } else { + _lockWord &= ~0x20; + return; + } + } else if (getGameType() == GType_WW) { + if (updateWindow == 4 || updateWindow >= 10) { + src = _window4BackScn; + srcWidth = _videoWindows[18] * 16; + } else if (updateWindow == 3 || updateWindow == 9) { + src = getFrontBuf() + xoffs + yoffs * _screenWidth; + srcWidth = _screenWidth; + } else { + _lockWord &= ~0x20; + return; + } + } else if (getGameType() == GType_ELVIRA2) { + if (updateWindow == 4 || updateWindow >= 10) { + src = _window4BackScn; + srcWidth = _videoWindows[18] * 16; + } else if (updateWindow == 3) { + src = getFrontBuf() + xoffs + yoffs * _screenWidth; + srcWidth = _screenWidth; + } else { + _lockWord &= ~0x20; + return; + } + } else if (getGameType() == GType_ELVIRA1) { + if (updateWindow == 6) { + _window6Flag = 1; + src = _window6BackScn; + srcWidth = 48; + } else if (updateWindow == 2 || updateWindow == 3) { + src = getFrontBuf() + xoffs + yoffs * _screenWidth; + srcWidth = _screenWidth; + } else { + src = _window4BackScn; + srcWidth = _videoWindows[18] * 16; + } + } - while (size--) { - *dst += 0x10; - dst++; + for (; height > 0; height--) { + memcpy(dst, src, width); + dst += _screenWidth; + src += srcWidth; } + + if (getGameType() == GType_ELVIRA1 && updateWindow == 3 && _bottomPalette != 0) { + dst = getFrontBuf() + 42560; + int size = 21440; + + while (size--) { + *dst += 0x10; + dst++; + } + } + + _syncFlag2 = 1; + _timer5 = 0; } _lockWord &= ~0x20; diff --git a/engines/agos/input.cpp b/engines/agos/input.cpp index f84083b7bc..d0fab120f5 100644 --- a/engines/agos/input.cpp +++ b/engines/agos/input.cpp @@ -174,6 +174,7 @@ void AGOSEngine::waitForInput() { _verbHitArea = 0; _hitAreaSubjectItem = NULL; _hitAreaObjectItem = NULL; + _clickOnly = 0; _nameLocked = 0; if (getGameType() == GType_WW) { diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index 0e82033ea2..40960c0cbe 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -118,15 +118,21 @@ char *AGOSEngine::genSaveName(int slot) { sprintf(buf, "feeble.%.3d", slot); } else if (getGameType() == GType_SIMON2) { sprintf(buf, "simon2.%.3d", slot); - } else { + } else if (getGameType() == GType_SIMON1) { sprintf(buf, "simon1.%.3d", slot); + } else if (getGameType() == GType_WW) { + sprintf(buf, "waxworks.%.3d", slot); + } else if (getGameType() == GType_ELVIRA2) { + sprintf(buf, "elvira2.%.3d", slot); + } else if (getGameType() == GType_ELVIRA1) { + sprintf(buf, "elvira1.%.3d", slot); } return buf; } void AGOSEngine::quickLoadOrSave() { // Quick load & save is only supported complete version of Simon the Sorcerer 1/2 - if (getGameType() != GType_SIMON1 && getGameType() != GType_SIMON2 || + if (getGameType() == GType_PP || getGameType() == GType_FF || (getFeatures() & GF_DEMO)) { return; } diff --git a/engines/agos/script_e1.cpp b/engines/agos/script_e1.cpp index b74c4f3c19..3becdc37bf 100644 --- a/engines/agos/script_e1.cpp +++ b/engines/agos/script_e1.cpp @@ -608,9 +608,9 @@ void AGOSEngine_Elvira1::oe1_pName() { void AGOSEngine_Elvira1::oe1_pcName() { // 115: Item *i = getNextItemPtr(); - Common::String name = (const char *)getStringPtrByID(i->itemName); - name.toUppercase(); - showMessageFormat("%s", name.c_str()); + + // TODO: Change first letter to upper case. + showMessageFormat("%s\n", (const byte *)getStringPtrByID(i->itemName)); // Difference } void AGOSEngine_Elvira1::oe1_isCalled() { @@ -815,6 +815,8 @@ void AGOSEngine_Elvira1::oe1_enableInput() { _lastHitArea3 = 0; _lastHitArea = 0; + + _clickOnly = 1; } void AGOSEngine_Elvira1::oe1_setTime() { @@ -1208,12 +1210,6 @@ void AGOSEngine::printScroll() { state.x_skip = 0; state.y_skip = 0; - state.surf2_addr = getFrontBuf(); - state.surf2_pitch = _dxSurfacePitch; - - state.surf_addr = getBackBuf(); - state.surf_pitch = _dxSurfacePitch; - drawImage(&state); } diff --git a/engines/agos/script_e2.cpp b/engines/agos/script_e2.cpp index ebcde7b038..203b95cd5e 100644 --- a/engines/agos/script_e2.cpp +++ b/engines/agos/script_e2.cpp @@ -310,7 +310,7 @@ void AGOSEngine_Elvira2::oe2_pObj() { SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2); if (subObject != NULL && subObject->objectFlags & kOFText) - showMessageFormat((const char *)getStringPtrByID(subObject->objectFlagValue[0])); + showMessageFormat("%s\n", (const char *)getStringPtrByID(subObject->objectFlagValue[0])); // Difference } void AGOSEngine_Elvira2::oe2_loadGame() { diff --git a/engines/agos/subroutine.cpp b/engines/agos/subroutine.cpp index 17039d1974..347aca997a 100644 --- a/engines/agos/subroutine.cpp +++ b/engines/agos/subroutine.cpp @@ -522,7 +522,7 @@ int AGOSEngine::startSubroutine(Subroutine *sub) { // WORKAROUND: Bit Flag 171 isn't set when Simon rides the lion to the // goblin camp in non-English versions. Bit Flag 171 is required to display // the red trail between locations on the map, during the ride. - if (getGameType() == GType_SIMON2) { + if (getGameType() == GType_SIMON2 && !_oldDrawMethod) { if (sub->id == 13020) setBitFlag(171, true); if (sub->id == 13021) diff --git a/engines/agos/verb.cpp b/engines/agos/verb.cpp index 645010f369..4142580184 100644 --- a/engines/agos/verb.cpp +++ b/engines/agos/verb.cpp @@ -682,7 +682,17 @@ void AGOSEngine::boxController(uint x, uint y, uint mode) { _variableArray[500] = best_ha->verb & 0xBFFF; } } - } + + if (_clickOnly != 0 && best_ha->id < 8) { + uint id = best_ha->id; + if (id >= 4) + id -= 4; + + invertBox(findBox(id), 0, 0, 0, 0); + _clickOnly = 0; + return; + } + } if (best_ha->flags & kBFDragBox) { _lastClickRem = best_ha; diff --git a/engines/agos/vga.cpp b/engines/agos/vga.cpp index 43745e6c7a..5b8bbafd54 100644 --- a/engines/agos/vga.cpp +++ b/engines/agos/vga.cpp @@ -210,6 +210,17 @@ bool AGOSEngine::vc_maybe_skip_proc_1(uint16 a, int16 b) { return item->state == b; } +void AGOSEngine::dirtyBackGround() { + AnimTable *animTable = _screenAnim1; + while (animTable->srcPtr) { + if (animTable->id == _vgaCurSpriteId) { + animTable->window |= 0x8000; + break; + } + animTable++; + } +} + VgaSprite *AGOSEngine::findCurSprite() { VgaSprite *vsp = _vgaSprites; while (vsp->id) { @@ -400,19 +411,22 @@ void AGOSEngine::vc3_loadSprite() { return; } - windowNum = vcReadNextWord(); /* 0 */ + windowNum = vcReadNextWord(); + if (getGameType() == GType_SIMON1 && windowNum == 3) { + _window3Flag = 1; + } if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) { - zoneNum = vcReadNextWord(); /* 0 */ - vgaSpriteId = vcReadNextWord(); /* 2 */ + zoneNum = vcReadNextWord(); + vgaSpriteId = vcReadNextWord(); } else { - vgaSpriteId = vcReadNextWord(); /* 2 */ + vgaSpriteId = vcReadNextWord(); zoneNum = vgaSpriteId / 100; } - x = vcReadNextWord(); /* 4 */ - y = vcReadNextWord(); /* 6 */ - palette = vcReadNextWord(); /* 8 */ + x = vcReadNextWord(); + y = vcReadNextWord(); + palette = vcReadNextWord(); old_file_1 = _curVgaFile1; @@ -607,6 +621,7 @@ void AGOSEngine::drawImage_init(int16 image, uint16 palette, uint16 x, uint16 y, state.image = vcReadVar(-state.image); state.palette = palette * 16; + state.paletteMod = 0; state.x = x - _scrollX; state.y = y - _scrollY; @@ -718,12 +733,18 @@ void AGOSEngine::vc12_delay() { void AGOSEngine::vc13_addToSpriteX() { VgaSprite *vsp = findCurSprite(); vsp->x += (int16)vcReadNextWord(); + + vsp->windowNum |= 0x8000; + dirtyBackGround(); _vgaSpriteChanged++; } void AGOSEngine::vc14_addToSpriteY() { VgaSprite *vsp = findCurSprite(); vsp->y += (int16)vcReadNextWord(); + + vsp->windowNum |= 0x8000; + dirtyBackGround(); _vgaSpriteChanged++; } @@ -951,6 +972,8 @@ void AGOSEngine::vc24_setSpriteXY() { vsp->flags = vcReadNextWord(); } + vsp->windowNum |= 0x8000; + dirtyBackGround(); _vgaSpriteChanged++; } @@ -963,6 +986,8 @@ void AGOSEngine::vc25_halt_sprite() { vsp++; } _vcPtr = (byte *)&_vc_get_out_of_code; + + dirtyBackGround(); _vgaSpriteChanged++; } @@ -1024,6 +1049,14 @@ void AGOSEngine::vc27_resetSprite() { } } + if (_lockWord & 0x20) { + AnimTable *animTable = _screenAnim1; + while (animTable->srcPtr) { + animTable->srcPtr = 0; + animTable++; + } + } + if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) vcWriteVar(254, 0); @@ -1083,8 +1116,20 @@ void AGOSEngine::vc31_setWindow() { } void AGOSEngine::vc32_saveScreen() { - // TODO - debug(0, "vc32_saveScreen: stub"); + uint xoffs = _videoWindows[4 * 4 + 0] * 16; + uint yoffs = _videoWindows[4 * 4 + 1]; + uint width = _videoWindows[4 * 4 + 2] * 16; + uint height = _videoWindows[4 * 4 + 3]; + + byte *dst = getBackGround() + xoffs + yoffs * _screenWidth; + byte *src = _window4BackScn; + uint srcWidth = _videoWindows[4 * 4 + 2] * 16; + + for (; height > 0; height--) { + memcpy(dst, src, width); + dst += _screenWidth; + src += srcWidth; + } } void AGOSEngine::vc33_setMouseOn() { @@ -1111,24 +1156,65 @@ void AGOSEngine::vc34_setMouseOff() { _leftButtonDown = 0; } -void AGOSEngine::clearWindow(uint num, uint color) { +void AGOSEngine::clearVideoBackGround(uint num, uint color) { + debug(0, "clearVideoBackGround: num %d color %d", num, color); + + const uint16 *vlut = &_videoWindows[num * 4]; + byte *dst = getBackGround() + vlut[0] * 16 + (vlut[1] * (vlut[2] * 16)); + + for (uint h = 0; h < vlut[3]; h++) { + memset(dst, color, vlut[2] * 16); + dst += _screenWidth; + } +} + +void AGOSEngine::clearVideoWindow(uint num, uint color) { if (getGameType() == GType_ELVIRA1) { if (num == 2 || num == 6) return; } else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) { if (num != 4 && num < 10) return; + } else if (getGameType() == GType_SIMON1) { + if (num != 4) + return; } - if (num == 3) { - memset(getBackBuf(), 0, _screenWidth * _screenHeight); - } else { + debug(0, "clearVideoWindow: num %d color %d", num, color); + + if (getGameType() == GType_SIMON2) { const uint16 *vlut = &_videoWindows[num * 4]; - byte *dst = getBackBuf() + vlut[0] * 16 + vlut[1] * _dxSurfacePitch; + uint xoffs = vlut[0] * 16; + uint yoffs = vlut[1]; + uint dstWidth = _videoWindows[18] * 16; + byte *dst = _window4BackScn + xoffs + yoffs * dstWidth; + + setMoveRect(0, 0, vlut[2] * 16, vlut[3]); for (uint h = 0; h < vlut[3]; h++) { - memset(dst, 0, vlut[2] * 16); - dst += _screenWidth; + memset(dst, color, vlut[2] * 16); + dst += dstWidth; + } + + _window4Flag = 1; + } else { + if (getGameType() == GType_ELVIRA1 && num == 3) { + memset(getFrontBuf(), color, _screenWidth * _screenHeight); + } else if (num == 4) { + const uint16 *vlut = &_videoWindows[num * 4]; + uint xoffs = (vlut[0] - _videoWindows[16]) * 16; + uint yoffs = (vlut[1] - _videoWindows[17]); + uint dstWidth = _videoWindows[18] * 16; + byte *dst = _window4BackScn + xoffs + yoffs * dstWidth; + + setMoveRect(0, 0, vlut[2] * 16, vlut[3]); + + for (uint h = 0; h < vlut[3]; h++) { + memset(dst, color, vlut[2] * 16); + dst += dstWidth; + } + + _window4Flag = 1; } } } @@ -1136,7 +1222,23 @@ void AGOSEngine::clearWindow(uint num, uint color) { void AGOSEngine::vc35_clearWindow() { uint16 num = vcReadNextWord(); uint16 color = vcReadNextWord(); - clearWindow(num, color); + + // Clear video window + clearVideoWindow(num, color); + + // Clear video background + if (getGameType() == GType_ELVIRA1) { + if (num == 2 || num == 6) + return; + } else if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) { + if (num != 4 && num < 10) + return; + } else if (getGameType() == GType_SIMON1) { + if (num != 4) + return; + } + + clearVideoBackGround(num, color); } void AGOSEngine::vc36_setWindowImage() { @@ -1147,7 +1249,7 @@ void AGOSEngine::vc36_setWindowImage() { if (getGameType() == GType_FF || getGameType() == GType_PP) { _copyPartialMode = 2; } else if (getGameType() == GType_SIMON1) { - if (windowNum == 16) { + if (windowNum == 16 && !_oldDrawMethod) { _copyPartialMode = 2; } else { setWindowImage(windowNum, vga_res); diff --git a/engines/agos/vga.h b/engines/agos/vga.h index 7a4f06f26f..ac84262cbf 100644 --- a/engines/agos/vga.h +++ b/engines/agos/vga.h @@ -56,7 +56,7 @@ struct AnimationHeader_Feeble { // Simon 1/2 struct ImageHeader_Simon { uint16 id; - uint16 x_1; + uint16 color; uint16 x_2; uint16 scriptOffs; }; @@ -116,6 +116,7 @@ struct VC10_state { int16 image; uint16 flags; byte palette; + byte paletteMod; int16 x, y; uint16 width, height; diff --git a/engines/agos/vga_e2.cpp b/engines/agos/vga_e2.cpp index a85135a9d2..2c40037b40 100644 --- a/engines/agos/vga_e2.cpp +++ b/engines/agos/vga_e2.cpp @@ -68,21 +68,37 @@ void AGOSEngine::vc45_setWindowPalette() { uint num = vcReadNextWord(); uint color = vcReadNextWord(); - const uint16 *vlut = &_videoWindows[num * 4]; - uint16 *dst = (uint16 *)getBackBuf() + vlut[0] * 8 + vlut[1] * _dxSurfacePitch / 2; - uint width = vlut[2] * 8; - - if (getGameType() == GType_ELVIRA2 && num == 7) { - dst -= 4; - width += 4; - } + if (num == 4) { + const uint16 *vlut = &_videoWindows[num * 4]; + uint16 *dst = (uint16 *)_window4BackScn; + uint width = vlut[2] * 16 / 2; + uint height = vlut[3]; + + for (uint h = 0; h < height; h++) { + for (uint w = 0; w < width; w++) { + dst[w] &= 0xF0F; + dst[w] |= color * 16; + } + dst += width; + } + } else { + const uint16 *vlut = &_videoWindows[num * 4]; + uint16 *dst = (uint16 *)getFrontBuf() + vlut[0] * 8 + vlut[1] * _dxSurfacePitch / 2; + uint width = vlut[2] * 16 / 2; + uint height = vlut[3]; + + if (getGameType() == GType_ELVIRA2 && num == 7) { + dst -= 4; + width += 4; + } - for (uint h = 0; h < vlut[3]; h++) { - for (uint w = 0; w < width; w++) { - dst[w] &= 0xF0F; - dst[w] |= color * 16; + for (uint h = 0; h < height; h++) { + for (uint w = 0; w < width; w++) { + dst[w] &= 0xF0F; + dst[w] |= color * 16; + } + dst += _dxSurfacePitch / 2; } - dst += _dxSurfacePitch / 2; } } @@ -211,7 +227,7 @@ void AGOSEngine::vc55_moveBox() { void AGOSEngine::vc56_fullScreen() { byte *src = _curVgaFile2 + 32; - byte *dst = getBackBuf(); + byte *dst = getFrontBuf(); memcpy(dst, src + 768, _screenHeight * _screenWidth); //fullFade(); diff --git a/engines/agos/vga_s1.cpp b/engines/agos/vga_s1.cpp index 9ddc3becf3..ad7b8b06f5 100644 --- a/engines/agos/vga_s1.cpp +++ b/engines/agos/vga_s1.cpp @@ -103,18 +103,27 @@ void AGOSEngine::vc32_copyVar() { void AGOSEngine::vc37_addToSpriteY() { VgaSprite *vsp = findCurSprite(); vsp->y += vcReadVar(vcReadNextWord()); + + vsp->windowNum |= 0x8000; + dirtyBackGround(); _vgaSpriteChanged++; } void AGOSEngine::vc45_setSpriteX() { VgaSprite *vsp = findCurSprite(); vsp->x = vcReadVar(vcReadNextWord()); + + vsp->windowNum |= 0x8000; + dirtyBackGround(); _vgaSpriteChanged++; } void AGOSEngine::vc46_setSpriteY() { VgaSprite *vsp = findCurSprite(); vsp->y = vcReadVar(vcReadNextWord()); + + vsp->windowNum |= 0x8000; + dirtyBackGround(); _vgaSpriteChanged++; } @@ -209,6 +218,8 @@ void AGOSEngine::vc61_setMaskImage() { vsp->y += vcReadNextWord(); vsp->flags = kDFMasked | kDFUseFrontBuf; + vsp->windowNum |= 0x8000; + dirtyBackGround(); _vgaSpriteChanged++; } diff --git a/engines/agos/vga_ww.cpp b/engines/agos/vga_ww.cpp index f73476c5cb..f9995fc715 100644 --- a/engines/agos/vga_ww.cpp +++ b/engines/agos/vga_ww.cpp @@ -110,7 +110,7 @@ void AGOSEngine::vc61() { if (a == 6) { src = _curVgaFile2 + 800; - dstPtr = getBackBuf(); + dstPtr = getFrontBuf(); memcpy(dstPtr, src, 64000); tmp = 4 - 1; } else { @@ -218,14 +218,21 @@ void AGOSEngine::vc62_fastFadeOut() { } } - // Allow one section of Simon the Sorcerer 1 introduction to be displayed - // in lower half of screen - if ((getGameType() == GType_SIMON1) && (_subroutine == 2923 || _subroutine == 2926)) { - clearSurfaces(200); - } else if (getGameType() == GType_FF || getGameType() == GType_PP) { + if (getGameType() == GType_FF || getGameType() == GType_PP) { clearSurfaces(480); + } else if (getGameType() == GType_WW) { + memset(getFrontBuf(), 0, _screenWidth * _screenHeight); + } else if (!_oldDrawMethod) { + // Allow one section of Simon the Sorcerer 1 introduction to be displayed + // in lower half of screen + if ((getGameType() == GType_SIMON1) && (_subroutine == 2923 || _subroutine == 2926)) { + clearSurfaces(200); + } else { + clearSurfaces(_windowNum == 4 ? 134 : 200); + } } else { - clearSurfaces(_windowNum == 4 ? 134 : 200); + if (_windowNum != 4) + memset(getFrontBuf(), 0, _screenWidth * _screenHeight); } } if (getGameType() == GType_SIMON2) { diff --git a/engines/agos/window.cpp b/engines/agos/window.cpp index 909ab97c33..81746f8dc3 100644 --- a/engines/agos/window.cpp +++ b/engines/agos/window.cpp @@ -123,6 +123,18 @@ void AGOSEngine::colorWindow(WindowBlock *window) { dst += _screenWidth; } } else { + if (getGameType() == GType_ELVIRA2 && window->y == 146) { + if (window->fill_color == 1) { + _displayPalette[33 * 4 + 0] = 48 * 4; + _displayPalette[33 * 4 + 1] = 40 * 4; + _displayPalette[33 * 4 + 2] = 32 * 4; + } else { + _displayPalette[33 * 4 + 0] = 56 * 4; + _displayPalette[33 * 4 + 1] = 56 * 4; + _displayPalette[33 * 4 + 2] = 40 * 4; + } + } + dst = getFrontBuf() + _dxSurfacePitch * window->y + window->x * 8; h = window->height * 8; w = window->width * 8; @@ -170,7 +182,7 @@ void AGOSEngine::restoreBlock(uint h, uint w, uint y, uint x) { uint i; dst = getFrontBuf(); - src = _backGroundBuf; + src = getBackGround(); dst += y * _dxSurfacePitch; src += y * _dxSurfacePitch; |