mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-05 09:10:29 +00:00
1707 lines
36 KiB
C++
1707 lines
36 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 2
|
||
|
* 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, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
*
|
||
|
* $URL$
|
||
|
* $Id$
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "gob/hotspots.h"
|
||
|
#include "gob/global.h"
|
||
|
#include "gob/helper.h"
|
||
|
#include "gob/draw.h"
|
||
|
#include "gob/game.h"
|
||
|
#include "gob/script.h"
|
||
|
#include "gob/inter.h"
|
||
|
|
||
|
namespace Gob {
|
||
|
|
||
|
Hotspots::Hotspot::Hotspot() {
|
||
|
clear();
|
||
|
}
|
||
|
|
||
|
Hotspots::Hotspot::Hotspot(uint16 i,
|
||
|
uint16 l, uint16 t, uint16 r, uint16 b, uint16 f, uint16 k,
|
||
|
uint16 enter, uint16 leave, uint16 pos) {
|
||
|
|
||
|
id = i;
|
||
|
left = l;
|
||
|
top = t;
|
||
|
right = r;
|
||
|
bottom = b;
|
||
|
flags = f;
|
||
|
key = k;
|
||
|
funcEnter = enter;
|
||
|
funcLeave = leave;
|
||
|
funcPos = pos;
|
||
|
script = 0;
|
||
|
}
|
||
|
|
||
|
void Hotspots::Hotspot::clear() {
|
||
|
id = 0;
|
||
|
left = 0xFFFF;
|
||
|
top = 0;
|
||
|
right = 0;
|
||
|
bottom = 0;
|
||
|
flags = 0;
|
||
|
key = 0;
|
||
|
funcEnter = 0;
|
||
|
funcLeave = 0;
|
||
|
funcPos = 0;
|
||
|
script = 0;
|
||
|
}
|
||
|
|
||
|
Hotspots::Type Hotspots::Hotspot::getType() const {
|
||
|
return (Type) (flags & 0xF);
|
||
|
}
|
||
|
|
||
|
MouseButtons Hotspots::Hotspot::getButton() const {
|
||
|
uint8 buttonBits = ((flags & 0x70) >> 4);
|
||
|
|
||
|
if (buttonBits == 0)
|
||
|
return kMouseButtonsLeft;
|
||
|
if (buttonBits == 1)
|
||
|
return kMouseButtonsRight;
|
||
|
if (buttonBits == 2)
|
||
|
return kMouseButtonsAny;
|
||
|
|
||
|
return kMouseButtonsNone;
|
||
|
}
|
||
|
|
||
|
uint8 Hotspots::Hotspot::getWindow() const {
|
||
|
return (flags & 0x0F00) >> 8;
|
||
|
}
|
||
|
|
||
|
uint8 Hotspots::Hotspot::getCursor() const {
|
||
|
return (flags & 0xF000) >> 12;
|
||
|
}
|
||
|
|
||
|
bool Hotspots::Hotspot::isIn(uint16 x, uint16 y) const {
|
||
|
if (x < left)
|
||
|
return false;
|
||
|
if (x > right)
|
||
|
return false;
|
||
|
if (y < top)
|
||
|
return false;
|
||
|
if (y > bottom)
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Hotspots::Hotspot::buttonMatch(MouseButtons button) const {
|
||
|
MouseButtons myButton = getButton();
|
||
|
|
||
|
if (myButton == kMouseButtonsAny)
|
||
|
return true;
|
||
|
|
||
|
if (myButton == kMouseButtonsNone)
|
||
|
return false;
|
||
|
|
||
|
if (myButton == button)
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
Hotspots::Hotspots(GobEngine *vm) : _vm(vm) {
|
||
|
_hotspots = new Hotspot[kHotspotCount];
|
||
|
|
||
|
_shouldPush = false;
|
||
|
|
||
|
_currentKey = 0;
|
||
|
_currentIndex = 0;
|
||
|
_currentId = 0;
|
||
|
}
|
||
|
|
||
|
Hotspots::~Hotspots() {
|
||
|
delete[] _hotspots;
|
||
|
|
||
|
while (!_stack.empty()) {
|
||
|
StackEntry backup = _stack.pop();
|
||
|
|
||
|
delete[] backup.hotspots;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Hotspots::clear() {
|
||
|
_currentKey = 0;
|
||
|
|
||
|
for (int i = 0; i < kHotspotCount; i++)
|
||
|
_hotspots[i].clear();
|
||
|
}
|
||
|
|
||
|
uint16 Hotspots::add(uint16 id,
|
||
|
uint16 left, uint16 top, uint16 right, uint16 bottom,
|
||
|
uint16 flags, uint16 key,
|
||
|
uint16 funcEnter, uint16 funcLeave, uint16 funcPos) {
|
||
|
|
||
|
Hotspot hotspot(id, left, top, right, bottom,
|
||
|
flags, key, funcEnter, funcLeave, funcPos);
|
||
|
|
||
|
return add(hotspot);
|
||
|
}
|
||
|
|
||
|
uint16 Hotspots::add(const Hotspot &hotspot) {
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
// free space => add same id => update
|
||
|
if (! ((spot.left == 0xFFFF) || (spot.id == hotspot.id)))
|
||
|
continue;
|
||
|
|
||
|
// When updating, keep bit 0x4000 intact
|
||
|
uint16 id = hotspot.id;
|
||
|
if ((spot.id & 0xBFFF) == (hotspot.id & 0xBFFF))
|
||
|
id = spot.id;
|
||
|
|
||
|
// Set
|
||
|
spot = hotspot;
|
||
|
spot.id = id;
|
||
|
|
||
|
// Remember the current script
|
||
|
spot.script = _vm->_game->_script;
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
error("Hotspots::add(): Hotspot array full");
|
||
|
return 0xFFFF;
|
||
|
}
|
||
|
|
||
|
void Hotspots::remove(uint16 id) {
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
if (_hotspots[i].id == id)
|
||
|
_hotspots[i].clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Hotspots::removeState(uint16 state) {
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if ((spot.id & 0xF000) == state)
|
||
|
spot.clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Hotspots::recalculate(bool force) {
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
// End reached
|
||
|
break;
|
||
|
|
||
|
if (!force && ((spot.flags & 0x80) != 0))
|
||
|
continue;
|
||
|
|
||
|
if (spot.funcPos == 0)
|
||
|
continue;
|
||
|
|
||
|
// Setting the needed script
|
||
|
Script *curScript = _vm->_game->_script;
|
||
|
|
||
|
_vm->_game->_script = spot.script;
|
||
|
if (!_vm->_game->_script)
|
||
|
_vm->_game->_script = curScript;
|
||
|
|
||
|
// Calling the function that contains the positions
|
||
|
_vm->_game->_script->call(spot.funcPos);
|
||
|
|
||
|
// Calculate positions
|
||
|
int16 left = _vm->_game->_script->readValExpr();
|
||
|
int16 top = _vm->_game->_script->readValExpr();
|
||
|
int16 width = _vm->_game->_script->readValExpr();
|
||
|
int16 height = _vm->_game->_script->readValExpr();
|
||
|
|
||
|
// Re-read the flags too, if applicable
|
||
|
uint16 flags = 0;
|
||
|
if ((spot.id & 0xF000) == 0xA000)
|
||
|
flags = _vm->_game->_script->readValExpr();
|
||
|
|
||
|
// Apply backDelta, if needed
|
||
|
if ((_vm->_draw->_renderFlags & RENDERFLAG_CAPTUREPOP) && (left != -1)) {
|
||
|
left += _vm->_draw->_backDeltaX;
|
||
|
top += _vm->_draw->_backDeltaY;
|
||
|
}
|
||
|
|
||
|
// Clamping
|
||
|
if (left < 0) {
|
||
|
width += left;
|
||
|
left = 0;
|
||
|
}
|
||
|
if (top < 0) {
|
||
|
height += top;
|
||
|
top = 0;
|
||
|
}
|
||
|
|
||
|
// Set the updated position
|
||
|
spot.left = left;
|
||
|
spot.top = top;
|
||
|
spot.right = left + width - 1;
|
||
|
spot.bottom = top + height - 1;
|
||
|
|
||
|
if ((spot.id & 0xF000) == 0xA000)
|
||
|
spot.flags = flags;
|
||
|
|
||
|
// Return
|
||
|
_vm->_game->_script->pop();
|
||
|
|
||
|
_vm->_game->_script = curScript;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Hotspots::push(uint8 all, bool force) {
|
||
|
// Should we push at all?
|
||
|
if (!_shouldPush && !force)
|
||
|
return;
|
||
|
|
||
|
// Count the hotspots
|
||
|
uint32 size = 0;
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
// End reached
|
||
|
break;
|
||
|
|
||
|
// Save all of them
|
||
|
if ( (all == 1) ||
|
||
|
// Don't save the global ones
|
||
|
((all == 0) && (spot.id >= 20)) ||
|
||
|
// Only save the ones with the correct state
|
||
|
((all == 2) && (((spot.id & 0xF000) == 0xD000) ||
|
||
|
((spot.id & 0xF000) == 0x4000) ||
|
||
|
((spot.id & 0xF000) == 0xE000)))) {
|
||
|
size++;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
StackEntry backup;
|
||
|
|
||
|
backup.shouldPush = _shouldPush;
|
||
|
backup.size = size;
|
||
|
backup.key = _currentKey;
|
||
|
backup.id = _currentId;
|
||
|
backup.index = _currentIndex;
|
||
|
|
||
|
backup.hotspots = new Hotspot[size];
|
||
|
|
||
|
// Copy the hotspots
|
||
|
Hotspot *destPtr = backup.hotspots;
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
// End reached
|
||
|
break;
|
||
|
|
||
|
// Save all of them
|
||
|
if ( (all == 1) ||
|
||
|
// Don't save the global ones
|
||
|
((all == 0) && (spot.id >= 20)) ||
|
||
|
// Only save the ones with the correct state
|
||
|
((all == 2) && (((spot.id & 0xF000) == 0xD000) ||
|
||
|
((spot.id & 0xF000) == 0x4000) ||
|
||
|
((spot.id & 0xF000) == 0xE000)))) {
|
||
|
|
||
|
memcpy(destPtr, &spot, sizeof(Hotspot));
|
||
|
destPtr++;
|
||
|
|
||
|
spot.left = 0xFFFF;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Reset current state
|
||
|
_shouldPush = false;
|
||
|
_currentKey = 0;
|
||
|
_currentId = 0;
|
||
|
_currentIndex = 0;
|
||
|
|
||
|
_stack.push(backup);
|
||
|
}
|
||
|
|
||
|
void Hotspots::pop() {
|
||
|
assert(!_stack.empty());
|
||
|
|
||
|
StackEntry backup = _stack.pop();
|
||
|
|
||
|
// Find the end of the filled hotspot space
|
||
|
int i;
|
||
|
Hotspot *destPtr = _hotspots;
|
||
|
for (i = 0; i < kHotspotCount; i++, destPtr++)
|
||
|
if (destPtr->left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if (((uint32) (kHotspotCount - i)) < backup.size)
|
||
|
error("Hotspots::pop(): Not enough free space in the current Hotspot "
|
||
|
"array to pop %d elements (got %d)", backup.size, kHotspotCount - i);
|
||
|
|
||
|
memcpy(destPtr, backup.hotspots, backup.size * sizeof(Hotspot));
|
||
|
|
||
|
_shouldPush = backup.shouldPush;
|
||
|
_currentKey = backup.key;
|
||
|
_currentId = backup.id;
|
||
|
_currentIndex = backup.index;
|
||
|
|
||
|
delete[] backup.hotspots;
|
||
|
}
|
||
|
|
||
|
bool Hotspots::isValid(uint16 key, uint16 id, uint16 index) const {
|
||
|
if (index >= kHotspotCount)
|
||
|
return false;
|
||
|
|
||
|
if (key == 0)
|
||
|
return false;
|
||
|
|
||
|
if (!(id & 0x8000))
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void Hotspots::call(uint16 offset) {
|
||
|
_vm->_game->_script->call(offset);
|
||
|
|
||
|
_shouldPush = true;
|
||
|
|
||
|
int16 stackSize = _stack.size();
|
||
|
|
||
|
_vm->_inter->funcBlock(0);
|
||
|
|
||
|
while (stackSize != _stack.size())
|
||
|
pop();
|
||
|
|
||
|
_shouldPush = false;
|
||
|
|
||
|
_vm->_game->_script->pop();
|
||
|
|
||
|
recalculate(false);
|
||
|
}
|
||
|
|
||
|
void Hotspots::enter(uint16 index) {
|
||
|
if (index >= kHotspotCount) {
|
||
|
warning("Hotspots::enter(): Index %d out of range", index);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Hotspot &spot = _hotspots[index];
|
||
|
|
||
|
if (((spot.id & 0xF000) == 0xA000) || ((spot.id & 0xF000) == 0x9000))
|
||
|
WRITE_VAR(17, -(spot.id & 0x0FFF));
|
||
|
|
||
|
if (spot.funcEnter != 0)
|
||
|
call(spot.funcEnter);
|
||
|
}
|
||
|
|
||
|
void Hotspots::leave(uint16 index) {
|
||
|
if (index >= kHotspotCount) {
|
||
|
warning("Hotspots::leave(): Index %d out of range", index);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Hotspot &spot = _hotspots[index];
|
||
|
|
||
|
if (((spot.id & 0xF000) == 0xA000) || ((spot.id & 0xF000) == 0x9000))
|
||
|
WRITE_VAR(17, spot.id & 0x0FFF);
|
||
|
|
||
|
if (spot.funcLeave != 0)
|
||
|
call(spot.funcLeave);
|
||
|
}
|
||
|
|
||
|
uint16 Hotspots::checkMouse(Type type, uint16 &id, uint16 &index) const {
|
||
|
id = 0;
|
||
|
index = 0;
|
||
|
|
||
|
if (type == kTypeMove) {
|
||
|
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if (spot.id & 0x4000)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() > kTypeMove)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getWindow() != 0)
|
||
|
continue;
|
||
|
|
||
|
if (!spot.isIn(_vm->_global->_inter_mouseX, _vm->_global->_inter_mouseY))
|
||
|
continue;
|
||
|
|
||
|
id = spot.id;
|
||
|
index = i;
|
||
|
|
||
|
return spot.key;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
} else if (type == kTypeClick) {
|
||
|
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if (spot.id & 0x4000)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getWindow() != 0)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() < kTypeMove)
|
||
|
continue;
|
||
|
|
||
|
if (!spot.isIn(_vm->_global->_inter_mouseX, _vm->_global->_inter_mouseY))
|
||
|
continue;
|
||
|
|
||
|
if (!spot.buttonMatch(_vm->_game->_mouseButtons))
|
||
|
continue;
|
||
|
|
||
|
id = spot.id;
|
||
|
index = i;
|
||
|
|
||
|
if ((spot.getType() == kTypeMove) || (spot.getType() == kTypeClick))
|
||
|
return spot.key;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (_vm->_game->_mouseButtons != kMouseButtonsLeft)
|
||
|
return kKeyEscape;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void Hotspots::checkHotspotChanged() {
|
||
|
uint16 key, id, index;
|
||
|
|
||
|
key = checkMouse(kTypeMove, id, index);
|
||
|
|
||
|
if (key == _currentKey)
|
||
|
return;
|
||
|
|
||
|
if (isValid(_currentKey, _currentId, _currentIndex))
|
||
|
leave(_currentIndex);
|
||
|
|
||
|
_currentKey = key;
|
||
|
_currentId = id;
|
||
|
_currentIndex = index;
|
||
|
|
||
|
if (isValid(key, id, index))
|
||
|
enter(index);
|
||
|
}
|
||
|
|
||
|
uint16 Hotspots::check(uint8 handleMouse, int16 delay, uint16 &id, uint16 &index) {
|
||
|
_vm->_game->_scrollHandleMouse = handleMouse != 0;
|
||
|
|
||
|
if (delay >= -1) {
|
||
|
_currentKey = 0;
|
||
|
_currentId = 0;
|
||
|
_currentIndex = 0;
|
||
|
}
|
||
|
|
||
|
id = 0;
|
||
|
index = 0;
|
||
|
|
||
|
if (handleMouse) {
|
||
|
if ((_vm->_draw->_cursorIndex == -1) && (_currentKey == 0)) {
|
||
|
_currentKey = checkMouse(kTypeMove, _currentId, _currentIndex);
|
||
|
|
||
|
if (isValid(_currentKey, _currentId, _currentIndex))
|
||
|
enter(_currentIndex);
|
||
|
}
|
||
|
|
||
|
_vm->_draw->animateCursor(-1);
|
||
|
}
|
||
|
|
||
|
uint32 startTime = _vm->_util->getTimeKey();
|
||
|
|
||
|
_vm->_draw->blitInvalidated();
|
||
|
_vm->_video->retrace();
|
||
|
|
||
|
uint16 key = 0;
|
||
|
while (key == 0) {
|
||
|
|
||
|
if (_vm->_inter->_terminate || _vm->shouldQuit()) {
|
||
|
if (handleMouse)
|
||
|
_vm->_draw->blitCursor();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
checkHotspotChanged();
|
||
|
|
||
|
if (!_vm->_draw->_noInvalidated) {
|
||
|
if (handleMouse)
|
||
|
_vm->_draw->animateCursor(-1);
|
||
|
else
|
||
|
_vm->_draw->blitInvalidated();
|
||
|
_vm->_video->waitRetrace();
|
||
|
}
|
||
|
|
||
|
key = _vm->_game->checkKeys(&_vm->_global->_inter_mouseX,
|
||
|
&_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons, handleMouse);
|
||
|
|
||
|
if (!handleMouse && (_vm->_game->_mouseButtons != kMouseButtonsNone)) {
|
||
|
_vm->_util->waitMouseRelease(0);
|
||
|
key = 3;
|
||
|
}
|
||
|
|
||
|
if (key != 0) {
|
||
|
if (handleMouse & 1)
|
||
|
_vm->_draw->blitCursor();
|
||
|
|
||
|
id = 0;
|
||
|
index = 0;
|
||
|
|
||
|
if (isValid(_currentKey, _currentId, _currentIndex))
|
||
|
leave(_currentIndex);
|
||
|
|
||
|
_currentKey = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (handleMouse) {
|
||
|
|
||
|
if (_vm->_game->_mouseButtons != kMouseButtonsNone) {
|
||
|
|
||
|
if (delay > 0) {
|
||
|
_vm->_draw->animateCursor(2);
|
||
|
_vm->_util->delay(delay);
|
||
|
} else if (handleMouse & 1)
|
||
|
_vm->_util->waitMouseRelease(1);
|
||
|
|
||
|
_vm->_draw->animateCursor(-1);
|
||
|
|
||
|
key = checkMouse(kTypeClick, id, index);
|
||
|
|
||
|
if ((key != 0) || (id != 0)) {
|
||
|
if ( (handleMouse & 1) &&
|
||
|
((delay <= 0) || (_vm->_game->_mouseButtons == kMouseButtonsNone)))
|
||
|
_vm->_draw->blitCursor();
|
||
|
|
||
|
if (key != _currentKey)
|
||
|
leave(_currentIndex);
|
||
|
|
||
|
_currentKey = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (handleMouse & 4)
|
||
|
return 0;
|
||
|
|
||
|
if (_currentKey != 0)
|
||
|
leave(_currentIndex);
|
||
|
|
||
|
_currentKey = checkMouse(kTypeMove, _currentId, _currentIndex);
|
||
|
if (isValid(_currentKey, _currentId, _currentIndex))
|
||
|
enter(_currentIndex);
|
||
|
|
||
|
} else
|
||
|
checkHotspotChanged();
|
||
|
|
||
|
}
|
||
|
|
||
|
if ((delay == -2) && (key == 0) &&
|
||
|
(_vm->_game->_mouseButtons == kMouseButtonsNone)) {
|
||
|
|
||
|
id = 0;
|
||
|
index = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (handleMouse)
|
||
|
_vm->_draw->animateCursor(-1);
|
||
|
|
||
|
if ((delay < 0) && (key == 0) &&
|
||
|
(_vm->_game->_mouseButtons == kMouseButtonsNone)) {
|
||
|
|
||
|
uint32 curTime = _vm->_util->getTimeKey();
|
||
|
// Timeout reached?
|
||
|
if ((curTime + delay) > startTime) {
|
||
|
id = 0;
|
||
|
index = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
_vm->_util->delay(10);
|
||
|
|
||
|
}
|
||
|
|
||
|
return key;
|
||
|
}
|
||
|
|
||
|
uint16 Hotspots::check(uint8 handleMouse, int16 delay) {
|
||
|
uint16 id, index;
|
||
|
|
||
|
return Hotspots::check(handleMouse, delay, id, index);
|
||
|
}
|
||
|
|
||
|
uint16 Hotspots::readString(uint16 xPos, uint16 yPos, uint16 width, uint16 height,
|
||
|
uint16 backColor, uint16 frontColor, char *str, uint16 fontIndex,
|
||
|
Type type, int16 &duration, uint16 &id, uint16 index) {
|
||
|
|
||
|
if ((fontIndex >= 8) || !_vm->_draw->_fonts[fontIndex])
|
||
|
return 0;
|
||
|
|
||
|
bool handleMouse = false;
|
||
|
if ( (_vm->_game->_handleMouse != 0) &&
|
||
|
((_vm->_global->_useMouse != 0) || (_vm->_game->_forceHandleMouse != 0)))
|
||
|
handleMouse = true;
|
||
|
|
||
|
Video::FontDesc &font = *_vm->_draw->_fonts[fontIndex];
|
||
|
|
||
|
bool monoSpaced = (font.extraData == 0);
|
||
|
|
||
|
uint32 pos = strlen(str);
|
||
|
uint32 editSize = monoSpaced ? 0 : (width / font.itemWidth);
|
||
|
|
||
|
uint16 key = 0;
|
||
|
char tempStr[256];
|
||
|
|
||
|
while (1) {
|
||
|
strncpy0(tempStr, str, 254);
|
||
|
strcat(tempStr, " ");
|
||
|
if ((editSize != 0) && strlen(tempStr) > editSize)
|
||
|
strncpy0(tempStr, str, 255);
|
||
|
|
||
|
_vm->_draw->_destSpriteX = xPos;
|
||
|
_vm->_draw->_destSpriteY = yPos;
|
||
|
_vm->_draw->_spriteRight = monoSpaced ? (editSize * font.itemWidth) : width;
|
||
|
_vm->_draw->_spriteBottom = height;
|
||
|
|
||
|
_vm->_draw->_destSurface = 21;
|
||
|
_vm->_draw->_backColor = backColor;
|
||
|
_vm->_draw->_frontColor = frontColor;
|
||
|
_vm->_draw->_textToPrint = tempStr;
|
||
|
_vm->_draw->_transparency = 1;
|
||
|
_vm->_draw->_fontIndex = fontIndex;
|
||
|
_vm->_draw->spriteOperation(DRAW_FILLRECT | 0x10 );
|
||
|
|
||
|
_vm->_draw->_destSpriteY = yPos + (height - font.itemHeight) / 2;
|
||
|
_vm->_draw->spriteOperation(DRAW_PRINTTEXT | 0x10);
|
||
|
|
||
|
if ((editSize != 0) && (pos == editSize))
|
||
|
pos--;
|
||
|
|
||
|
char curSym = tempStr[pos];
|
||
|
|
||
|
if (_vm->_inter->_variables)
|
||
|
WRITE_VAR(56, pos);
|
||
|
|
||
|
bool first = true;
|
||
|
while (1) {
|
||
|
tempStr[0] = curSym;
|
||
|
tempStr[1] = 0;
|
||
|
|
||
|
if (font.extraData) {
|
||
|
_vm->_draw->_destSpriteY = yPos;
|
||
|
_vm->_draw->_spriteBottom = height;
|
||
|
_vm->_draw->_spriteRight = 1;
|
||
|
|
||
|
_vm->_draw->_destSpriteX = xPos;
|
||
|
for (uint32 j = 0; j < pos; j++)
|
||
|
_vm->_draw->_destSpriteX += font.extraData[str[j] - font.startItem];
|
||
|
|
||
|
} else {
|
||
|
_vm->_draw->_destSpriteX = xPos + font.itemWidth * pos;
|
||
|
_vm->_draw->_destSpriteY = yPos + height - 1;
|
||
|
_vm->_draw->_spriteRight = font.itemWidth;
|
||
|
_vm->_draw->_spriteBottom = 1;
|
||
|
}
|
||
|
|
||
|
_vm->_draw->_destSurface = 21;
|
||
|
_vm->_draw->_backColor = frontColor;
|
||
|
_vm->_draw->spriteOperation(DRAW_FILLRECT | 0x10);
|
||
|
|
||
|
if (first) {
|
||
|
key = check(handleMouse, -1, id, index);
|
||
|
|
||
|
if (key == 0)
|
||
|
key = check(handleMouse, -300, id, index);
|
||
|
|
||
|
first = false;
|
||
|
} else
|
||
|
key = check(handleMouse, -300, id, index);
|
||
|
|
||
|
tempStr[0] = curSym;
|
||
|
tempStr[1] = 0;
|
||
|
|
||
|
if (font.extraData) {
|
||
|
_vm->_draw->_destSpriteY = yPos;
|
||
|
_vm->_draw->_spriteBottom = height;
|
||
|
_vm->_draw->_spriteRight = 1;
|
||
|
|
||
|
_vm->_draw->_destSpriteX = xPos;
|
||
|
for (uint32 j = 0; j < pos; j++)
|
||
|
_vm->_draw->_destSpriteX += font.extraData[str[j] - font.startItem];
|
||
|
|
||
|
} else {
|
||
|
_vm->_draw->_destSpriteX = xPos + font.itemWidth * pos;
|
||
|
_vm->_draw->_destSpriteY = yPos + height - 1;
|
||
|
_vm->_draw->_spriteRight = font.itemWidth;
|
||
|
_vm->_draw->_spriteBottom = 1;
|
||
|
}
|
||
|
|
||
|
_vm->_draw->_destSurface = 21;
|
||
|
_vm->_draw->_backColor = backColor;
|
||
|
_vm->_draw->_frontColor = frontColor;
|
||
|
_vm->_draw->_textToPrint = tempStr;
|
||
|
_vm->_draw->_transparency = 1;
|
||
|
_vm->_draw->_fontIndex = fontIndex;
|
||
|
_vm->_draw->spriteOperation(DRAW_FILLRECT | 0x10);
|
||
|
|
||
|
_vm->_draw->_destSpriteY = yPos + (height - font.itemHeight) / 2;
|
||
|
_vm->_draw->spriteOperation(DRAW_PRINTTEXT | 0x10);
|
||
|
|
||
|
if ((key != 0) || (id != 0))
|
||
|
break;
|
||
|
|
||
|
key = check(handleMouse, -300, id, index);
|
||
|
|
||
|
if ((key != 0) || (id != 0) ||
|
||
|
_vm->_inter->_terminate || _vm->shouldQuit())
|
||
|
break;
|
||
|
|
||
|
if (duration > 0) {
|
||
|
duration -= 600;
|
||
|
if (duration <= 1) {
|
||
|
key = 0;
|
||
|
id = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((key == 0) || (id != 0) ||
|
||
|
_vm->_inter->_terminate || _vm->shouldQuit())
|
||
|
return 0;
|
||
|
|
||
|
switch (key) {
|
||
|
case kKeyRight:
|
||
|
if ((pos > strlen(str)) || (pos > (editSize - 1)) || (editSize == 0)) {
|
||
|
pos++;
|
||
|
continue;
|
||
|
}
|
||
|
return kKeyDown;
|
||
|
|
||
|
case kKeyLeft:
|
||
|
if (pos > 0) {
|
||
|
pos--;
|
||
|
continue;
|
||
|
}
|
||
|
return kKeyUp;
|
||
|
|
||
|
case kKeyBackspace:
|
||
|
if (pos > 0) {
|
||
|
_vm->_util->cutFromStr(str, pos - 1, 1);
|
||
|
pos--;
|
||
|
continue;
|
||
|
} else {
|
||
|
if (pos < strlen(str))
|
||
|
_vm->_util->cutFromStr(str, pos, 1);
|
||
|
}
|
||
|
|
||
|
case kKeyDelete:
|
||
|
if (pos >= strlen(str))
|
||
|
continue;
|
||
|
|
||
|
_vm->_util->cutFromStr(str, pos, 1);
|
||
|
continue;
|
||
|
|
||
|
case kKeyReturn:
|
||
|
case kKeyF1:
|
||
|
case kKeyF2:
|
||
|
case kKeyF3:
|
||
|
case kKeyF4:
|
||
|
case kKeyF5:
|
||
|
case kKeyF6:
|
||
|
case kKeyF7:
|
||
|
case kKeyF8:
|
||
|
case kKeyF9:
|
||
|
case kKeyF10:
|
||
|
case kKeyUp:
|
||
|
case kKeyDown:
|
||
|
return key;
|
||
|
|
||
|
case kKeyEscape:
|
||
|
if (_vm->_global->_useMouse != 0)
|
||
|
continue;
|
||
|
|
||
|
_vm->_game->_forceHandleMouse = !_vm->_game->_forceHandleMouse;
|
||
|
|
||
|
handleMouse = false;
|
||
|
if ( (_vm->_game->_handleMouse != 0) &&
|
||
|
((_vm->_global->_useMouse != 0) || (_vm->_game->_forceHandleMouse != 0)))
|
||
|
handleMouse = true;
|
||
|
|
||
|
while (_vm->_global->_pressedKeys[1] != 0)
|
||
|
;
|
||
|
continue;
|
||
|
|
||
|
default:
|
||
|
uint16 savedKey = key;
|
||
|
|
||
|
key &= 0xFF;
|
||
|
|
||
|
if (((type == kTypeInputFloatNoLeave) || (type == kTypeInputFloatLeave)) &&
|
||
|
(key >= ' ') && (key <= 0xFF)) {
|
||
|
const char *str1 = "0123456789-.,+ ";
|
||
|
const char *str2 = "0123456789-,,+ ";
|
||
|
|
||
|
if ((((savedKey >> 8) > 1) && ((savedKey >> 8) < 12)) &&
|
||
|
((_vm->_global->_pressedKeys[42] != 0) ||
|
||
|
(_vm->_global->_pressedKeys[56] != 0)))
|
||
|
key = ((savedKey >> 8) - 1) % 10 + '0';
|
||
|
|
||
|
int i;
|
||
|
for (i = 0; str1[i] != 0; i++) {
|
||
|
if (key == str1[i]) {
|
||
|
key = str2[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i == (int16) strlen(str1))
|
||
|
key = 0;
|
||
|
}
|
||
|
|
||
|
if ((key >= ' ') && (key <= 0xFF)) {
|
||
|
if (editSize == 0) {
|
||
|
int length = _vm->_draw->stringLength(str, fontIndex) +
|
||
|
font.extraData[' ' - font.startItem] +
|
||
|
font.extraData[key - font.startItem];
|
||
|
|
||
|
if (length > width)
|
||
|
continue;
|
||
|
|
||
|
if (((int32) strlen(str)) >= (_vm->_global->_inter_animDataSize * 4 - 1))
|
||
|
continue;
|
||
|
|
||
|
} else {
|
||
|
if (strlen(str) > editSize)
|
||
|
continue;
|
||
|
else if (editSize == strlen(str))
|
||
|
_vm->_util->cutFromStr(str, strlen(str) - 1, 1);
|
||
|
}
|
||
|
|
||
|
pos++;
|
||
|
tempStr[0] = key;
|
||
|
tempStr[1] = 0;
|
||
|
|
||
|
_vm->_util->insertStr(tempStr, str, pos - 1);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint16 Hotspots::handleInput(int16 time, uint16 maxPos, uint16 &curPos,
|
||
|
InputDesc *inpDesc, uint16 &id, uint16 &index) {
|
||
|
|
||
|
uint16 descInd = 0;
|
||
|
uint16 key = 0;
|
||
|
uint16 found = 0xFFFF;
|
||
|
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
continue;
|
||
|
|
||
|
if ((spot.id & 0xC000) != 0x8000)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() < kTypeInput1NoLeave)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() > kTypeInputFloatLeave)
|
||
|
continue;
|
||
|
|
||
|
char tempStr[256];
|
||
|
strncpy0(tempStr, GET_VARO_STR(spot.key), 255);
|
||
|
|
||
|
_vm->_draw->_destSpriteX = spot.left;
|
||
|
_vm->_draw->_destSpriteY = spot.top;
|
||
|
_vm->_draw->_spriteRight = spot.right - spot.left + 1;
|
||
|
_vm->_draw->_spriteBottom = spot.bottom - spot.top + 1;
|
||
|
|
||
|
_vm->_draw->_destSurface = 21;
|
||
|
|
||
|
_vm->_draw->_backColor = inpDesc[descInd].backColor;
|
||
|
_vm->_draw->_frontColor = inpDesc[descInd].frontColor;
|
||
|
_vm->_draw->_textToPrint = tempStr;
|
||
|
_vm->_draw->_transparency = 1;
|
||
|
_vm->_draw->_fontIndex = inpDesc[descInd].fontIndex;
|
||
|
|
||
|
_vm->_draw->spriteOperation(DRAW_FILLRECT | 0x10);
|
||
|
|
||
|
_vm->_draw->_destSpriteY += ((spot.bottom - spot.top + 1) -
|
||
|
_vm->_draw->_fonts[_vm->_draw->_fontIndex]->itemHeight) / 2;
|
||
|
_vm->_draw->spriteOperation(DRAW_PRINTTEXT | 0x10);
|
||
|
|
||
|
descInd++;
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < 40; i++)
|
||
|
WRITE_VAR_OFFSET(i * 4 + 0x44, 0);
|
||
|
|
||
|
while (1) {
|
||
|
descInd = 0;
|
||
|
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
continue;
|
||
|
|
||
|
if ((spot.id & 0xC000) != 0x8000)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() < kTypeInput1NoLeave)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() > kTypeInputFloatLeave)
|
||
|
continue;
|
||
|
|
||
|
if (descInd == curPos) {
|
||
|
found = i;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
descInd++;
|
||
|
}
|
||
|
|
||
|
assert(found != 0xFFFF);
|
||
|
|
||
|
Hotspot inputSpot = _hotspots[found];
|
||
|
|
||
|
key = readString(inputSpot.left, inputSpot.top,
|
||
|
inputSpot.right - inputSpot.left + 1,
|
||
|
inputSpot.bottom - inputSpot.top + 1,
|
||
|
inpDesc[curPos].backColor, inpDesc[curPos].frontColor,
|
||
|
GET_VARO_STR(inputSpot.key), inpDesc[curPos].fontIndex,
|
||
|
inputSpot.getType(), time, id, index);
|
||
|
|
||
|
if (_vm->_inter->_terminate)
|
||
|
return 0;
|
||
|
|
||
|
switch (key) {
|
||
|
case kKeyNone:
|
||
|
if (id == 0)
|
||
|
return 0;
|
||
|
|
||
|
if (_vm->_game->_mouseButtons != kMouseButtonsNone) {
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if (spot.getWindow() != 0)
|
||
|
continue;
|
||
|
|
||
|
if ((spot.id & 0x4000))
|
||
|
continue;
|
||
|
|
||
|
if (!spot.isIn(_vm->_global->_inter_mouseX, _vm->_global->_inter_mouseY))
|
||
|
continue;
|
||
|
|
||
|
if ((spot.id & 0xF000))
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() < kTypeInput1NoLeave)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() > kTypeInputFloatLeave)
|
||
|
continue;
|
||
|
|
||
|
index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_hotspots[index].getType() < kTypeInput1NoLeave)
|
||
|
return 0;
|
||
|
|
||
|
if (_hotspots[index].getType() > kTypeInputFloatLeave)
|
||
|
return 0;
|
||
|
|
||
|
curPos = 0;
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
continue;
|
||
|
|
||
|
if ((spot.id & 0xC000) != 0x8000)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() < kTypeInput1NoLeave)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() > kTypeInputFloatLeave)
|
||
|
continue;
|
||
|
|
||
|
if (i == index)
|
||
|
break;
|
||
|
|
||
|
curPos++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case kKeyF1:
|
||
|
case kKeyF2:
|
||
|
case kKeyF3:
|
||
|
case kKeyF4:
|
||
|
case kKeyF5:
|
||
|
case kKeyF6:
|
||
|
case kKeyF7:
|
||
|
case kKeyF8:
|
||
|
case kKeyF9:
|
||
|
case kKeyF10:
|
||
|
return key;
|
||
|
|
||
|
case kKeyReturn:
|
||
|
|
||
|
if (maxPos == 1)
|
||
|
return key;
|
||
|
|
||
|
if (curPos == (maxPos - 1)) {
|
||
|
curPos = 0;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
curPos++;
|
||
|
break;
|
||
|
|
||
|
case kKeyDown:
|
||
|
if ((maxPos - 1) > curPos)
|
||
|
curPos++;
|
||
|
break;
|
||
|
|
||
|
case kKeyUp:
|
||
|
if (curPos > 0)
|
||
|
curPos--;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Hotspots::evaluate() {
|
||
|
InputDesc descArray[20];
|
||
|
int16 array[300];
|
||
|
char *str;
|
||
|
int16 counter;
|
||
|
int16 var_24;
|
||
|
int16 var_26;
|
||
|
int16 collStackPos;
|
||
|
|
||
|
push(0);
|
||
|
|
||
|
uint16 endIndex = 0;
|
||
|
while (_hotspots[endIndex].left != 0xFFFF)
|
||
|
endIndex++;
|
||
|
|
||
|
_shouldPush = false;
|
||
|
|
||
|
_vm->_game->_script->skip(1);
|
||
|
|
||
|
byte count = _vm->_game->_script->readByte();
|
||
|
|
||
|
_vm->_game->_handleMouse = _vm->_game->_script->peekByte(0);
|
||
|
int16 duration = _vm->_game->_script->peekByte(1);
|
||
|
byte stackPos2 = _vm->_game->_script->peekByte(3);
|
||
|
byte descIndex = _vm->_game->_script->peekByte(4);
|
||
|
bool needRecalculation = _vm->_game->_script->peekByte(5) != 0;
|
||
|
|
||
|
duration *= 1000;
|
||
|
if ((stackPos2 != 0) || (descIndex != 0)) {
|
||
|
duration /= 100;
|
||
|
if (_vm->_game->_script->peekByte(1) == 100)
|
||
|
duration = 2;
|
||
|
}
|
||
|
|
||
|
int16 timeVal = duration;
|
||
|
|
||
|
_vm->_game->_script->skip(6);
|
||
|
|
||
|
WRITE_VAR(16, 0);
|
||
|
|
||
|
byte var_41 = 0;
|
||
|
int16 var_46 = 0;
|
||
|
|
||
|
uint16 id = 0;
|
||
|
uint16 validId = 0xFFFF;
|
||
|
uint16 index = 0;
|
||
|
|
||
|
bool hasInput = false;
|
||
|
uint16 inputIndex = 0;
|
||
|
|
||
|
for (uint16 i = 0; i < count; i++) {
|
||
|
array[i] = 0;
|
||
|
|
||
|
byte type = _vm->_game->_script->readByte();
|
||
|
byte window = 0;
|
||
|
|
||
|
if ((type & 0x40) != 0) {
|
||
|
type -= 0x40;
|
||
|
window = _vm->_game->_script->readByte();
|
||
|
}
|
||
|
|
||
|
uint16 left, top, width, height, right, bottom;
|
||
|
uint32 funcEnter = 0, funcLeave = 0, funcPos = 0;
|
||
|
if ((type & 0x80) != 0) {
|
||
|
funcPos = _vm->_game->_script->pos();
|
||
|
left = _vm->_game->_script->readValExpr();
|
||
|
top = _vm->_game->_script->readValExpr();
|
||
|
width = _vm->_game->_script->readValExpr();
|
||
|
height = _vm->_game->_script->readValExpr();
|
||
|
} else {
|
||
|
funcPos = 0;
|
||
|
left = _vm->_game->_script->readUint16();
|
||
|
top = _vm->_game->_script->readUint16();
|
||
|
width = _vm->_game->_script->readUint16();
|
||
|
height = _vm->_game->_script->readUint16();
|
||
|
}
|
||
|
|
||
|
if ((_vm->_draw->_renderFlags & RENDERFLAG_CAPTUREPOP) && (left != 0xFFFF)) {
|
||
|
left += _vm->_draw->_backDeltaX;
|
||
|
top += _vm->_draw->_backDeltaY;
|
||
|
}
|
||
|
|
||
|
right = left + width - 1;
|
||
|
bottom = top + height - 1;
|
||
|
|
||
|
int16 key = 0;
|
||
|
int16 flags = 0;
|
||
|
Video::FontDesc *font = 0;
|
||
|
|
||
|
type &= 0x7F;
|
||
|
switch (type) {
|
||
|
case kTypeNone:
|
||
|
_vm->_game->_script->skip(6);
|
||
|
|
||
|
funcEnter = _vm->_game->_script->pos();
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
|
||
|
funcLeave = _vm->_game->_script->pos();
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
|
||
|
key = i + 0xA000;
|
||
|
flags = type + (window << 8);
|
||
|
|
||
|
add(i + 0x8000, left, top, right, bottom,
|
||
|
flags, key, funcEnter, funcLeave, funcPos);
|
||
|
break;
|
||
|
|
||
|
case kTypeMove:
|
||
|
key = _vm->_game->_script->readInt16();
|
||
|
array[i] = _vm->_game->_script->readInt16();
|
||
|
flags = _vm->_game->_script->readInt16();
|
||
|
|
||
|
funcEnter = _vm->_game->_script->pos();
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
|
||
|
funcLeave = _vm->_game->_script->pos();
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
|
||
|
if (key == 0)
|
||
|
key = i + 0xA000;
|
||
|
flags = type + (window << 8) + (flags << 4);
|
||
|
|
||
|
add(i + 0x8000, left, top, right, bottom,
|
||
|
flags, key, funcEnter, funcLeave, funcPos);
|
||
|
break;
|
||
|
|
||
|
case kTypeInput1NoLeave:
|
||
|
case kTypeInput1Leave:
|
||
|
case kTypeInput2NoLeave:
|
||
|
case kTypeInput2Leave:
|
||
|
case kTypeInput3NoLeave:
|
||
|
case kTypeInput3Leave:
|
||
|
case kTypeInputFloatNoLeave:
|
||
|
case kTypeInputFloatLeave:
|
||
|
hasInput = true;
|
||
|
|
||
|
_vm->_util->clearKeyBuf();
|
||
|
|
||
|
key = _vm->_game->_script->readVarIndex();
|
||
|
descArray[inputIndex].fontIndex = _vm->_game->_script->readInt16();
|
||
|
descArray[inputIndex].backColor = _vm->_game->_script->readByte();
|
||
|
descArray[inputIndex].frontColor = _vm->_game->_script->readByte();
|
||
|
descArray[inputIndex].ptr = 0;
|
||
|
|
||
|
if ((type >= kTypeInput2NoLeave) && (type <= kTypeInput3Leave)) {
|
||
|
descArray[inputIndex].ptr = _vm->_game->_script->getData() + _vm->_game->_script->pos() + 2;
|
||
|
_vm->_game->_script->skip(_vm->_game->_script->peekUint16() + 2);
|
||
|
}
|
||
|
|
||
|
if (left == 0xFFFF) {
|
||
|
if ((type & 1) == 0)
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
font = _vm->_draw->_fonts[descArray[inputIndex].fontIndex];
|
||
|
if (!font->extraData)
|
||
|
right = left + width * font->itemWidth - 1;
|
||
|
|
||
|
funcEnter = 0;
|
||
|
funcPos = 0;
|
||
|
funcLeave = 0;
|
||
|
if (!(type & 1)) {
|
||
|
funcLeave = _vm->_game->_script->pos();
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
}
|
||
|
|
||
|
flags = type;
|
||
|
|
||
|
inputIndex++;
|
||
|
|
||
|
add(i + 0x8000, left, top, right, bottom,
|
||
|
flags, key, funcEnter, funcLeave, funcPos);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 11:
|
||
|
_vm->_game->_script->skip(6);
|
||
|
|
||
|
for (int j = 0; j < kHotspotCount; j++) {
|
||
|
Hotspot &spot = _hotspots[j];
|
||
|
|
||
|
if ((spot.id & 0xF000) == 0xE000) {
|
||
|
spot.id &= 0xBFFF;
|
||
|
spot.funcEnter = _vm->_game->_script->pos();
|
||
|
spot.funcLeave = _vm->_game->_script->pos();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
break;
|
||
|
|
||
|
case 12:
|
||
|
_vm->_game->_script->skip(6);
|
||
|
|
||
|
for (int j = 0; j < kHotspotCount; j++) {
|
||
|
Hotspot &spot = _hotspots[j];
|
||
|
|
||
|
if ((spot.id & 0xF000) == 0xD000) {
|
||
|
spot.id &= 0xBFFF;
|
||
|
spot.funcEnter = _vm->_game->_script->pos();
|
||
|
spot.funcLeave = _vm->_game->_script->pos();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
break;
|
||
|
|
||
|
case 20:
|
||
|
validId = i;
|
||
|
// Fall through to case 2
|
||
|
case kTypeClick:
|
||
|
key = _vm->_game->_script->readInt16();
|
||
|
array[i] = _vm->_game->_script->readInt16();
|
||
|
flags = _vm->_game->_script->readInt16();
|
||
|
|
||
|
funcEnter = 0;
|
||
|
|
||
|
funcLeave = _vm->_game->_script->pos();
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
|
||
|
flags = 2 + (window << 8) + (flags << 4);
|
||
|
|
||
|
add(i + 0x8000, left, top, right, bottom,
|
||
|
flags, key, funcEnter, funcLeave, funcPos);
|
||
|
break;
|
||
|
|
||
|
case 21:
|
||
|
key = _vm->_game->_script->readInt16();
|
||
|
array[i] = _vm->_game->_script->readInt16();
|
||
|
flags = _vm->_game->_script->readInt16() & 3;
|
||
|
|
||
|
funcEnter = _vm->_game->_script->pos();
|
||
|
_vm->_game->_script->skipBlock();
|
||
|
|
||
|
funcLeave = 0;
|
||
|
|
||
|
flags = 2 + (window << 8) + (flags << 4);
|
||
|
|
||
|
add(i + 0x8000, left, top, right, bottom,
|
||
|
flags, key, funcEnter, funcLeave, funcPos);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (needRecalculation)
|
||
|
recalculate(true);
|
||
|
|
||
|
_vm->_game->_forceHandleMouse = 0;
|
||
|
_vm->_util->clearKeyBuf();
|
||
|
|
||
|
do {
|
||
|
uint16 key = 0;
|
||
|
if (hasInput) {
|
||
|
uint16 curEditIndex = 0;
|
||
|
|
||
|
key = handleInput(duration, inputIndex, curEditIndex, descArray, id, index);
|
||
|
|
||
|
WRITE_VAR(55, curEditIndex);
|
||
|
if (key == kKeyReturn) {
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if ((spot.id & 0xC000) != 0x8000)
|
||
|
continue;
|
||
|
|
||
|
if ((spot.getType() & 1) != 0)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() <= kTypeClick)
|
||
|
continue;
|
||
|
|
||
|
id = spot.id;
|
||
|
validId = spot.id & 0x7FFF;
|
||
|
index = i;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
} else
|
||
|
key = check(_vm->_game->_handleMouse, -duration, id, index);
|
||
|
|
||
|
if (((key & 0xFF) >= ' ') && ((key & 0xFF) <= 0xFF) &&
|
||
|
((key >> 8) > 1) && ((key >> 8) < 12))
|
||
|
key = '0' + (((key >> 8) - 1) % 10) + (key & 0xFF00);
|
||
|
|
||
|
if (id == 0) {
|
||
|
if (key != 0) {
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if ((spot.id & 0xC000) != 0x8000)
|
||
|
continue;
|
||
|
|
||
|
if ((spot.key == key) || (spot.key == 0x7FFF)) {
|
||
|
id = spot.id;
|
||
|
index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (id == 0) {
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if ((spot.id & 0xC000) != 0x8000)
|
||
|
continue;
|
||
|
|
||
|
if ((spot.key & 0xFF00) != 0)
|
||
|
continue;
|
||
|
|
||
|
if (spot.key == 0)
|
||
|
continue;
|
||
|
|
||
|
if (toupper(key & 0xFF) == toupper(spot.key)) {
|
||
|
id = spot.id;
|
||
|
index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else if (duration != 0) {
|
||
|
if (stackPos2 != 0) {
|
||
|
collStackPos = 0;
|
||
|
|
||
|
for (int i = endIndex; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if ((spot.id & 0xF000) != 0x8000)
|
||
|
continue;
|
||
|
|
||
|
collStackPos++;
|
||
|
if (collStackPos != stackPos2)
|
||
|
continue;
|
||
|
|
||
|
id = spot.id;
|
||
|
index = i;
|
||
|
_vm->_inter->storeMouse();
|
||
|
if (VAR(16) != 0)
|
||
|
break;
|
||
|
|
||
|
if ((id & 0xF000) == 0x8000)
|
||
|
WRITE_VAR(16, array[id & 0xFFF]);
|
||
|
else
|
||
|
WRITE_VAR(16, id & 0xFFF);
|
||
|
|
||
|
if (spot.funcLeave != 0) {
|
||
|
uint32 timeKey = _vm->_util->getTimeKey();
|
||
|
call(spot.funcLeave);
|
||
|
|
||
|
if (timeVal != 2) {
|
||
|
duration = timeVal - (_vm->_util->getTimeKey() - timeKey);
|
||
|
|
||
|
if ((duration - var_46) < 3) {
|
||
|
var_46 -= (duration - 3);
|
||
|
duration = 3;
|
||
|
} else if (var_46 != 0) {
|
||
|
duration -= var_46;
|
||
|
var_46 = 0;
|
||
|
}
|
||
|
|
||
|
if (duration > timeVal)
|
||
|
duration = timeVal;
|
||
|
|
||
|
} else
|
||
|
duration = 2;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (VAR(16) == 0)
|
||
|
id = 0;
|
||
|
else
|
||
|
var_41 = 1;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
if (descIndex != 0) {
|
||
|
|
||
|
counter = 0;
|
||
|
for (int i = endIndex; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if ((spot.id & 0xF000) == 0x8000) {
|
||
|
if (++counter == descIndex) {
|
||
|
id = spot.id;
|
||
|
index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if ((spot.id & 0xF000) == 0x8000) {
|
||
|
id = spot.id;
|
||
|
index = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((_currentKey != 0) && (_hotspots[_currentIndex].funcLeave != 0))
|
||
|
call(_hotspots[_currentIndex].funcLeave);
|
||
|
|
||
|
_currentKey = 0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (var_41 != 0)
|
||
|
break;
|
||
|
|
||
|
if ((id == 0) || (_hotspots[index].funcLeave != 0))
|
||
|
continue;
|
||
|
|
||
|
_vm->_inter->storeMouse();
|
||
|
|
||
|
if ((id & 0xF000) == 0x8000)
|
||
|
WRITE_VAR(16, array[id & 0xFFF]);
|
||
|
else
|
||
|
WRITE_VAR(16, id & 0xFFF);
|
||
|
|
||
|
if (_hotspots[index].funcEnter != 0)
|
||
|
call(_hotspots[index].funcEnter);
|
||
|
|
||
|
WRITE_VAR(16, 0);
|
||
|
id = 0;
|
||
|
}
|
||
|
while ((id == 0) && !_vm->_inter->_terminate && !_vm->shouldQuit());
|
||
|
|
||
|
char tempStr[256];
|
||
|
if ((id & 0xFFF) == validId) {
|
||
|
collStackPos = 0;
|
||
|
var_24 = 0;
|
||
|
var_26 = 1;
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
continue;
|
||
|
|
||
|
if ((spot.id & 0xC000) != 0x8000)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() < kTypeInput1NoLeave)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() > kTypeInputFloatLeave)
|
||
|
continue;
|
||
|
|
||
|
if (spot.getType() > kTypeInput3Leave) {
|
||
|
char *ptr;
|
||
|
strncpy0(tempStr, GET_VARO_STR(spot.key), 255);
|
||
|
while ((ptr = strchr(tempStr, ' ')))
|
||
|
_vm->_util->cutFromStr(tempStr, (ptr - tempStr), 1);
|
||
|
if (_vm->_global->_language == kLanguageBritish)
|
||
|
while ((ptr = strchr(tempStr, '.')))
|
||
|
*ptr = ',';
|
||
|
WRITE_VARO_STR(spot.key, tempStr);
|
||
|
}
|
||
|
|
||
|
if ((spot.getType() >= kTypeInput2NoLeave) && (spot.getType() <= kTypeInput3Leave)) {
|
||
|
str = (char *) descArray[var_24].ptr;
|
||
|
|
||
|
strncpy0(tempStr, GET_VARO_STR(spot.key), 255);
|
||
|
|
||
|
if (spot.getType() < kTypeInput3NoLeave)
|
||
|
_vm->_util->cleanupStr(tempStr);
|
||
|
|
||
|
int16 pos = 0;
|
||
|
do {
|
||
|
char spotStr[256];
|
||
|
|
||
|
strncpy0(spotStr, str, 255);
|
||
|
pos += strlen(str) + 1;
|
||
|
|
||
|
str += strlen(str) + 1;
|
||
|
|
||
|
if (spot.getType() < kTypeInput3NoLeave)
|
||
|
_vm->_util->cleanupStr(spotStr);
|
||
|
|
||
|
if (strcmp(tempStr, spotStr) == 0) {
|
||
|
WRITE_VAR(17, VAR(17) + 1);
|
||
|
WRITE_VAR(17 + var_26, 1);
|
||
|
break;
|
||
|
}
|
||
|
} while (READ_LE_UINT16(descArray[var_24].ptr - 2) > pos);
|
||
|
collStackPos++;
|
||
|
} else {
|
||
|
WRITE_VAR(17 + var_26, 2);
|
||
|
}
|
||
|
var_24++;
|
||
|
var_26++;
|
||
|
}
|
||
|
|
||
|
if (collStackPos != (int16) VAR(17))
|
||
|
WRITE_VAR(17, 0);
|
||
|
else
|
||
|
WRITE_VAR(17, 1);
|
||
|
}
|
||
|
|
||
|
if (_vm->_game->_handleMouse == 1)
|
||
|
_vm->_draw->blitCursor();
|
||
|
|
||
|
if (!_vm->_inter->_terminate && (var_41 == 0)) {
|
||
|
_vm->_game->_script->seek(_hotspots[index].funcLeave);
|
||
|
|
||
|
_vm->_inter->storeMouse();
|
||
|
if (VAR(16) == 0) {
|
||
|
if ((id & 0xF000) == 0x8000)
|
||
|
WRITE_VAR(16, array[id & 0xFFF]);
|
||
|
else
|
||
|
WRITE_VAR(16, id & 0xFFF);
|
||
|
}
|
||
|
} else
|
||
|
_vm->_game->_script->setFinished(true);
|
||
|
|
||
|
for (int i = 0; i < count; i++)
|
||
|
remove(i + 0x8000);
|
||
|
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (((spot.id & 0xF000) == 0xA000) || ((spot.id & 0xF000) == 0x9000))
|
||
|
spot.id |= 0x4000;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
int16 Hotspots::findCursor(uint16 x, uint16 y) const {
|
||
|
int16 cursor = 0;
|
||
|
|
||
|
for (int i = 0; i < kHotspotCount; i++) {
|
||
|
Hotspot &spot = _hotspots[i];
|
||
|
|
||
|
if (spot.left == 0xFFFF)
|
||
|
break;
|
||
|
|
||
|
if ((spot.getWindow() != 0) || (spot.id & 0x4000))
|
||
|
continue;
|
||
|
|
||
|
if (!spot.isIn(x, y))
|
||
|
continue;
|
||
|
|
||
|
if (spot.getCursor() == 0) {
|
||
|
if (spot.getType() >= kTypeInput1NoLeave) {
|
||
|
cursor = 3;
|
||
|
break;
|
||
|
} else if ((spot.getButton() != kMouseButtonsRight) && (cursor == 0))
|
||
|
cursor = 1;
|
||
|
} else if (cursor == 0)
|
||
|
cursor = spot.getCursor();
|
||
|
}
|
||
|
|
||
|
return cursor;
|
||
|
}
|
||
|
|
||
|
} // End of namespace Gob
|