Files
scummvm/engines/gob/draw_v2.cpp
T
Simon Delamarre 0099c3624c GOB: coordinates adjustment for games existing in several resolutions
This mechanism was used to accommodate games existing in several resolutions, while keeping the same script logic across versions.
Opcodes manipulating coordinates and lengths call the adjustCoords() function to double or halve their values depending on the adjustment needed.

Its usage has been confirmed only in a German version of Adibou1 for now, restrict the feature to this game.
2023-04-21 00:13:44 +02:00

980 lines
26 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/endian.h"
#include "common/str.h"
#include "graphics/cursorman.h"
#include "gob/gob.h"
#include "gob/draw.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/game.h"
#include "gob/script.h"
#include "gob/resources.h"
#include "gob/hotspots.h"
#include "gob/scenery.h"
#include "gob/inter.h"
#include "gob/video.h"
namespace Gob {
Draw_v2::Draw_v2(GobEngine *vm) : Draw_v1(vm) {
_mayorWorkaroundStatus = 0;
}
void Draw_v2::initScreen() {
_vm->_game->_preventScroll = false;
_scrollOffsetX = 0;
_scrollOffsetY = 0;
initSpriteSurf(kBackSurface, _vm->_video->_surfWidth, _vm->_video->_surfHeight, 0);
_backSurface = _spritesArray[kBackSurface];
_backSurface->clear();
if (!_spritesArray[kCursorSurface]) {
initSpriteSurf(kCursorSurface, 32, 16, 2);
_cursorSpritesBack = _spritesArray[kCursorSurface];
_cursorSprites = _cursorSpritesBack;
_scummvmCursor = _vm->_video->initSurfDesc(16, 16, SCUMMVM_CURSOR);
}
_spritesArray[kFrontSurface] = _frontSurface;
_spritesArray[kBackSurface ] = _backSurface;
_vm->_video->dirtyRectsAll();
}
void Draw_v2::closeScreen() {
//freeSprite(kCursorSurface);
//_cursorSprites = 0;
//_cursorSpritesBack = 0;
//_scummvmCursor = 0;
freeSprite(kBackSurface);
}
void Draw_v2::blitCursor() {
if (!_cursorSprites || (_cursorIndex == -1))
return;
_showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1);
}
void Draw_v2::animateCursor(int16 cursor) {
if (!_cursorSprites)
return;
int16 cursorIndex = cursor;
int16 newX = 0, newY = 0;
uint16 hotspotX, hotspotY;
_showCursor |= 1;
// .-- _draw_animateCursorSUB1 ---
if (cursorIndex == -1) {
cursorIndex =
_vm->_game->_hotspots->findCursor(_vm->_global->_inter_mouseX,
_vm->_global->_inter_mouseY);
if (_cursorAnimLow[cursorIndex] == -1)
cursorIndex = 1;
}
// '------
if (_cursorAnimLow[cursorIndex] != -1) {
// .-- _draw_animateCursorSUB2 ---
if (cursorIndex == _cursorIndex) {
if ((_cursorAnimDelays[_cursorIndex] != 0) &&
((_cursorTimeKey + (_cursorAnimDelays[_cursorIndex] * 10)) <=
_vm->_util->getTimeKey())) {
_cursorAnim++;
if ((_cursorAnimHigh[_cursorIndex] < _cursorAnim) ||
(_cursorAnimLow[_cursorIndex] > _cursorAnim))
_cursorAnim = _cursorAnimLow[_cursorIndex];
_cursorTimeKey = _vm->_util->getTimeKey();
} else {
if (_noInvalidated && (_vm->_global->_inter_mouseX == _cursorX) &&
(_vm->_global->_inter_mouseY == _cursorY)) {
_vm->_video->waitRetrace();
return;
}
}
} else {
_cursorIndex = cursorIndex;
if (_cursorAnimDelays[cursorIndex] != 0) {
_cursorAnim = _cursorAnimLow[cursorIndex];
_cursorTimeKey = _vm->_util->getTimeKey();
}
}
if (_cursorAnimDelays[_cursorIndex] != 0) {
if ((_cursorAnimHigh[_cursorIndex] < _cursorAnim) ||
(_cursorAnimLow[_cursorIndex] > _cursorAnim))
_cursorAnim = _cursorAnimLow[_cursorIndex];
cursorIndex = _cursorAnim;
}
// '------
hotspotX = 0;
hotspotY = 0;
if (_cursorHotspotXVar != -1) {
hotspotX = (uint16) VAR(_cursorIndex + _cursorHotspotXVar);
hotspotY = (uint16) VAR(_cursorIndex + _cursorHotspotYVar);
} else if (_cursorHotspotX != -1) {
hotspotX = _cursorHotspotX;
hotspotY = _cursorHotspotY;
}
newX = _vm->_global->_inter_mouseX - hotspotX;
newY = _vm->_global->_inter_mouseY - hotspotY;
_scummvmCursor->clear();
_scummvmCursor->blit(*_cursorSprites,
cursorIndex * _cursorWidth, 0,
(cursorIndex + 1) * _cursorWidth - 1,
_cursorHeight - 1, 0, 0);
CursorMan.replaceCursor(_scummvmCursor->getData(),
_cursorWidth, _cursorHeight, hotspotX, hotspotY, 0, false, &_vm->getPixelFormat());
CursorMan.disableCursorPalette(true);
if (_frontSurface != _backSurface) {
if (!_noInvalidated) {
int16 tmp = _cursorIndex;
_cursorIndex = -1;
blitInvalidated();
_cursorIndex = tmp;
} else {
_showCursor = 3;
_vm->_video->waitRetrace();
if (MIN(newY, _cursorY) < 50)
_vm->_util->delay(5);
}
}
} else {
blitCursor();
_cursorX = newX;
_cursorY = newY;
}
_showCursor &= ~1;
}
void Draw_v2::printTotText(int16 id) {
byte *dataPtr;
byte *ptr, *ptrEnd;
byte cmd;
int16 savedFlags;
int16 destX, destY;
int16 spriteRight, spriteBottom;
int16 val;
int16 rectLeft, rectTop, rectRight, rectBottom;
int16 size;
id &= 0xFFF;
_vm->validateLanguage();
// WORKAROUND: In the scripts of some Gobliins 2 versions, the dialog text IDs
// for Fingus and the mayor are swapped.
if ((_vm->getGameType() == kGameTypeGob2) && !_vm->isCD() &&
_vm->isCurrentTot("gob07.tot")) {
if (id == 24) {
if (_mayorWorkaroundStatus == 1) {
_mayorWorkaroundStatus = 0;
id = 31;
} else
_mayorWorkaroundStatus = 2;
} else if (id == 31) {
if (_mayorWorkaroundStatus == 0) {
_mayorWorkaroundStatus = 1;
id = 24;
} else
_mayorWorkaroundStatus = 0;
}
}
TextItem *textItem = _vm->_game->_resources->getTextItem(id);
if (!textItem)
return;
size = textItem->getSize();
dataPtr = textItem->getData();
ptr = dataPtr;
_pattern = 0;
bool isSubtitle = (ptr[1] & 0x80) != 0;
if (isSubtitle && !_vm->_global->_doSubtitles) {
delete textItem;
return;
}
if (_renderFlags & RENDERFLAG_DOUBLECOORDS) {
destX = (READ_LE_UINT16(ptr) & 0x7FFF) * 2;
spriteRight = READ_LE_UINT16(ptr + 4) * 2 + 1;
} else {
// No mask used for Fascination
destX = READ_LE_UINT16(ptr);
if (_vm->getGameType() != kGameTypeFascination)
destX &= 0x7FFF;
spriteRight = READ_LE_UINT16(ptr + 4);
}
if (_renderFlags & RENDERFLAG_FROMSPLIT) {
int16 start;
start = _vm->_video->_splitStart;
destY = start;
spriteBottom = READ_LE_UINT16(ptr + 6) - READ_LE_UINT16(ptr + 2);
if (_renderFlags & RENDERFLAG_DOUBLECOORDS)
spriteBottom *= 3;
spriteBottom += start;
if (_renderFlags & RENDERFLAG_DOUBLECOORDS) {
spriteBottom += _backDeltaY;
destY += _backDeltaY;
}
} else {
destY = READ_LE_UINT16(ptr + 2);
spriteBottom = READ_LE_UINT16(ptr + 6);
if (_renderFlags & RENDERFLAG_DOUBLECOORDS) {
destY *= 2;
spriteBottom *= 2;
}
}
ptr += 8;
if (_renderFlags & RENDERFLAG_CAPTUREPUSH) {
_vm->_game->capturePush(destX, destY,
spriteRight - destX + 1, spriteBottom - destY + 1);
(*_vm->_scenery->_pCaptureCounter)++;
}
_destSpriteX = destX;
_destSpriteY = destY;
_spriteRight = spriteRight;
_spriteBottom = spriteBottom;
_destSurface = kBackSurface;
_backColor = *ptr++;
_transparency = 1;
if ((_vm->getGameType() == kGameTypeAdibou2 ||
_vm->getGameType() == kGameTypeAdi4) &&
_backColor == 16)
_backColor = -1;
spriteOperation(DRAW_CLEARRECT);
_backColor = 0;
savedFlags = _renderFlags;
_renderFlags &= ~RENDERFLAG_NOINVALIDATE;
while ((_destSpriteX = READ_LE_UINT16(ptr)) != -1) {
_destSpriteX += destX;
_destSpriteY = READ_LE_UINT16(ptr + 2) + destY;
_spriteRight = READ_LE_UINT16(ptr + 4) + destX;
_spriteBottom = READ_LE_UINT16(ptr + 6) + destY;
ptr += 8;
cmd = *ptr++;
switch ((cmd & 0xF0) >> 4) {
case 0:
_frontColor = cmd & 0xF;
spriteOperation(DRAW_DRAWLINE);
break;
case 1:
_frontColor = cmd & 0xF;
spriteOperation(DRAW_DRAWBAR);
break;
case 2:
_backColor = cmd & 0xF;
spriteOperation(DRAW_FILLRECTABS);
break;
default:
break;
}
}
ptr += 2;
ptrEnd = ptr;
while (((ptrEnd - dataPtr) < size) && (*ptrEnd != 1)) {
// Converting to unknown commands/characters to spaces
if ((_vm->_game->_script->getVersionMinor() < 2) && (*ptrEnd > 3) && (*ptrEnd < 32))
*ptrEnd = 32;
switch (*ptrEnd) {
case 1:
break;
case 2:
case 5:
ptrEnd += 5;
break;
case 3:
case 4:
ptrEnd += 2;
break;
case 6:
ptrEnd++;
switch (*ptrEnd & 0xC0) {
case 0x40:
ptrEnd += 9;
break;
case 0x80:
ptrEnd += 3;
break;
case 0xC0:
ptrEnd += 11;
break;
default:
ptrEnd++;
break;
}
break;
case 10:
ptrEnd += (ptrEnd[1] * 2) + 2;
break;
default:
ptrEnd++;
break;
}
}
ptrEnd++;
int16 fontIndex = 0, frontColor = 0;
int16 strPos = 0, strPos2 = -1, strPosBak;
int16 offX = 0, offY = 0;
int16 colId = 0;
int16 colCmd = 0;
int16 width;
int16 maskChar = 0;
char mask[80], str[80], buf[50];
memset(mask, 0, 80);
memset(str, ' ', 80);
_backColor = 0;
_transparency = 1;
while (true) {
if ((((*ptr >= 1) && (*ptr <= 7)) || (*ptr == 10)) && (strPos != 0)) {
str[MAX(strPos, strPos2)] = 0;
strPosBak = strPos;
width = strlen(str) * _fonts[fontIndex]->getCharWidth();
adjustCoords(1, &width, nullptr);
if (colCmd & 0x0F) {
rectLeft = offX - 2;
rectTop = offY - 2;
rectRight = offX + width + 1;
rectBottom = _fonts[fontIndex]->getCharHeight();
adjustCoords(1, &rectBottom, nullptr);
rectBottom += offY + 1;
adjustCoords(0, &rectLeft, &rectTop);
adjustCoords(2, &rectRight, &rectBottom);
if (colId != -1)
_vm->_game->_hotspots->add(colId + 0xD000, rectLeft, rectTop,
rectRight, rectBottom, (uint16) Hotspots::kTypeClick, 0, 0, 0, 0);
if (_needAdjust != 2)
printTextCentered(colCmd & 0x0F, rectLeft + 4, rectTop + 4,
rectRight - 4, rectBottom - 4, str, fontIndex, frontColor);
else
printTextCentered(colCmd & 0x0F, rectLeft + 2, rectTop + 2,
rectRight - 2, rectBottom - 2, str, fontIndex, frontColor);
} else {
_destSpriteX = offX;
_destSpriteY = offY;
_fontIndex = fontIndex;
_frontColor = frontColor;
_textToPrint = str;
if (isSubtitle) {
_fontIndex = _subtitleFont;
_frontColor = _subtitleColor;
}
if (_needAdjust != 2) {
if ((_destSpriteX >= destX) && (_destSpriteY >= destY) &&
(((_fonts[_fontIndex]->getCharHeight() / 2) + _destSpriteY - 1) <= spriteBottom)) {
while (((_destSpriteX + width - 1) > spriteRight) && (width > 0)) {
width -= _fonts[_fontIndex]->getCharWidth() / 2;
str[strlen(str) - 1] = '\0';
}
spriteOperation(DRAW_PRINTTEXT);
}
} else
spriteOperation(DRAW_PRINTTEXT);
width = strlen(str);
for (strPos = 0; strPos < width; strPos++) {
if (mask[strPos] == '\0')
continue;
rectLeft = _fonts[fontIndex]->getCharWidth();
rectTop = _fonts[fontIndex]->getCharHeight();
adjustCoords(1, &rectLeft, &rectTop);
_destSpriteX = strPos * rectLeft + offX;
_spriteRight = _destSpriteX + rectLeft - 1;
_spriteBottom = offY + rectTop;
_destSpriteY = _spriteBottom;
spriteOperation(DRAW_DRAWLINE);
}
}
rectLeft = 0;
for (int i = 0; i < strPosBak; i++)
rectLeft += _fonts[_fontIndex]->getCharWidth(str[i]);
adjustCoords(1, &rectLeft, nullptr);
offX += rectLeft;
strPos = 0;
strPos2 = -1;
memset(mask, 0, 80);
memset(str, ' ', 80);
}
if (*ptr == 1)
break;
cmd = *ptr;
switch ((uint8) cmd) {
case 2:
case 5:
ptr++;
offX = destX + (int16)READ_LE_UINT16(ptr);
offY = destY + (int16)READ_LE_UINT16(ptr + 2);
if (_renderFlags & RENDERFLAG_DOUBLECOORDS) {
offX += (int16)READ_LE_UINT16(ptr);
offY += (int16)READ_LE_UINT16(ptr + 2);
}
ptr += 4;
break;
case 3:
ptr++;
fontIndex = ((*ptr & 0xF0) >> 4) & 7;
frontColor = *ptr & 0x0F;
ptr++;
if (isSubtitle) {
_subtitleFont = fontIndex;
_subtitleColor = frontColor;
}
break;
case 4:
ptr++;
frontColor = *ptr++;
if (isSubtitle)
_subtitleColor = frontColor;
break;
case 6:
ptr++;
colCmd = *ptr++;
colId = -1;
if (colCmd & 0x80) {
colId = (int16)READ_LE_UINT16(ptr);
ptr += 2;
}
if (colCmd & 0x40) {
rectLeft = destX + (int16)READ_LE_UINT16(ptr);
rectRight = destX + (int16)READ_LE_UINT16(ptr + 2);
rectTop = destY + (int16)READ_LE_UINT16(ptr + 4);
rectBottom = destY + (int16)READ_LE_UINT16(ptr + 6);
adjustCoords(2, &rectLeft, &rectTop);
adjustCoords(2, &rectRight, &rectBottom);
_vm->_game->_hotspots->add(colId + 0x0D000, rectLeft, rectTop,
rectRight, rectBottom, (uint16) Hotspots::kTypeClick, 0, 0, 0, 0);
ptr += 8;
}
break;
case 7:
ptr++;
colCmd = 0;
break;
case 8:
ptr++;
maskChar = 1;
break;
case 9:
ptr++;
maskChar = 0;
break;
case 10:
str[0] = (char) 255;
WRITE_LE_UINT16(str + 1, ptr - _vm->_game->_resources->getTexts());
str[3] = 0;
ptr++;
for (int i = *ptr++; i > 0; i--) {
mask[strPos++] = maskChar;
ptr += 2;
}
break;
default:
str[strPos] = (char) cmd;
// fall through
case 32:
mask[strPos++] = maskChar;
ptr++;
break;
case 186:
cmd = ptrEnd[17] & 0x7F;
if (cmd == 0) {
val = READ_LE_UINT16(ptrEnd + 18) * 4;
Common::sprintf_s(buf, "%d", (int32)VAR_OFFSET(val));
} else if (cmd == 1) {
val = READ_LE_UINT16(ptrEnd + 18) * 4;
Common::strlcpy(buf, GET_VARO_STR(val), 20);
} else {
val = READ_LE_UINT16(ptrEnd + 18) * 4;
Common::sprintf_s(buf, "%d", (int32)VAR_OFFSET(val));
if (buf[0] == '-') {
while (strlen(buf) - 1 < (uint32)ptrEnd[17]) {
_vm->_util->insertStr("0", buf, 1);
}
} else {
while (strlen(buf) - 1 < (uint32)ptrEnd[17]) {
_vm->_util->insertStr("0", buf, 0);
}
}
if (_vm->_global->_language == 2)
_vm->_util->insertStr(".", buf, strlen(buf) + 1 - ptrEnd[17]);
else
_vm->_util->insertStr(",", buf, strlen(buf) + 1 - ptrEnd[17]);
}
memcpy(str + strPos, buf, strlen(buf));
memset(mask, maskChar, strlen(buf));
if (ptrEnd[17] & 0x80) {
strPos2 = strPos + strlen(buf);
strPos++;
ptrEnd += 23;
ptr++;
} else {
strPos += strlen(buf);
if (ptr[1] != ' ') {
if ((ptr[1] == 2) &&
(((int16)READ_LE_UINT16(ptr + 4)) == _destSpriteY)) {
ptr += 5;
str[strPos] = ' ';
mask[strPos++] = maskChar;
}
} else {
str[strPos] = ' ';
mask[strPos++] = maskChar;
while (ptr[1] == ' ')
ptr++;
if ((ptr[1] == 2) &&
(((int16)READ_LE_UINT16(ptr + 4)) == _destSpriteY))
ptr += 5;
}
ptrEnd += 23;
ptr++;
}
break;
}
}
delete textItem;
_renderFlags = savedFlags;
if (!(_renderFlags & RENDERFLAG_COLLISIONS))
return;
_vm->_game->_hotspots->check(0, 0);
if (*_vm->_scenery->_pCaptureCounter != 0) {
(*_vm->_scenery->_pCaptureCounter)--;
_vm->_game->capturePop(1);
}
}
void Draw_v2::spriteOperation(int16 operation) {
int16 len;
int16 x, y;
SurfacePtr sourceSurf, destSurf;
bool deltaVeto;
int16 left;
int16 ratio;
Resource *resource;
deltaVeto = (operation & 0x10) != 0;
operation &= 0x0F;
if (_sourceSurface >= 100)
_sourceSurface -= 80;
if (_destSurface >= 100)
_destSurface -= 80;
if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) {
if ((_sourceSurface == kBackSurface) && (operation != DRAW_LOADSPRITE)) {
_spriteLeft += _backDeltaX;
_spriteTop += _backDeltaY;
}
if (_destSurface == kBackSurface) {
_destSpriteX += _backDeltaX;
_destSpriteY += _backDeltaY;
if ((operation == DRAW_DRAWLINE) ||
((operation >= DRAW_DRAWBAR) && (operation <= DRAW_FILLRECTABS))) {
_spriteRight += _backDeltaX;
_spriteBottom += _backDeltaY;
}
}
}
int16 spriteLeft = _spriteLeft;
int16 spriteTop = _spriteTop;
int16 spriteRight = _spriteRight;
int16 spriteBottom = _spriteBottom;
int16 destSpriteX = _destSpriteX;
int16 destSpriteY = _destSpriteY;
int16 destSurface = _destSurface;
int16 sourceSurface = _sourceSurface;
if (_vm->_video->_splitSurf && ((_destSurface == kFrontSurface) || (_destSurface == kBackSurface))) {
if ((_destSpriteY >= _vm->_video->_splitStart)) {
_destSpriteY -= _vm->_video->_splitStart;
if ((operation == DRAW_DRAWLINE) ||
((operation >= DRAW_DRAWBAR) && (operation <= DRAW_FILLRECTABS)))
_spriteBottom -= _vm->_video->_splitStart;
_destSurface += 4;
}
if ((_spriteTop >= _vm->_video->_splitStart) && (operation == DRAW_BLITSURF)) {
_spriteTop -= _vm->_video->_splitStart;
if (_destSurface < 24)
_destSurface += 4;
}
}
adjustCoords(0, &_destSpriteX, &_destSpriteY);
if ((operation != DRAW_LOADSPRITE) && (_needAdjust != 2)) {
adjustCoords(0, &_spriteRight, &_spriteBottom);
adjustCoords(0, &_spriteLeft, &_spriteTop);
if (operation == DRAW_DRAWLINE) {
if ((_spriteRight == _destSpriteX) || (_spriteBottom == _destSpriteY)) {
operation = DRAW_FILLRECTABS;
_backColor = _frontColor;
}
} else if (operation == DRAW_DRAWLETTER)
operation = DRAW_BLITSURF;
if (operation == DRAW_DRAWLINE) {
if (_spriteBottom < _destSpriteY) {
SWAP(_spriteBottom, _destSpriteY);
SWAP(_spriteRight, _destSpriteX);
}
} else if ((operation == DRAW_LOADSPRITE) ||
(operation > DRAW_PRINTTEXT)) {
if (_spriteBottom < _destSpriteY)
SWAP(_spriteBottom, _destSpriteY);
if (_spriteRight < _destSpriteX)
SWAP(_spriteRight, _destSpriteX);
_spriteRight++;
_spriteBottom++;
}
}
sourceSurf = _spritesArray[_sourceSurface];
destSurf = _spritesArray[_destSurface];
if (!destSurf) {
warning("Can't do operation %d on surface %d: nonexistent", operation, _destSurface);
return;
}
switch (operation) {
case DRAW_BLITSURF:
case DRAW_DRAWLETTER:
if (!sourceSurf || !destSurf)
break;
_spritesArray[_destSurface]->blit(*_spritesArray[_sourceSurface],
_spriteLeft, _spriteTop,
_spriteLeft + _spriteRight - 1,
_spriteTop + _spriteBottom - 1,
_destSpriteX, _destSpriteY, (_transparency == 0) ? -1 : 0, _transparency & 0x80);
dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
_destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1);
break;
case DRAW_PUTPIXEL:
_spritesArray[_destSurface]->putPixel(_destSpriteX, _destSpriteY, _frontColor);
dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _destSpriteX, _destSpriteY);
break;
case DRAW_FILLRECT:
if (!(_backColor & 0xFF00) || !(_backColor & 0x0100)) {
_spritesArray[_destSurface]->fillRect(_destSpriteX,
_destSpriteY, _destSpriteX + _spriteRight - 1,
_destSpriteY + _spriteBottom - 1, getColor(_backColor));
} else {
uint8 strength = 16 - (((uint16) _backColor) >> 12);
_spritesArray[_destSurface]->shadeRect(_destSpriteX,
_destSpriteY, _destSpriteX + _spriteRight - 1,
_destSpriteY + _spriteBottom - 1, getColor(_backColor), strength);
}
dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
_destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1);
break;
case DRAW_DRAWLINE:
_spritesArray[_destSurface]->drawLine(_destSpriteX, _destSpriteY,
_spriteRight, _spriteBottom, _frontColor);
dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
break;
case DRAW_INVALIDATE:
_spritesArray[_destSurface]->drawCircle(_destSpriteX,
_destSpriteY, _spriteRight, _frontColor);
dirtiedRect(_destSurface, _destSpriteX - _spriteRight, _destSpriteY - _spriteBottom,
_destSpriteX + _spriteRight, _destSpriteY + _spriteBottom);
break;
case DRAW_LOADSPRITE:
resource = _vm->_game->_resources->getResource((uint16) _spriteLeft,
&_spriteRight, &_spriteBottom);
if (!resource)
break;
if (_vm->_draw->_needAdjust == 3 || _vm->_draw->_needAdjust == 4)
adjustCoords(0, &_spriteRight, &_spriteBottom);
_vm->_video->drawPackedSprite(resource->getData(),
_spriteRight, _spriteBottom, _destSpriteX, _destSpriteY,
_transparency, *_spritesArray[_destSurface]);
dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
_destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1);
delete resource;
break;
case DRAW_PRINTTEXT:
// WORKAROUND: There's mistakes in Little Red's animal names.
// See this function for details.
fixLittleRedStrings();
len = strlen(_textToPrint);
left = _destSpriteX;
if ((_fontIndex >= 4) || (_fontToSprite[_fontIndex].sprite == -1)) {
if ((_fontIndex >= kFontCount) || !_fonts[_fontIndex]) {
warning("Trying to print \"%s\" with undefined font %d", _textToPrint, _fontIndex);
break;
}
Font *font = _fonts[_fontIndex];
if (font->isMonospaced()) {
if (((int8) _textToPrint[0]) == -1) {
_vm->validateLanguage();
byte *dataBuf = _vm->_game->_resources->getTexts() + _textToPrint[1] + 1;
len = *dataBuf++;
for (int i = 0; i < len; i++, dataBuf += 2) {
font->drawLetter(*_spritesArray[_destSurface], READ_LE_UINT16(dataBuf),
_destSpriteX, _destSpriteY, getColor(_frontColor),
getColor(_backColor), _transparency);
}
} else {
font->drawString(_textToPrint, _destSpriteX, _destSpriteY, getColor(_frontColor),
getColor(_backColor), _transparency, *_spritesArray[_destSurface]);
_destSpriteX += len * font->getCharWidth();
}
} else {
for (int i = 0; i < len; i++) {
font->drawLetter(*_spritesArray[_destSurface], _textToPrint[i],
_destSpriteX, _destSpriteY, getColor(_frontColor),
getColor(_backColor), _transparency);
_destSpriteX += font->getCharWidth(_textToPrint[i]);
}
}
} else {
sourceSurf = _spritesArray[_fontToSprite[_fontIndex].sprite];
ratio = ((sourceSurf == _frontSurface) || (sourceSurf == _backSurface)) ?
320 : sourceSurf->getWidth();
ratio /= _fontToSprite[_fontIndex].width;
for (int i = 0; i < len; i++) {
y = ((_textToPrint[i] - _fontToSprite[_fontIndex].base) / ratio)
* _fontToSprite[_fontIndex].height;
x = ((_textToPrint[i] - _fontToSprite[_fontIndex].base) % ratio)
* _fontToSprite[_fontIndex].width;
_spritesArray[_destSurface]->blit(*_spritesArray[_fontToSprite[_fontIndex].sprite], x, y,
x + _fontToSprite[_fontIndex].width - 1,
y + _fontToSprite[_fontIndex].height - 1,
_destSpriteX, _destSpriteY, (_transparency == 0) ? -1 : 0);
_destSpriteX += _fontToSprite[_fontIndex].width;
}
}
dirtiedRect(_destSurface, left, _destSpriteY,
_destSpriteX - 1, _destSpriteY + _fonts[_fontIndex]->getCharHeight() - 1);
break;
case DRAW_DRAWBAR:
if (_needAdjust != 2) {
_spritesArray[_destSurface]->fillRect(_destSpriteX, _spriteBottom - 1,
_spriteRight, _spriteBottom, _frontColor);
_spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
_destSpriteX + 1, _spriteBottom, _frontColor);
_spritesArray[_destSurface]->fillRect(_spriteRight - 1, _destSpriteY,
_spriteRight, _spriteBottom, _frontColor);
_spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
_spriteRight, _destSpriteY + 1, _frontColor);
} else {
_spritesArray[_destSurface]->drawLine(_destSpriteX, _spriteBottom,
_spriteRight, _spriteBottom, _frontColor);
_spritesArray[_destSurface]->drawLine(_destSpriteX, _destSpriteY,
_destSpriteX, _spriteBottom, _frontColor);
_spritesArray[_destSurface]->drawLine(_spriteRight, _destSpriteY,
_spriteRight, _spriteBottom, _frontColor);
_spritesArray[_destSurface]->drawLine(_destSpriteX, _destSpriteY,
_spriteRight, _destSpriteY, _frontColor);
}
dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
break;
case DRAW_CLEARRECT:
if ((_backColor != 16) && (_backColor != 144)) {
_spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
_spriteRight, _spriteBottom,
getColor(_backColor));
}
dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
break;
case DRAW_FILLRECTABS:
_spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
_spriteRight, _spriteBottom, getColor(_backColor));
dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
break;
default:
warning("unkown operation %d in Draw_v2::spriteOperation", operation);
break;
}
_spriteLeft = spriteLeft;
_spriteTop = spriteTop;
_spriteRight = spriteRight;
_spriteBottom = spriteBottom;
if (operation != DRAW_PRINTTEXT)
_destSpriteX = destSpriteX;
_destSpriteY = destSpriteY;
_destSurface = destSurface;
_sourceSurface = sourceSurface;
if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) {
if (_sourceSurface == kBackSurface) {
_spriteLeft -= _backDeltaX;
_spriteTop -= _backDeltaY;
}
if (_destSurface == kBackSurface) {
_destSpriteX -= _backDeltaX;
_destSpriteY -= _backDeltaY;
}
}
}
/* WORKAROUND: Fix wrong German animal names in Once Upon A Time: Little Red Riding Hood.
*
* The DOS, Amiga and Atari version of Little Red come with a small screen, accessible
* through the main menu, that lets children read and listen to animal names in 5
* languages: French, German, English, Spanish and Italian.
* Unfortunately, the German names are partially wrong. This is especially tragic
* because this is a game for small children and they're supposed to learn something
* here. We fix this.
*
* However, there's also problems with the recorded spoken German names:
* - "Der Rabe" has a far too short "a", sounding more like "Rabbe"
* - The wrong article for "Schmetterling" is very audible
* - In general, the words are way too overpronounced
* These are, of course, way harder to fix.
*/
static const char *kLittleRedStrings[][2] = {
{"die Heule" , "die Eule"},
{"das Schmetterling" , "der Schmetterling"},
{"die Vespe" , "die Wespe"},
{"das Eich\224rnchen" , "das Eichh\224rnchen"}
};
void Draw_v2::fixLittleRedStrings() {
if (!_textToPrint || (_vm->getGameType() != kGameTypeLittleRed))
return;
for (int i = 0; i < ARRAYSIZE(kLittleRedStrings); i++) {
if (!strcmp(_textToPrint, kLittleRedStrings[i][0])) {
_textToPrint = kLittleRedStrings[i][1];
return;
}
}
}
} // End of namespace Gob