scummvm/engines/gob/draw_v7.cpp
Simon Delamarre 8bb49c1acf GOB: fix cursor still visible in breakout game of some Adibou2 versions
Only cursors drawn from scripts must be copied in _cursorSprites, not the ones loaded from executable.
This simplifies a lot of globals from the Draw object, that were needed only in the cursor-from-exec case.

Note: other GOB games are not impacted even if shared code from draw_v2.cpp, inter_v1.cpp is modified (_cursorHotspotsX and _doCursorPalettes are non-null only in Adibou 2).
2023-01-12 23:26:40 +01:00

278 lines
8 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/formats/winexe_ne.h"
#include "common/formats/winexe_pe.h"
#include "graphics/cursorman.h"
#include "graphics/wincursor.h"
#include "gob/dataio.h"
#include "gob/draw.h"
#include "gob/game.h"
#include "gob/global.h"
#include "gob/hotspots.h"
#include "gob/inter.h"
#include "gob/resources.h"
#include "gob/scenery.h"
#include "gob/script.h"
namespace Gob {
Draw_v7::Draw_v7(GobEngine *vm) : Draw_Playtoons(vm), _cursors(nullptr) {
}
Draw_v7::~Draw_v7() {
delete _cursors;
}
bool Draw_v7::loadCursorFile() {
if (_cursors)
return true;
if (_vm->_dataIO->hasFile("cursor32.dll")) {
_cursors = new Common::PEResources();
if (_cursors->loadFromEXE("cursor32.dll"))
return true;
} else if (_vm->_dataIO->hasFile("cursor.dll")) {
_cursors = new Common::NEResources();
if (_cursors->loadFromEXE("cursor.dll"))
return true;
}
delete _cursors;
_cursors = nullptr;
return false;
}
bool Draw_v7::loadCursorFromFile(Common::String cursorName) {
Graphics::WinCursorGroup *cursorGroup = nullptr;
Graphics::Cursor *defaultCursor = nullptr;
// Load the cursor file and cursor group
if (loadCursorFile())
cursorGroup = Graphics::WinCursorGroup::createCursorGroup(_cursors, Common::WinResourceID(cursorName));
// If the requested cursor does not exist, create a default one
const Graphics::Cursor *cursor = nullptr;
if (!cursorGroup || cursorGroup->cursors.empty() || !cursorGroup->cursors[0].cursor) {
defaultCursor = Graphics::makeDefaultWinCursor();
cursor = defaultCursor;
} else
cursor = cursorGroup->cursors[0].cursor;
// Make sure the cursor sprite is big enough
if (_scummvmCursor->getWidth() != cursor->getWidth() || _scummvmCursor->getHeight() != cursor->getHeight()) {
_vm->_draw->_scummvmCursor.reset();
_vm->_draw->_scummvmCursor = _vm->_video->initSurfDesc(cursor->getWidth(), cursor->getHeight(), SCUMMVM_CURSOR);
}
_scummvmCursor->clear();
Surface cursorSurf(cursor->getWidth(), cursor->getHeight(), 1, cursor->getSurface());
_scummvmCursor->blit(cursorSurf, 0, 0);
CursorMan.replaceCursor(_scummvmCursor->getData(),
cursor->getWidth(),
cursor->getHeight(),
cursor->getHotspotX(),
cursor->getHotspotY(),
cursor->getKeyColor(),
false,
&_vm->getPixelFormat());
CursorMan.replaceCursorPalette(cursor->getPalette(),
cursor->getPaletteStartIndex(),
cursor->getPaletteCount());
CursorMan.disableCursorPalette(false);
delete cursorGroup;
delete defaultCursor;
return true;
}
void Draw_v7::initScreen()
{
_vm->_game->_preventScroll = false;
_scrollOffsetX = 0;
_scrollOffsetY = 0;
if (!_spritesArray[kBackSurface] || _vm->_global->_videoMode != 0x18) {
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_v7::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) {
// --- Advance cursor animation
// TODO: Not sure if this is still valid in Adibou2/Adi4
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 { // Not found in Adibou 2 ASM
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;
}
// '------
if (cursorIndex == -1)
return;
bool cursorChanged = _cursorNames[cursorIndex] != _cursorName;
if ((!_cursorDrawnFromScripts || !_cursorNames[cursorIndex].empty()) && cursorChanged) {
_cursorName = _cursorNames[cursorIndex];
// If the cursor name is empty, that cursor will be drawn by the scripts
if (_cursorNames[cursorIndex].empty() || _cursorNames[cursorIndex] == "VIDE") { // "VIDE" is "empty" in french
for (int i = 0; i < 40; i++) {
_cursorNames[i].clear();
}
_cursorDrawnFromScripts = true;
_cursorX = _vm->_global->_inter_mouseX;
_cursorY = _vm->_global->_inter_mouseY;
_showCursor &= ~1;
return;
} else {
_cursorDrawnFromScripts = false;
loadCursorFromFile(_cursorName);
_cursorX = _vm->_global->_inter_mouseX;
_cursorY = _vm->_global->_inter_mouseY;
}
}
if (_cursorDrawnFromScripts) {
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;
if (_scummvmCursor->getWidth() != _cursorWidth || _scummvmCursor->getHeight() != _cursorHeight) {
_vm->_draw->_scummvmCursor.reset();
_vm->_draw->_scummvmCursor = _vm->_video->initSurfDesc(_cursorWidth, _cursorHeight, SCUMMVM_CURSOR);
}
_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);
}
}
if (!cursorChanged && !_cursorDrawnFromScripts)
return;
} else {
blitCursor();
_cursorX = newX;
_cursorY = newY;
}
_showCursor &= ~1;
}
} // End of namespace Gob