mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 12:39:56 +00:00
1260 lines
28 KiB
C++
1260 lines
28 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 "dreamweb/dreamweb.h"
|
|
|
|
namespace DreamWeb {
|
|
|
|
void DreamWebEngine::showRyanPage() {
|
|
showFrame(_icons1, kInventx + 167, kInventy - 12, 12, 0);
|
|
showFrame(_icons1, kInventx + 167 + 18 * _vars._ryanPage, kInventy - 12, 13 + _vars._ryanPage, 0);
|
|
}
|
|
|
|
void DreamWebEngine::findAllRyan() {
|
|
memset(_ryanInvList, 0xff, sizeof(_ryanInvList));
|
|
for (uint i = 0; i < kNumexobjects; ++i) {
|
|
const DynObject *extra = getExAd(i);
|
|
if (extra->mapad[0] != kExObjectType)
|
|
continue;
|
|
if (extra->mapad[1] != 0xff)
|
|
continue;
|
|
uint8 slot = extra->mapad[2];
|
|
assert(slot < 30);
|
|
_ryanInvList[slot]._index = i;
|
|
_ryanInvList[slot]._type = kExObjectType;
|
|
}
|
|
}
|
|
|
|
void DreamWebEngine::fillRyan() {
|
|
ObjectRef *inv = &_ryanInvList[_vars._ryanPage * 10];
|
|
findAllRyan();
|
|
for (uint i = 0; i < 2; ++i) {
|
|
for (uint j = 0; j < 5; ++j) {
|
|
obToInv(inv->_index, inv->_type, kInventx + j * kItempicsize, kInventy + i * kItempicsize);
|
|
++inv;
|
|
}
|
|
}
|
|
showRyanPage();
|
|
}
|
|
|
|
bool DreamWebEngine::isItWorn(const DynObject *object) {
|
|
return (object->objId[0] == 'W'-'A') && (object->objId[1] == 'E'-'A');
|
|
}
|
|
|
|
void DreamWebEngine::wornError() {
|
|
_commandType = 255;
|
|
delPointer();
|
|
printMessage(76, 21, 57, 240, false);
|
|
workToScreenM();
|
|
hangOnP(50);
|
|
showPanel();
|
|
showMan();
|
|
examIcon();
|
|
_commandType = 255;
|
|
workToScreenM();
|
|
}
|
|
|
|
void DreamWebEngine::makeWorn(DynObject *object) {
|
|
object->objId[0] = 'W'-'A';
|
|
object->objId[1] = 'E'-'A';
|
|
}
|
|
|
|
void DreamWebEngine::obToInv(uint8 index, uint8 flag, uint16 x, uint16 y) {
|
|
showFrame(_icons1, x - 2, y - 1, 10, 0);
|
|
if (index == 0xff)
|
|
return;
|
|
|
|
if (flag == kExObjectType)
|
|
showFrame(_exFrames, x + 18, y + 19, 3 * index + 1, 128);
|
|
else
|
|
showFrame(_freeFrames, x + 18, y + 19, 3 * index + 1, 128);
|
|
|
|
const DynObject *object = (const DynObject *)getAnyAdDir(index, flag);
|
|
bool worn = isItWorn(object);
|
|
if (worn)
|
|
showFrame(_icons1, x - 3, y - 2, 7, 0);
|
|
}
|
|
|
|
void DreamWebEngine::obPicture() {
|
|
if (_objectType == kSetObjectType1)
|
|
return;
|
|
uint8 frame = 3 * _command + 1;
|
|
if (_objectType == kExObjectType)
|
|
showFrame(_exFrames, 160, 68, frame, 0x80);
|
|
else
|
|
showFrame(_freeFrames, 160, 68, frame, 0x80);
|
|
}
|
|
|
|
void DreamWebEngine::obIcons() {
|
|
uint8 slotSize, slotCount;
|
|
getAnyAd(&slotSize, &slotCount);
|
|
if (slotSize != 0xff) {
|
|
// can open it
|
|
showFrame(_icons2, 210, 1, 4, 0);
|
|
}
|
|
|
|
showFrame(_icons2, 260, 1, 1, 0);
|
|
}
|
|
|
|
void DreamWebEngine::examineOb(bool examineAgain) {
|
|
_pointerMode = 0;
|
|
_timeCount = 0;
|
|
|
|
while (true) {
|
|
if (examineAgain) {
|
|
_inMapArea = 0;
|
|
_examAgain = 0;
|
|
_openedOb = 255;
|
|
_openedType = 255;
|
|
_invOpen = 0;
|
|
_objectType = _commandType;
|
|
_itemFrame = 0;
|
|
_pointerFrame = 0;
|
|
createPanel();
|
|
showPanel();
|
|
showMan();
|
|
showExit();
|
|
obIcons();
|
|
obPicture();
|
|
describeOb();
|
|
underTextLine();
|
|
_commandType = 255;
|
|
readMouse();
|
|
showPointer();
|
|
workToScreen();
|
|
delPointer();
|
|
examineAgain = false;
|
|
}
|
|
|
|
readMouse();
|
|
showPointer();
|
|
waitForVSync();
|
|
dumpPointer();
|
|
dumpTextLine();
|
|
delPointer();
|
|
_getBack = 0;
|
|
|
|
switch (_invOpen) {
|
|
case 0: {
|
|
RectWithCallback examList[] = {
|
|
{ 273,320,157,198,&DreamWebEngine::getBackFromOb },
|
|
{ 260,300,0,44,&DreamWebEngine::useObject },
|
|
{ 210,254,0,44,&DreamWebEngine::selectOpenOb },
|
|
{ 144,176,64,96,&DreamWebEngine::setPickup },
|
|
{ 0,50,50,200,&DreamWebEngine::examineInventory },
|
|
{ 0,320,0,200,&DreamWebEngine::blank },
|
|
{ 0xFFFF,0,0,0,nullptr }
|
|
};
|
|
checkCoords(examList);
|
|
break;
|
|
}
|
|
case 1: {
|
|
// Note: This table contains the non-constant _openChangeSize!
|
|
RectWithCallback invList1[] = {
|
|
{ 273,320,157,198,&DreamWebEngine::getBackFromOb },
|
|
{ 255,294,0,24,&DreamWebEngine::dropObject },
|
|
{ kInventx+167,kInventx+167+(18*3),kInventy-18,kInventy-2,&DreamWebEngine::incRyanPage },
|
|
{ kInventx,_openChangeSize,kInventy+100,kInventy+100+kItempicsize,&DreamWebEngine::useOpened },
|
|
{ kInventx,kInventx+(5*kItempicsize),kInventy,kInventy+(2*kItempicsize),&DreamWebEngine::inToInv },
|
|
{ 0,320,0,200,&DreamWebEngine::blank },
|
|
{ 0xFFFF,0,0,0,nullptr }
|
|
};
|
|
checkCoords(invList1);
|
|
break;
|
|
}
|
|
default: {
|
|
RectWithCallback withList1[] = {
|
|
{ 273,320,157,198,&DreamWebEngine::getBackFromOb },
|
|
{ kInventx+167,kInventx+167+(18*3),kInventy-18,kInventy-2,&DreamWebEngine::incRyanPage },
|
|
{ kInventx,kInventx+(5*kItempicsize), kInventy,kInventy+(2*kItempicsize),&DreamWebEngine::selectOb },
|
|
{ 0,320,0,200,&DreamWebEngine::blank },
|
|
{ 0xFFFF,0,0,0,nullptr }
|
|
};
|
|
checkCoords(withList1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (_quitRequested)
|
|
break;
|
|
if (_examAgain != 0)
|
|
examineAgain = true;
|
|
else if (_getBack != 0)
|
|
break;
|
|
}
|
|
|
|
_pickUp = 0;
|
|
if (_vars._watchingTime != 0 || _newLocation == 255) {
|
|
// isWatching
|
|
makeMainScreen();
|
|
}
|
|
|
|
_invOpen = 0;
|
|
_openedOb = 255;
|
|
}
|
|
|
|
void DreamWebEngine::inventory() {
|
|
if (_vars._manDead == 1 || _vars._watchingTime != 0) {
|
|
blank();
|
|
return;
|
|
}
|
|
|
|
commandOnlyCond(32, 239);
|
|
|
|
if (_mouseButton == _oldButton)
|
|
return;
|
|
if (!(_mouseButton & 1)) // only on left mouse button
|
|
return;
|
|
|
|
|
|
_timeCount = 0;
|
|
_pointerMode = 0;
|
|
_inMapArea = 0;
|
|
animPointer();
|
|
createPanel();
|
|
showPanel();
|
|
examIcon();
|
|
showMan();
|
|
showExit();
|
|
underTextLine();
|
|
_pickUp = 0;
|
|
_invOpen = 2;
|
|
openInv();
|
|
readMouse();
|
|
showPointer();
|
|
workToScreen();
|
|
delPointer();
|
|
_openedOb = 255;
|
|
examineOb(false);
|
|
}
|
|
|
|
void DreamWebEngine::transferText(uint8 from, uint8 to) {
|
|
_exText.setOffset(to, _vars._exTextPos);
|
|
const char *src = _freeDesc.getString(from);
|
|
char *dst = _exText._text + _vars._exTextPos;
|
|
|
|
size_t len = strlen(src);
|
|
assert(_vars._exTextPos + len + 1 <= kExtextlen);
|
|
memcpy(dst, src, len + 1);
|
|
_vars._exTextPos += len + 1;
|
|
}
|
|
|
|
void DreamWebEngine::getBackFromOb() {
|
|
if (_pickUp != 1)
|
|
getBack1();
|
|
else
|
|
blank();
|
|
}
|
|
|
|
byte DreamWebEngine::getOpenedSlotCount() {
|
|
byte obj = _openedOb;
|
|
switch (_openedType) {
|
|
case kExObjectType:
|
|
return getExAd(obj)->slotCount;
|
|
case kFreeObjectType:
|
|
return getFreeAd(obj)->slotCount;
|
|
default:
|
|
return getSetAd(obj)->slotCount;
|
|
}
|
|
}
|
|
|
|
byte DreamWebEngine::getOpenedSlotSize() {
|
|
byte obj = _openedOb;
|
|
switch (_openedType) {
|
|
case kExObjectType:
|
|
return getExAd(obj)->slotSize;
|
|
case kFreeObjectType:
|
|
return getFreeAd(obj)->slotSize;
|
|
default:
|
|
return getSetAd(obj)->slotSize;
|
|
}
|
|
}
|
|
|
|
void DreamWebEngine::openOb() {
|
|
uint8 commandLine[64] = "OBJECT NAME ONE ";
|
|
|
|
copyName(_openedType, _openedOb, commandLine);
|
|
|
|
if (getLanguage() != Common::RU_RUS) {
|
|
printMessage(kInventx, kInventy+86, 62, 240, false);
|
|
|
|
printDirect(commandLine, _lastXPos + 5, kInventy+86, 220, false);
|
|
} else {
|
|
printDirect(commandLine, kInventx, kInventy+86, 220, false);
|
|
printMessage(_lastXPos, kInventy+86, 62, 240, false);
|
|
}
|
|
|
|
fillOpen();
|
|
_openChangeSize = getOpenedSlotCount() * kItempicsize + kInventx;
|
|
}
|
|
|
|
void DreamWebEngine::identifyOb() {
|
|
if (_vars._watchingTime != 0) {
|
|
blank();
|
|
return;
|
|
}
|
|
|
|
uint16 initialX = _mouseX - _mapAdX;
|
|
uint16 initialY = _mouseY - _mapAdY;
|
|
|
|
if (initialX >= 22 * 8 || initialY >= 20 * 8) {
|
|
blank();
|
|
return;
|
|
}
|
|
|
|
byte x = initialX & 0xFF;
|
|
byte y = initialY & 0xFF;
|
|
|
|
_inMapArea = 1;
|
|
_pointersPath = findPathOfPoint(x, y);
|
|
_pointerFirstPath = findFirstPath(x, y);
|
|
|
|
if (checkIfEx(x, y) || checkIfFree(x, y) ||
|
|
checkIfPerson(x, y) || checkIfSet(x, y))
|
|
return; // finishidentify
|
|
|
|
x = (_mouseX - _mapAdX) & 0xFF;
|
|
y = (_mouseY - _mapAdY) & 0xFF;
|
|
byte flag, flagEx, type, flagX, flagY;
|
|
|
|
checkOne(x, y, &flag, &flagEx, &type, &flagX, &flagY);
|
|
|
|
if (type != 0 && _vars._manDead != 1)
|
|
obName(type, 3);
|
|
else
|
|
blank();
|
|
}
|
|
|
|
ObjectRef DreamWebEngine::findInvPos() {
|
|
uint16 x = _mouseX - kInventx;
|
|
uint16 y = _mouseY - kInventy;
|
|
uint8 pos = (x / kItempicsize) + (y / kItempicsize) * 5;
|
|
uint8 invPos = _vars._ryanPage * 10 + pos;
|
|
_lastInvPos = invPos;
|
|
return _ryanInvList[invPos];
|
|
}
|
|
|
|
void DreamWebEngine::selectOb() {
|
|
ObjectRef objectId = findInvPos();
|
|
if (objectId._index == 255) {
|
|
blank();
|
|
return;
|
|
}
|
|
|
|
_withObject = objectId._index;
|
|
_withType = objectId._type;
|
|
|
|
if (objectId != _oldSubject || _commandType != 221) {
|
|
if (objectId == _oldSubject)
|
|
_commandType = 221;
|
|
_oldSubject = objectId;
|
|
commandWithOb(0, objectId._type, objectId._index);
|
|
}
|
|
|
|
if (_mouseButton == _oldButton || !(_mouseButton & 1))
|
|
return;
|
|
|
|
delPointer();
|
|
_invOpen = 0;
|
|
useRoutine();
|
|
}
|
|
|
|
void DreamWebEngine::setPickup() {
|
|
if (_objectType != kSetObjectType1 && _objectType != kSetObjectType3) {
|
|
// Object types 1 and 3 are excluded, so the resulting object is a DynObject
|
|
uint8 dummy;
|
|
DynObject *object = (DynObject *)getAnyAd(&dummy, &dummy);
|
|
if (object->mapad[0] == 4) {
|
|
blank();
|
|
return;
|
|
}
|
|
} else {
|
|
blank();
|
|
return;
|
|
}
|
|
|
|
if (_commandType != 209) {
|
|
_commandType = 209;
|
|
commandWithOb(33, _objectType, _command);
|
|
}
|
|
|
|
if (_mouseButton != 1 || _mouseButton == _oldButton)
|
|
return;
|
|
|
|
createPanel();
|
|
showPanel();
|
|
showMan();
|
|
showExit();
|
|
examIcon();
|
|
_pickUp = 1;
|
|
_invOpen = 2;
|
|
|
|
if (_objectType != kExObjectType) {
|
|
assert(_objectType == kFreeObjectType);
|
|
_openedOb = 255;
|
|
_itemFrame = transferToEx(_command);
|
|
_objectType = kExObjectType;
|
|
DynObject *object = getExAd(_itemFrame);
|
|
object->mapad[0] = 20;
|
|
object->mapad[1] = 255;
|
|
} else {
|
|
_itemFrame = _command;
|
|
_openedOb = 255;
|
|
}
|
|
|
|
openInv();
|
|
workToScreenM();
|
|
}
|
|
|
|
void DreamWebEngine::deleteExFrame(uint8 frameNum) {
|
|
Frame *frame = &_exFrames._frames[frameNum];
|
|
|
|
uint16 frameSize = frame->width * frame->height;
|
|
// Note: the original asm didn't subtract frameSize from remainder
|
|
uint16 remainder = kExframeslen - frame->ptr() - frameSize;
|
|
uint16 startOff = frame->ptr();
|
|
uint16 endOff = startOff + frameSize;
|
|
|
|
// Shift frame data after this one down
|
|
memmove(&_exFrames._data[startOff], &_exFrames._data[endOff], remainder);
|
|
|
|
// Combined frame data is now frameSize smaller
|
|
_vars._exFramePos -= frameSize;
|
|
|
|
// Adjust all frame pointers pointing into the shifted data
|
|
for (unsigned int i = 0; i < kNumexobjects; ++i) {
|
|
if (_exData[i].mapad[0] != 0xff) {
|
|
frame = &_exFrames._frames[3*i+0];
|
|
if (frame->ptr() >= startOff) {
|
|
frame->setPtr(frame->ptr() - frameSize);
|
|
assert(frame->ptr() + frame->width*frame->height <= _vars._exFramePos);
|
|
} else {
|
|
assert(frame->ptr() + frame->width*frame->height <= startOff);
|
|
}
|
|
frame = &_exFrames._frames[3*i+1];
|
|
if (frame->ptr() >= startOff) {
|
|
frame->setPtr(frame->ptr() - frameSize);
|
|
assert(frame->ptr() + frame->width*frame->height <= _vars._exFramePos);
|
|
} else {
|
|
assert(frame->ptr() + frame->width*frame->height <= startOff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DreamWebEngine::deleteExText(uint8 textNum) {
|
|
uint16 offset = _exText.getOffset(textNum);
|
|
|
|
uint16 startOff = offset;
|
|
uint16 textSize = strlen(_exText.getString(textNum)) + 1;
|
|
uint16 endOff = startOff + textSize;
|
|
uint16 remainder = kExtextlen - offset - textSize;
|
|
|
|
// Shift text data after this one down
|
|
memmove(&_exText._text[startOff], &_exText._text[endOff], remainder);
|
|
|
|
// Combined text data is now frameSize smaller
|
|
_vars._exTextPos -= textSize;
|
|
|
|
// Adjust all text pointers pointing into the shifted data
|
|
for (unsigned int i = 0; i < kNumexobjects; ++i) {
|
|
uint16 t = _exText.getOffset(i);
|
|
if (t >= offset + textSize)
|
|
_exText.setOffset(i, t - textSize);
|
|
}
|
|
}
|
|
|
|
void DreamWebEngine::deleteExObject(uint8 index) {
|
|
DynObject *obj = getExAd(index);
|
|
|
|
memset(obj, 0xFF, sizeof(DynObject));
|
|
|
|
deleteExFrame(3*index);
|
|
deleteExFrame(3*index + 1);
|
|
|
|
deleteExText(index);
|
|
|
|
for (uint8 i = 0; i < kNumexobjects; ++i) {
|
|
DynObject *t = getExAd(i);
|
|
// Is this object contained in the one we've just deleted?
|
|
if (t->mapad[0] == 4 && t->mapad[1] == index)
|
|
deleteExObject(i);
|
|
}
|
|
}
|
|
|
|
void DreamWebEngine::removeObFromInv() {
|
|
if (_command == 100)
|
|
return; // object doesn't exist
|
|
|
|
assert(_objectType == kExObjectType);
|
|
|
|
deleteExObject(_command);
|
|
}
|
|
|
|
void DreamWebEngine::inToInv() {
|
|
if (!_pickUp) {
|
|
outOfInv();
|
|
return;
|
|
}
|
|
|
|
ObjectRef subject = findInvPos();
|
|
|
|
if (subject._index != 255) {
|
|
swapWithInv();
|
|
return;
|
|
}
|
|
|
|
subject._type = _objectType;
|
|
subject._index = _itemFrame;
|
|
|
|
if (subject != _oldSubject || _commandType != 220) {
|
|
if (subject == _oldSubject)
|
|
_commandType = 220;
|
|
_oldSubject = subject;
|
|
commandWithOb(35, subject._type, subject._index);
|
|
}
|
|
|
|
if (_mouseButton == _oldButton || !(_mouseButton & 1))
|
|
return; // notletgo2
|
|
|
|
delPointer();
|
|
DynObject *object = getExAd(_itemFrame);
|
|
object->mapad[0] = 4;
|
|
object->mapad[1] = 255;
|
|
object->mapad[2] = _lastInvPos;
|
|
_pickUp = 0;
|
|
fillRyan();
|
|
readMouse();
|
|
showPointer();
|
|
outOfInv();
|
|
workToScreen();
|
|
delPointer();
|
|
}
|
|
|
|
void DreamWebEngine::outOfInv() {
|
|
ObjectRef subject = findInvPos();
|
|
|
|
if (subject._index == 255) {
|
|
blank();
|
|
return;
|
|
}
|
|
|
|
if (_mouseButton == 2) {
|
|
reExFromInv();
|
|
return;
|
|
}
|
|
|
|
if (subject != _oldSubject || _commandType != 221) {
|
|
if (subject == _oldSubject)
|
|
_commandType = 221;
|
|
_oldSubject = subject;
|
|
commandWithOb(36, subject._type, subject._index);
|
|
}
|
|
|
|
if (_mouseButton == _oldButton || !(_mouseButton & 1))
|
|
return;
|
|
|
|
delPointer();
|
|
_pickUp = 1;
|
|
subject = findInvPos();
|
|
_objectType = subject._type;
|
|
_itemFrame = subject._index;
|
|
assert(subject._type == kExObjectType);
|
|
DynObject *object = getExAd(subject._index);
|
|
object->mapad[0] = 20;
|
|
object->mapad[1] = 255;
|
|
fillRyan();
|
|
readMouse();
|
|
showPointer();
|
|
inToInv();
|
|
workToScreen();
|
|
delPointer();
|
|
}
|
|
|
|
void DreamWebEngine::purgeALocation(uint8 index) {
|
|
// index == al
|
|
for (uint8 i = 0; i < kNumexobjects; ++i) {
|
|
DynObject *t = getExAd(i);
|
|
if (t->currentLocation == index && t->mapad[0] == 0) {
|
|
deleteExObject(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
const uint8 *DreamWebEngine::getObTextStart() {
|
|
const uint8 *textBase = nullptr;
|
|
const uint8 *text;
|
|
uint16 textOff = 0;
|
|
if (_objectType == kFreeObjectType) {
|
|
text = (const uint8 *)_freeDesc.getString(_command);
|
|
} else if (_objectType == kSetObjectType1) {
|
|
textBase = (const uint8 *)_setDesc._text;
|
|
textOff = kNumSetTexts * 2;
|
|
text = (const uint8 *)_setDesc.getString(_command);
|
|
} else {
|
|
text = (const uint8 *)_exText.getString(_command);
|
|
}
|
|
|
|
if (_objectType != kSetObjectType1)
|
|
return text;
|
|
|
|
const uint8 *obname = text;
|
|
while (true) {
|
|
const uint8 *start = text;
|
|
findNextColon(&text);
|
|
|
|
// Not an empty description string?
|
|
if (*text != 0 && *text != ':')
|
|
return start;
|
|
|
|
// If the description string (of a SetObjectType1 object) is empty,
|
|
// look for an object with the same name.
|
|
// Example: Eden's garage door outside has two parts. The right part
|
|
// has no description of its own but uses that of the left part.
|
|
|
|
bool found = false;
|
|
do {
|
|
text++;
|
|
uint8 c = *obname;
|
|
|
|
// scan for matching first character
|
|
while (*text != c) {
|
|
text++;
|
|
|
|
// arbitrary give-up counter
|
|
// FIXME: Make this more precise to avoid reading out of bounds
|
|
if (text - (textBase - textOff) >= 8000) {
|
|
warning("Object description for %d/%d not found", _objectType, _command);
|
|
return obname;
|
|
}
|
|
}
|
|
|
|
// found matching first character, so match the rest
|
|
const uint8 *s1 = obname;
|
|
const uint8 *s2 = text;
|
|
do {
|
|
s1++;
|
|
s2++;
|
|
} while (*s1 != ':' && *s1 != 0 && *s1 == *s2);
|
|
|
|
if (*s1 == ':' || *s1 == 0)
|
|
found = true; // (prefix) matched the entire object name
|
|
} while (!found);
|
|
|
|
// We found an object with the same name. The next loop iteration
|
|
// will check if this one again has an empty description.
|
|
}
|
|
}
|
|
|
|
void DreamWebEngine::dropObject() {
|
|
if (_commandType != 223) {
|
|
_commandType = 223;
|
|
if (!_pickUp) {
|
|
blank();
|
|
return;
|
|
}
|
|
commandWithOb(37, _objectType, _itemFrame);
|
|
}
|
|
|
|
if (_mouseButton == _oldButton || !(_mouseButton & 1))
|
|
return;
|
|
|
|
if (isItWorn(getEitherAd())) {
|
|
wornError();
|
|
return;
|
|
}
|
|
|
|
if (_realLocation != 47) {
|
|
byte flag, flagEx, type, flagX, flagY;
|
|
checkOne(_ryanX + 12, _ryanY + 12, &flag, &flagEx, &type, &flagX, &flagY);
|
|
|
|
if (flag >= 2) {
|
|
dropError();
|
|
return;
|
|
}
|
|
} else {
|
|
dropError();
|
|
return;
|
|
}
|
|
|
|
if (_mapXSize == 64 && _mapYSize == 64) {
|
|
// Inside lift
|
|
dropError();
|
|
return;
|
|
}
|
|
|
|
if (compare(_itemFrame, kExObjectType, "GUNA") || compare(_itemFrame, kExObjectType, "SHLD")) {
|
|
cantDrop();
|
|
return;
|
|
}
|
|
|
|
_objectType = kExObjectType;
|
|
DynObject *object = getExAd(_itemFrame);
|
|
object->mapad[0] = 0;
|
|
object->mapad[1] = ((_ryanX + 4) >> 4) + _mapX;
|
|
object->mapad[2] = (_ryanX + 4) & 0xF;
|
|
object->mapad[3] = ((_ryanY + 8) >> 4) + _mapY;
|
|
object->mapad[4] = (_ryanY + 8) & 0xF;
|
|
_pickUp = 0;
|
|
object->currentLocation = _realLocation;
|
|
}
|
|
|
|
bool DreamWebEngine::checkObjectSize() {
|
|
byte containerSize = getOpenedSlotSize();
|
|
DynObject *object = getEitherAd();
|
|
// If there is no size defined for the object in the editor, set its size
|
|
// to 6. This could be a bad idea, according to the original source.
|
|
byte objectSize = (object->objectSize != 255) ? object->objectSize : 6;
|
|
|
|
if (containerSize >= 100) {
|
|
// Special type of container: only objects of the same special type fit.
|
|
if (containerSize == objectSize)
|
|
return true;
|
|
|
|
errorMessage3();
|
|
return false;
|
|
}
|
|
|
|
if (objectSize >= 100) {
|
|
// Special type of object, but a regular container.
|
|
// Subtract 100 from the size to get its regular size.
|
|
objectSize -= 100;
|
|
}
|
|
|
|
if (containerSize >= objectSize)
|
|
return true;
|
|
|
|
errorMessage2();
|
|
return false;
|
|
}
|
|
|
|
void DreamWebEngine::selectOpenOb() {
|
|
uint8 slotSize, slotCount;
|
|
getAnyAd(&slotSize, &slotCount);
|
|
if (slotCount == 255) {
|
|
// Can't open the object
|
|
blank();
|
|
return;
|
|
}
|
|
|
|
if (_commandType != 224) {
|
|
_commandType = 224;
|
|
commandWithOb(38, _objectType, _command);
|
|
}
|
|
|
|
if (_mouseButton == _oldButton || !(_mouseButton & 1))
|
|
return;
|
|
|
|
_openedOb = _command;
|
|
_openedType = _objectType;
|
|
createPanel();
|
|
showPanel();
|
|
showMan();
|
|
examIcon();
|
|
showExit();
|
|
openInv();
|
|
openOb();
|
|
underTextLine();
|
|
readMouse();
|
|
showPointer();
|
|
workToScreen();
|
|
delPointer();
|
|
}
|
|
|
|
void DreamWebEngine::reExFromInv() {
|
|
ObjectRef objectId = findInvPos();
|
|
_commandType = objectId._type;
|
|
_command = objectId._index;
|
|
_examAgain = 1;
|
|
_pointerMode = 0;
|
|
}
|
|
|
|
void DreamWebEngine::swapWithInv() {
|
|
ObjectRef subject;
|
|
subject._type = _objectType;
|
|
subject._index = _itemFrame;
|
|
if (subject != _oldSubject || _commandType != 243) {
|
|
if (subject == _oldSubject)
|
|
_commandType = 243;
|
|
_oldSubject = subject;
|
|
commandWithOb(34, subject._type, subject._index);
|
|
}
|
|
|
|
if (_mouseButton == _oldButton || !(_mouseButton & 1))
|
|
return;
|
|
|
|
byte prevType = _objectType;
|
|
byte prevFrame = _itemFrame;
|
|
ObjectRef objectId = findInvPos();
|
|
_itemFrame = objectId._index;
|
|
_objectType = objectId._type;
|
|
DynObject *object = getEitherAd();
|
|
object->mapad[0] = 20;
|
|
object->mapad[1] = 255;
|
|
byte prevType2 = _objectType;
|
|
byte prevFrame2 = _itemFrame;
|
|
_objectType = prevType;
|
|
_itemFrame = prevFrame;
|
|
delPointer();
|
|
object = getEitherAd();
|
|
object->mapad[0] = 4;
|
|
object->mapad[1] = 255;
|
|
object->mapad[2] = _lastInvPos;
|
|
_objectType = prevType2;
|
|
_itemFrame = prevFrame2;
|
|
fillRyan();
|
|
readMouse();
|
|
showPointer();
|
|
workToScreen();
|
|
delPointer();
|
|
}
|
|
|
|
void DreamWebEngine::useOpened() {
|
|
if (_openedOb == 255)
|
|
return; // cannot use opened object
|
|
|
|
if (!_pickUp) {
|
|
outOfOpen();
|
|
return;
|
|
}
|
|
|
|
ObjectRef objectId = findOpenPos();
|
|
|
|
if (objectId._index != 255) {
|
|
swapWithOpen();
|
|
return;
|
|
}
|
|
|
|
if (_pickUp != 1) {
|
|
blank();
|
|
return;
|
|
}
|
|
|
|
objectId._type = _objectType;
|
|
objectId._index = _itemFrame;
|
|
if (objectId != _oldSubject || _commandType != 227) {
|
|
if (objectId == _oldSubject)
|
|
_commandType = 227;
|
|
_oldSubject = objectId;
|
|
commandWithOb(35, objectId._type, objectId._index);
|
|
}
|
|
|
|
if (_mouseButton == _oldButton || !(_mouseButton & 1))
|
|
return;
|
|
|
|
if (isItWorn(getEitherAd())) {
|
|
wornError();
|
|
return;
|
|
}
|
|
|
|
delPointer();
|
|
|
|
if (_itemFrame == _openedOb &&
|
|
_objectType == _openedType) {
|
|
errorMessage1();
|
|
return;
|
|
}
|
|
|
|
if (!checkObjectSize())
|
|
return;
|
|
|
|
_pickUp = 0;
|
|
DynObject *object = getEitherAd();
|
|
object->mapad[0] = _openedType;
|
|
object->mapad[1] = _openedOb;
|
|
object->mapad[2] = _lastInvPos;
|
|
object->mapad[3] = _realLocation;
|
|
fillOpen();
|
|
underTextLine();
|
|
readMouse();
|
|
useOpened();
|
|
showPointer();
|
|
workToScreen();
|
|
delPointer();
|
|
}
|
|
|
|
void DreamWebEngine::outOfOpen() {
|
|
if (_openedOb == 255)
|
|
return; // cannot use opened object
|
|
|
|
ObjectRef objectId = findOpenPos();
|
|
|
|
if (objectId._index == 255) {
|
|
blank();
|
|
return;
|
|
}
|
|
|
|
if (objectId != _oldSubject || _commandType != 228) {
|
|
if (objectId == _oldSubject)
|
|
_commandType = 228;
|
|
_oldSubject = objectId;
|
|
commandWithOb(36, objectId._type, objectId._index);
|
|
}
|
|
|
|
if (_mouseButton == _oldButton)
|
|
return; // notletgo4
|
|
|
|
if (_mouseButton != 1)
|
|
return;
|
|
|
|
delPointer();
|
|
_pickUp = 1;
|
|
objectId = findOpenPos();
|
|
_objectType = objectId._type;
|
|
_itemFrame = objectId._index;
|
|
|
|
if (_objectType != kExObjectType) {
|
|
assert(objectId._type == kFreeObjectType);
|
|
_itemFrame = transferToEx(objectId._index);
|
|
_objectType = kExObjectType;
|
|
}
|
|
|
|
DynObject *object = getEitherAd();
|
|
object->mapad[0] = 20;
|
|
object->mapad[1] = 255;
|
|
|
|
fillOpen();
|
|
underTextLine();
|
|
readMouse();
|
|
useOpened();
|
|
showPointer();
|
|
workToScreen();
|
|
delPointer();
|
|
}
|
|
|
|
void DreamWebEngine::swapWithOpen() {
|
|
ObjectRef subject;
|
|
subject._type = _objectType;
|
|
subject._index = _itemFrame;
|
|
if (subject != _oldSubject || _commandType != 242) {
|
|
if (subject == _oldSubject)
|
|
_commandType = 242;
|
|
_oldSubject = subject;
|
|
commandWithOb(34, subject._type, subject._index);
|
|
}
|
|
|
|
if (_mouseButton == _oldButton || !(_mouseButton & 1))
|
|
return;
|
|
|
|
if (isItWorn(getEitherAd())) {
|
|
wornError();
|
|
return;
|
|
}
|
|
|
|
delPointer();
|
|
|
|
if (_itemFrame == _openedOb &&
|
|
_objectType == _openedType) {
|
|
errorMessage1();
|
|
return;
|
|
}
|
|
|
|
if (!checkObjectSize())
|
|
return;
|
|
|
|
byte prevType = _objectType;
|
|
byte prevFrame = _itemFrame;
|
|
ObjectRef objectId = findOpenPos();
|
|
_objectType = objectId._type;
|
|
_itemFrame = objectId._index;
|
|
|
|
if (_objectType != kExObjectType) {
|
|
assert(objectId._type == kFreeObjectType);
|
|
_itemFrame = transferToEx(objectId._index);
|
|
_objectType = kExObjectType;
|
|
}
|
|
|
|
DynObject *object = getEitherAd();
|
|
object->mapad[0] = 20;
|
|
object->mapad[1] = 255;
|
|
|
|
byte prevType2 = _objectType;
|
|
byte prevFrame2 = _itemFrame;
|
|
_objectType = prevType;
|
|
_itemFrame = prevFrame;
|
|
object = getEitherAd();
|
|
object->mapad[0] = _openedType;
|
|
object->mapad[1] = _openedOb;
|
|
object->mapad[2] = _lastInvPos;
|
|
object->mapad[3] = _realLocation;
|
|
_objectType = prevType2;
|
|
_itemFrame = prevFrame2;
|
|
fillOpen();
|
|
fillRyan();
|
|
underTextLine();
|
|
readMouse();
|
|
useOpened();
|
|
showPointer();
|
|
workToScreen();
|
|
delPointer();
|
|
}
|
|
|
|
ObjectRef DreamWebEngine::findOpenPos() {
|
|
uint8 pos = (_mouseX - kInventx) / kItempicsize;
|
|
_lastInvPos = pos;
|
|
|
|
return _openInvList[pos];
|
|
}
|
|
|
|
byte DreamWebEngine::transferToEx(uint8 from) {
|
|
emergencyPurge(from);
|
|
|
|
byte pos = getExPos();
|
|
DynObject *exObject = getExAd(pos);
|
|
|
|
DynObject *freeObject = getFreeAd(from);
|
|
|
|
memcpy(exObject, freeObject, sizeof(DynObject));
|
|
|
|
exObject->currentLocation = _realLocation;
|
|
exObject->initialLocation = _realLocation;
|
|
exObject->index = from;
|
|
exObject->mapad[0] = 4;
|
|
exObject->mapad[1] = 255;
|
|
exObject->mapad[2] = _lastInvPos;
|
|
|
|
transferFrame(from, pos, 0);
|
|
transferFrame(from, pos, 1);
|
|
transferText(from, pos);
|
|
|
|
freeObject->mapad[0] = 254;
|
|
|
|
pickupConts(from, pos);
|
|
|
|
return pos;
|
|
}
|
|
|
|
void DreamWebEngine::fillOpen() {
|
|
delTextLine();
|
|
uint8 size = getOpenedSlotCount();
|
|
if (size > 4)
|
|
size = 4;
|
|
findAllOpen();
|
|
for (uint8 i = 0; i < size; ++i) {
|
|
uint8 index = _openInvList[i]._index;
|
|
uint8 type = _openInvList[i]._type;
|
|
obToInv(index, type, kInventx + i * kItempicsize, kInventy + 96);
|
|
}
|
|
underTextLine();
|
|
}
|
|
|
|
void DreamWebEngine::findAllOpen() {
|
|
memset(_openInvList, 0xFF, 32);
|
|
|
|
for (uint8 i = 0; i < kNumexobjects; ++i) {
|
|
const DynObject *obj = getExAd(i);
|
|
if (obj->mapad[1] != _openedOb)
|
|
continue;
|
|
if (obj->mapad[0] != _openedType)
|
|
continue;
|
|
if (_openedType != kExObjectType && obj->mapad[3] != _realLocation)
|
|
continue;
|
|
uint8 slot = obj->mapad[2];
|
|
assert(slot < 16);
|
|
_openInvList[slot]._index = i;
|
|
_openInvList[slot]._type = kExObjectType;
|
|
}
|
|
|
|
for (uint8 i = 0; i < 80; ++i) {
|
|
const DynObject *obj = getFreeAd(i);
|
|
if (obj->mapad[1] != _openedOb)
|
|
continue;
|
|
if (obj->mapad[0] != _openedType)
|
|
continue;
|
|
uint8 slot = obj->mapad[2];
|
|
_openInvList[slot]._index = i;
|
|
_openInvList[slot]._type = kFreeObjectType;
|
|
}
|
|
}
|
|
|
|
void DreamWebEngine::pickupConts(uint8 from, uint8 containerEx) {
|
|
const DynObject *obj = getFreeAd(from);
|
|
|
|
if (obj->slotCount == 255)
|
|
return; // not openable
|
|
|
|
for (uint8 index = 0; index < 80; ++index) {
|
|
DynObject *freeObj = getFreeAd(index);
|
|
|
|
if (freeObj->mapad[0] != kFreeObjectType)
|
|
continue;
|
|
if (freeObj->mapad[1] != from)
|
|
continue;
|
|
|
|
uint8 pos = getExPos();
|
|
DynObject *exObj = getExAd(pos);
|
|
|
|
memcpy(exObj, freeObj, sizeof(DynObject));
|
|
exObj->currentLocation = _realLocation;
|
|
exObj->initialLocation = _realLocation;
|
|
exObj->index = index;
|
|
exObj->mapad[0] = 4; // kExObjectType?
|
|
exObj->mapad[1] = containerEx;
|
|
|
|
transferFrame(index, pos, 0);
|
|
transferFrame(index, pos, 1);
|
|
transferText(index, pos);
|
|
|
|
freeObj->mapad[0] = 0xFF;
|
|
}
|
|
}
|
|
|
|
void DreamWebEngine::incRyanPage() {
|
|
commandOnlyCond(31, 222);
|
|
|
|
if (_mouseButton == _oldButton || !(_mouseButton & 1))
|
|
return;
|
|
|
|
_vars._ryanPage = (_mouseX - (kInventx + 167)) / 18;
|
|
|
|
delPointer();
|
|
fillRyan();
|
|
readMouse();
|
|
showPointer();
|
|
workToScreen();
|
|
delPointer();
|
|
}
|
|
|
|
void DreamWebEngine::emergencyPurge(uint8 from) {
|
|
debug(2, "Ex memory: frames %d/%d, text %d/%d", _vars._exFramePos, kExframeslen, _vars._exTextPos, kExtextlen);
|
|
|
|
uint16 frameBytesNeeded = 0;
|
|
for (int offset = 0; offset <= 1; ++offset) {
|
|
const Frame &freeFrame = _freeFrames._frames[3 * from + offset];
|
|
frameBytesNeeded += freeFrame.width * freeFrame.height;
|
|
}
|
|
const uint16 textBytesNeeded = strlen(_freeDesc.getString(from)) + 1;
|
|
|
|
while (_vars._exFramePos + frameBytesNeeded > kExframeslen ||
|
|
_vars._exTextPos + textBytesNeeded > kExtextlen)
|
|
{
|
|
purgeAnItem();
|
|
debug(2, "Ex memory after purging: frames %d/%d, text %d/%d", _vars._exFramePos, kExframeslen, _vars._exTextPos, kExtextlen);
|
|
}
|
|
}
|
|
|
|
void DreamWebEngine::purgeAnItem() {
|
|
const DynObject *extraObjects = _exData;
|
|
|
|
|
|
for (uint i = 0; i < kNumexobjects; ++i) {
|
|
if (extraObjects[i].mapad[0] == 0 &&
|
|
(extraObjects[i].objId[0] == 255 || extraObjects[i].objId[0] == 2) &&
|
|
extraObjects[i].initialLocation != _realLocation) {
|
|
debug(1, "Purging ex object %d", i);
|
|
deleteExObject(i);
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < kNumexobjects; ++i) {
|
|
if (extraObjects[i].mapad[0] == 0 && extraObjects[i].objId[0] == 255) {
|
|
debug(1, "Purging ex object %d", i);
|
|
deleteExObject(i);
|
|
return;
|
|
}
|
|
}
|
|
|
|
error("Out of Ex object memory");
|
|
}
|
|
|
|
void DreamWebEngine::dropError() {
|
|
_commandType = 255;
|
|
delPointer();
|
|
printMessage(76, 21, 56, 240, 240 & 1);
|
|
workToScreenM();
|
|
hangOnP(50);
|
|
showPanel();
|
|
showMan();
|
|
examIcon();
|
|
_commandType = 255;
|
|
workToScreenM();
|
|
}
|
|
|
|
void DreamWebEngine::cantDrop() {
|
|
_commandType = 255;
|
|
delPointer();
|
|
printMessage(76, 21, 24, 240, 240 & 1);
|
|
workToScreenM();
|
|
hangOnP(50);
|
|
showPanel();
|
|
showMan();
|
|
examIcon();
|
|
_commandType = 255;
|
|
workToScreenM();
|
|
}
|
|
|
|
void DreamWebEngine::examineInventory() {
|
|
commandOnlyCond(32, 249);
|
|
|
|
if (!(_mouseButton & 1))
|
|
return;
|
|
|
|
createPanel();
|
|
showPanel();
|
|
showMan();
|
|
showExit();
|
|
examIcon();
|
|
_pickUp = 0;
|
|
_invOpen = 2;
|
|
openInv();
|
|
workToScreenM();
|
|
}
|
|
|
|
void DreamWebEngine::openInv() {
|
|
_invOpen = 1;
|
|
printMessage(80, 58 - 10, 61, 240, (240 & 1));
|
|
fillRyan();
|
|
_commandType = 255;
|
|
}
|
|
|
|
void DreamWebEngine::pickupOb(uint8 command, uint8 pos) {
|
|
_lastInvPos = pos;
|
|
_objectType = kFreeObjectType;
|
|
_itemFrame = command;
|
|
_command = command;
|
|
//uint8 dummy;
|
|
//getAnyAd(&dummy, &dummy); // was in the original source, seems useless here
|
|
transferToEx(command);
|
|
}
|
|
|
|
void DreamWebEngine::initialInv() {
|
|
if (_realLocation != 24)
|
|
return;
|
|
|
|
pickupOb(11, 5);
|
|
pickupOb(12, 6);
|
|
pickupOb(13, 7);
|
|
pickupOb(14, 8);
|
|
pickupOb(18, 0);
|
|
pickupOb(19, 1);
|
|
pickupOb(20, 9);
|
|
pickupOb(16, 2);
|
|
_vars._watchMode = 1;
|
|
_vars._reelToHold = 0;
|
|
_vars._endOfHoldReel = 6;
|
|
_vars._watchSpeed = 1;
|
|
_vars._speedCount = 1;
|
|
switchRyanOff();
|
|
}
|
|
|
|
} // End of namespace DreamWeb
|