scummvm/engines/dreamweb/object.cpp

1116 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 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.
*
*/
#include "dreamweb/dreamweb.h"
namespace DreamGen {
void DreamBase::showRyanPage() {
showFrame(engine->icons1(), kInventx + 167, kInventy - 12, 12, 0);
showFrame(engine->icons1(), kInventx + 167 + 18 * data.byte(kRyanpage), kInventy - 12, 13 + data.byte(kRyanpage), 0);
}
void DreamBase::findAllRyan() {
memset(_ryanInvList, 0xff, 60);
for (size_t 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 DreamBase::fillRyan() {
ObjectRef *inv = &_ryanInvList[data.byte(kRyanpage) * 10];
findAllRyan();
for (size_t i = 0; i < 2; ++i) {
for (size_t j = 0; j < 5; ++j) {
obToInv(inv->_index, inv->_type, kInventx + j * kItempicsize, kInventy + i * kItempicsize);
++inv;
}
}
showRyanPage();
}
bool DreamBase::isItWorn(const DynObject *object) {
return (object->id[0] == 'W'-'A') && (object->id[1] == 'E'-'A');
}
void DreamBase::wornError() {
data.byte(kCommandtype) = 255;
delPointer();
printMessage(76, 21, 57, 240, false);
workToScreenM();
hangOnP(50);
showPanel();
showMan();
examIcon();
data.byte(kCommandtype) = 255;
workToScreenM();
}
void DreamBase::makeWorn(DynObject *object) {
object->id[0] = 'W'-'A';
object->id[1] = 'E'-'A';
}
void DreamBase::obToInv(uint8 index, uint8 flag, uint16 x, uint16 y) {
showFrame(engine->icons1(), x - 2, y - 1, 10, 0);
if (index == 0xff)
return;
Frame *extras = (Frame *)getSegment(data.word(kExtras)).ptr(0, 0);
Frame *frees = (Frame *)getSegment(data.word(kFreeframes)).ptr(0, 0);
Frame *frames = (flag == 4) ? extras : frees;
showFrame(frames, x + 18, y + 19, 3 * index + 1, 128);
const DynObject *object = (const DynObject *)getAnyAdDir(index, flag);
bool worn = isItWorn(object);
if (worn)
showFrame(engine->icons1(), x - 3, y - 2, 7, 0);
}
void DreamBase::obPicture() {
if (data.byte(kObjecttype) == kSetObjectType1)
return;
Frame *frames;
if (data.byte(kObjecttype) == kExObjectType)
frames = (Frame *)getSegment(data.word(kExtras)).ptr(0, 0);
else
frames = (Frame *)getSegment(data.word(kFreeframes)).ptr(0, 0);
uint8 frame = 3 * data.byte(kCommand) + 1;
showFrame(frames, 160, 68, frame, 0x80);
}
void DreamBase::obIcons() {
uint8 value1, value2;
getAnyAd(&value1, &value2);
if (value1 != 0xff) {
// can open it
showFrame(engine->icons2(), 210, 1, 4, 0);
}
showFrame(engine->icons2(), 260, 1, 1, 0);
}
void DreamBase::examineOb(bool examineAgain) {
data.byte(kPointermode) = 0;
data.word(kTimecount) = 0;
while (true) {
if (examineAgain) {
data.byte(kInmaparea) = 0;
data.byte(kExamagain) = 0;
data.byte(kOpenedob) = 255;
data.byte(kOpenedtype) = 255;
data.byte(kInvopen) = 0;
data.byte(kObjecttype) = data.byte(kCommandtype);
data.byte(kItemframe) = 0;
data.byte(kPointerframe) = 0;
createPanel();
showPanel();
showMan();
showExit();
obIcons();
obPicture();
describeOb();
underTextLine();
data.byte(kCommandtype) = 255;
readMouse();
showPointer();
workToScreen();
delPointer();
examineAgain = false;
}
readMouse();
showPointer();
vSync();
dumpPointer();
dumpTextLine();
delPointer();
data.byte(kGetback) = 0;
switch (data.byte(kInvopen)) {
case 0: {
RectWithCallback<DreamBase> examList[] = {
{ 273,320,157,198,&DreamBase::getBackFromOb },
{ 260,300,0,44,&DreamBase::useObject },
{ 210,254,0,44,&DreamBase::selectOpenOb },
{ 144,176,64,96,&DreamBase::setPickup },
{ 0,50,50,200,&DreamBase::examineInventory },
{ 0,320,0,200,&DreamBase::blank },
{ 0xFFFF,0,0,0,0 }
};
checkCoords(examList);
break;
}
case 1: {
// Note: This table contains the non-constant _openChangeSize!
RectWithCallback<DreamBase> invList1[] = {
{ 273,320,157,198,&DreamBase::getBackFromOb },
{ 255,294,0,24,&DreamBase::dropObject },
{ kInventx+167,kInventx+167+(18*3),kInventy-18,kInventy-2,&DreamBase::incRyanPage },
{ kInventx,_openChangeSize,kInventy+100,kInventy+100+kItempicsize,&DreamBase::useOpened },
{ kInventx,kInventx+(5*kItempicsize),kInventy,kInventy+(2*kItempicsize),&DreamBase::inToInv },
{ 0,320,0,200,&DreamBase::blank },
{ 0xFFFF,0,0,0,0 }
};
checkCoords(invList1);
break;
}
default: {
RectWithCallback<DreamBase> withList1[] = {
{ 273,320,157,198,&DreamBase::getBackFromOb },
{ kInventx+167,kInventx+167+(18*3),kInventy-18,kInventy-2,&DreamBase::incRyanPage },
{ kInventx,kInventx+(5*kItempicsize), kInventy,kInventy+(2*kItempicsize),&DreamBase::selectOb },
{ 0,320,0,200,&DreamBase::blank },
{ 0xFFFF,0,0,0,0 }
};
checkCoords(withList1);
break;
}
}
if (_quitRequested)
break;
if (data.byte(kExamagain) != 0)
examineAgain = true;
else if (data.byte(kGetback) != 0)
break;
}
data.byte(kPickup) = 0;
if (data.word(kWatchingtime) != 0 || data.byte(kNewlocation) == 255) {
// isWatching
makeMainScreen();
}
data.byte(kInvopen) = 0;
data.byte(kOpenedob) = 255;
}
void DreamBase::inventory() {
if (data.byte(kMandead) == 1 || data.word(kWatchingtime) != 0) {
blank();
return;
}
if (data.byte(kCommandtype) != 239) {
data.byte(kCommandtype) = 239;
commandOnly(32);
}
if (data.word(kMousebutton) == data.word(kOldbutton))
return;
if (!(data.word(kMousebutton) & 1)) // only on left mouse button
return;
data.word(kTimecount) = 0;
data.byte(kPointermode) = 0;
data.byte(kInmaparea) = 0;
animPointer();
createPanel();
showPanel();
examIcon();
showMan();
showExit();
underTextLine();
data.byte(kPickup) = 0;
data.byte(kInvopen) = 2;
openInv();
readMouse();
showPointer();
workToScreen();
delPointer();
data.byte(kOpenedob) = 255;
examineOb(false);
}
void DreamBase::transferText(uint8 from, uint8 to) {
getSegment(data.word(kExtras)).word(kExtextdat + 2*to) = data.word(kExtextpos);
uint16 freeTextOffset = 2*from;
uint16 srcOffset = getSegment(data.word(kFreedesc)).word(kFreetextdat + freeTextOffset);
const char *src = (const char *)getSegment(data.word(kFreedesc)).ptr(kFreetext + srcOffset, 0);
char *dst = (char *)getSegment(data.word(kExtras)).ptr(kExtext + data.word(kExtextpos), 0);
size_t len = strlen(src);
memcpy(dst, src, len + 1);
data.word(kExtextpos) += len + 1;
}
void DreamBase::getBackFromOb() {
if (data.byte(kPickup) != 1)
getBack1();
else
blank();
}
byte DreamBase::getOpenedSlotCount() {
byte obj = data.byte(kOpenedob);
switch (data.byte(kOpenedtype)) {
case 4:
return getExAd(obj)->slotCount;
case 2:
return getFreeAd(obj)->slotCount;
default:
return getSetAd(obj)->slotCount;
}
}
byte DreamBase::getOpenedSlotSize() {
byte obj = data.byte(kOpenedob);
switch (data.byte(kOpenedtype)) {
case 4:
return getExAd(obj)->slotSize;
case 2:
return getFreeAd(obj)->slotSize;
default:
return getSetAd(obj)->slotSize;
}
}
void DreamBase::openOb() {
uint8 commandLine[64] = "OBJECT NAME ONE ";
copyName(data.byte(kOpenedtype), data.byte(kOpenedob), commandLine);
printMessage(kInventx, kInventy+86, 62, 240, false);
printDirect(commandLine, data.word(kLastxpos) + 5, kInventy+86, 220, false);
fillOpen();
_openChangeSize = getOpenedSlotCount() * kItempicsize + kInventx;
}
void DreamBase::identifyOb() {
if (data.word(kWatchingtime) != 0) {
blank();
return;
}
uint16 initialX = data.word(kMousex) - data.word(kMapadx);
uint16 initialY = data.word(kMousey) - data.word(kMapady);
if (initialX >= 22 * 8 || initialY >= 20 * 8) {
blank();
return;
}
byte x = initialX & 0xFF;
byte y = initialY & 0xFF;
data.byte(kInmaparea) = 1;
data.byte(kPointerspath) = findPathOfPoint(x, y);
data.byte(kPointerfirstpath) = findFirstPath(x, y);
if (checkIfEx(x, y) || checkIfFree(x, y) ||
checkIfPerson(x, y) || checkIfSet(x, y))
return; // finishidentify
x = (data.word(kMousex) - data.word(kMapadx)) & 0xFF;
y = (data.word(kMousey) - data.word(kMapady)) & 0xFF;
byte flag, flagEx, type, flagX, flagY;
checkOne(x, y, &flag, &flagEx, &type, &flagX, &flagY);
if (type != 0 && data.byte(kMandead) != 1)
obName(type, 3);
else
blank();
}
ObjectRef DreamBase::findInvPos() {
uint16 x = data.word(kMousex) - kInventx;
uint16 y = data.word(kMousey) - kInventy;
uint8 pos = (x / kItempicsize) + (y / kItempicsize) * 5;
uint8 invPos = data.byte(kRyanpage) * 10 + pos;
data.byte(kLastinvpos) = invPos;
return _ryanInvList[invPos];
}
void DreamBase::selectOb() {
ObjectRef objectId = findInvPos();
if (objectId._index == 255) {
blank();
return;
}
data.byte(kWithobject) = objectId._index;
data.byte(kWithtype) = objectId._type;
if (objectId != _oldSubject || data.byte(kCommandtype) != 221) {
if (objectId == _oldSubject)
data.byte(kCommandtype) = 221;
_oldSubject = objectId;
commandWithOb(0, objectId._type, objectId._index);
}
if (data.word(kMousebutton) == data.word(kOldbutton) || !(data.word(kMousebutton) & 1))
return;
delPointer();
data.byte(kInvopen) = 0;
useRoutine();
}
void DreamBase::setPickup() {
if (data.byte(kObjecttype) != kSetObjectType1 && data.byte(kObjecttype) != 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 (data.byte(kCommandtype) != 209) {
data.byte(kCommandtype) = 209;
commandWithOb(33, data.byte(kObjecttype), data.byte(kCommand));
}
if (data.word(kMousebutton) != 1 || data.word(kMousebutton) == data.word(kOldbutton))
return;
createPanel();
showPanel();
showMan();
showExit();
examIcon();
data.byte(kPickup) = 1;
data.byte(kInvopen) = 2;
if (data.byte(kObjecttype) != kExObjectType) {
assert(data.byte(kObjecttype) == kFreeObjectType);
data.byte(kOpenedob) = 255;
data.byte(kItemframe) = transferToEx(data.byte(kCommand));
data.byte(kObjecttype) = kExObjectType;
DynObject *object = getExAd(data.byte(kItemframe));
object->mapad[0] = 20;
object->mapad[1] = 255;
} else {
data.byte(kItemframe) = data.byte(kCommand);
data.byte(kOpenedob) = 255;
}
openInv();
workToScreenM();
}
void DreamBase::deleteExFrame(uint8 frameNum) {
Frame *frame = (Frame *)getSegment(data.word(kExtras)).ptr(kExframedata + sizeof(Frame)*frameNum, sizeof(Frame));
uint16 frameSize = frame->width * frame->height;
// Note: the original asm didn't subtract frameSize from remainder
uint16 remainder = kExframeslen - frame->ptr() - frameSize;
uint16 startOff = kExframes + frame->ptr();
uint16 endOff = startOff + frameSize;
// Shift frame data after this one down
memmove(getSegment(data.word(kExtras)).ptr(startOff, remainder), getSegment(data.word(kExtras)).ptr(endOff, remainder), remainder);
// Combined frame data is now frameSize smaller
data.word(kExframepos) -= frameSize;
// Adjust all frame pointers pointing into the shifted data
for (unsigned int i = 0; i < 3*kNumexobjects; ++i) {
frame = (Frame *)getSegment(data.word(kExtras)).ptr(kExframedata + sizeof(Frame)*i, sizeof(Frame));
if (frame->ptr() >= startOff)
frame->setPtr(frame->ptr() - frameSize);
}
}
void DreamBase::deleteExText(uint8 textNum) {
uint16 offset = getSegment(data.word(kExtras)).word(kExtextdat + 2*textNum);
uint16 startOff = kExtext + offset;
uint16 textSize = strlen((char *)getSegment(data.word(kExtras)).ptr(startOff, 0)) + 1;
uint16 endOff = startOff + textSize;
uint16 remainder = kExtextlen - offset - textSize;
// Shift text data after this one down
memmove(getSegment(data.word(kExtras)).ptr(startOff, remainder), getSegment(data.word(kExtras)).ptr(endOff, remainder), remainder);
// Combined text data is now frameSize smaller
data.word(kExtextpos) -= textSize;
// Adjust all text pointers pointing into the shifted data
for (unsigned int i = 0; i < kNumexobjects; ++i) {
uint16 t = getSegment(data.word(kExtras)).word(kExtextdat + 2*i);
if (t >= offset + textSize)
getSegment(data.word(kExtras)).word(kExtextdat + 2*i) = t - textSize;
}
}
void DreamBase::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 DreamBase::removeObFromInv() {
if (data.byte(kCommand) == 100)
return; // object doesn't exist
assert(data.byte(kObjecttype) == kExObjectType);
deleteExObject(data.byte(kCommand));
}
void DreamBase::inToInv() {
if (!data.byte(kPickup)) {
outOfInv();
return;
}
ObjectRef subject = findInvPos();
if (subject._index != 255) {
swapWithInv();
return;
}
subject._type = data.byte(kObjecttype);
subject._index = data.byte(kItemframe);
if (subject != _oldSubject || data.byte(kCommandtype) != 220) {
if (subject == _oldSubject)
data.byte(kCommandtype) = 220;
_oldSubject = subject;
commandWithOb(35, subject._type, subject._index);
}
if (data.word(kMousebutton) == data.word(kOldbutton) || !(data.word(kMousebutton) & 1))
return; // notletgo2
delPointer();
DynObject *object = getExAd(data.byte(kItemframe));
object->mapad[0] = 4;
object->mapad[1] = 255;
object->mapad[2] = data.byte(kLastinvpos);
data.byte(kPickup) = 0;
fillRyan();
readMouse();
showPointer();
outOfInv();
workToScreen();
delPointer();
}
void DreamBase::outOfInv() {
ObjectRef subject = findInvPos();
if (subject._index == 255) {
blank();
return;
}
if (data.word(kMousebutton) == 2) {
reExFromInv();
return;
}
if (subject != _oldSubject || data.byte(kCommandtype) != 221) {
if (subject == _oldSubject)
data.byte(kCommandtype) = 221;
_oldSubject = subject;
commandWithOb(36, subject._type, subject._index);
}
if (data.word(kMousebutton) == data.word(kOldbutton) || !(data.word(kMousebutton) & 1))
return;
delPointer();
data.byte(kPickup) = 1;
subject = findInvPos();
data.byte(kObjecttype) = subject._type;
data.byte(kItemframe) = 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 DreamBase::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 *DreamBase::getObTextStart() {
uint16 textSeg, textDatOff, textOff;
if (data.byte(kObjecttype) == kFreeObjectType) {
textSeg = data.word(kFreedesc);
textDatOff = kFreetextdat;
textOff = kFreetext;
} else if (data.byte(kObjecttype) == kSetObjectType1) {
textSeg = data.word(kSetdesc);
textDatOff = kSettextdat;
textOff = kSettext;
} else {
textSeg = data.word(kExtras);
textDatOff = kExtextdat;
textOff = kExtext;
}
const uint8 *textBase = getSegment(textSeg).ptr(textOff, 0);
const uint8 *text = textBase + getSegment(textSeg).word(textDatOff + 2*data.byte(kCommand));
if (data.byte(kObjecttype) != 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
if (text - (textBase - textOff) >= 8000) {
warning("Object description for %d/%d not found", data.byte(kObjecttype), data.byte(kCommand));
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 DreamBase::dropObject() {
if (data.byte(kCommandtype) != 223) {
data.byte(kCommandtype) = 223;
if (!data.byte(kPickup)) {
blank();
return;
}
commandWithOb(37, data.byte(kObjecttype), data.byte(kItemframe));
}
if (data.word(kMousebutton) == data.word(kOldbutton) || !(data.word(kMousebutton) & 1))
return;
if (isItWorn(getEitherAdCPP())) {
wornError();
return;
}
if (data.byte(kReallocation) != 47) {
byte flag, flagEx, type, flagX, flagY;
checkOne(data.byte(kRyanx) + 12, data.byte(kRyany) + 12, &flag, &flagEx, &type, &flagX, &flagY);
if (flag >= 2) {
dropError();
return;
}
} else {
dropError();
return;
}
if (data.byte(kMapxsize) == 64 && data.byte(kMapysize) == 64) {
// Inside lift
dropError();
return;
}
if (compare(data.byte(kItemframe), 4, "GUNA") || compare(data.byte(kItemframe), 4, "SHLD")) {
cantDrop();
return;
}
data.byte(kObjecttype) = 4;
DynObject *object = getExAd(data.byte(kItemframe));
object->mapad[0] = 0;
object->mapad[1] = ((data.byte(kRyanx) + 4) >> 4) + data.byte(kMapx);
object->mapad[2] = (data.byte(kRyanx) + 4) & 0xF;
object->mapad[3] = ((data.byte(kRyany) + 8) >> 4) + data.byte(kMapy);
object->mapad[4] = (data.byte(kRyany) + 8) & 0xF;
data.byte(kPickup) = 0;
object->currentLocation = data.byte(kReallocation);
}
bool DreamBase::checkObjectSize() {
byte containerSize = getOpenedSlotSize();
DynObject *object = getEitherAdCPP();
// 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 DreamBase::selectOpenOb() {
uint8 slotSize, slotCount;
getAnyAd(&slotSize, &slotCount);
if (slotCount == 255) {
// Can't open the object
blank();
return;
}
if (data.byte(kCommandtype) != 224) {
data.byte(kCommandtype) = 224;
commandWithOb(38, data.byte(kObjecttype), data.byte(kCommand));
}
if (data.word(kMousebutton) == data.word(kOldbutton) || !(data.word(kMousebutton) & 1))
return;
data.byte(kOpenedob) = data.byte(kCommand);
data.byte(kOpenedtype) = data.byte(kObjecttype);
createPanel();
showPanel();
showMan();
examIcon();
showExit();
openInv();
openOb();
underTextLine();
readMouse();
showPointer();
workToScreen();
delPointer();
}
void DreamBase::reExFromInv() {
ObjectRef objectId = findInvPos();
data.byte(kCommandtype) = objectId._type;
data.byte(kCommand) = objectId._index;
data.byte(kExamagain) = 1;
data.byte(kPointermode) = 0;
}
void DreamBase::swapWithInv() {
ObjectRef subject;
subject._type = data.byte(kObjecttype);
subject._index = data.byte(kItemframe);
if (subject != _oldSubject || data.byte(kCommandtype) != 243) {
if (subject == _oldSubject)
data.byte(kCommandtype) = 243;
_oldSubject = subject;
commandWithOb(34, subject._type, subject._index);
}
if (data.word(kMousebutton) == data.word(kOldbutton) || !(data.word(kMousebutton) & 1))
return;
byte prevType = data.byte(kObjecttype);
byte prevFrame = data.byte(kItemframe);
ObjectRef objectId = findInvPos();
data.byte(kItemframe) = objectId._index;
data.byte(kObjecttype) = objectId._type;
DynObject *object = getEitherAdCPP();
object->mapad[0] = 20;
object->mapad[1] = 255;
byte prevType2 = data.byte(kObjecttype);
byte prevFrame2 = data.byte(kItemframe);
data.byte(kObjecttype) = prevType;
data.byte(kItemframe) = prevFrame;
delPointer();
object = getEitherAdCPP();
object->mapad[0] = 4;
object->mapad[1] = 255;
object->mapad[2] = data.byte(kLastinvpos);
data.byte(kObjecttype) = prevType2;
data.byte(kItemframe) = prevFrame2;
fillRyan();
readMouse();
showPointer();
workToScreen();
delPointer();
}
void DreamBase::useOpened() {
if (data.byte(kOpenedob) == 255)
return; // cannot use opened object
if (!data.byte(kPickup)) {
outOfOpen();
return;
}
ObjectRef objectId = findOpenPos();
if (objectId._index != 255) {
swapWithOpen();
return;
}
if (data.byte(kPickup) != 1) {
blank();
return;
}
objectId._type = data.byte(kObjecttype);
objectId._index = data.byte(kItemframe);
if (objectId != _oldSubject || data.byte(kCommandtype) != 227) {
if (objectId == _oldSubject)
data.byte(kCommandtype) = 227;
_oldSubject = objectId;
commandWithOb(35, objectId._type, objectId._index);
}
if (data.word(kMousebutton) == data.word(kOldbutton) || !(data.word(kMousebutton) & 1))
return;
if (isItWorn(getEitherAdCPP())) {
wornError();
return;
}
delPointer();
if (data.byte(kItemframe) == data.byte(kOpenedob) &&
data.byte(kObjecttype) == data.byte(kOpenedtype)) {
errorMessage1();
return;
}
if (!checkObjectSize())
return;
data.byte(kPickup) = 0;
DynObject *object = getEitherAdCPP();
object->mapad[0] = data.byte(kOpenedtype);
object->mapad[1] = data.byte(kOpenedob);
object->mapad[2] = data.byte(kLastinvpos);
object->mapad[3] = data.byte(kReallocation);
fillOpen();
underTextLine();
readMouse();
useOpened();
showPointer();
workToScreen();
delPointer();
}
void DreamBase::outOfOpen() {
if (data.byte(kOpenedob) == 255)
return; // cannot use opened object
ObjectRef objectId = findOpenPos();
if (objectId._index == 255) {
blank();
return;
}
if (objectId != _oldSubject || data.byte(kCommandtype) != 228) {
if (objectId == _oldSubject)
data.byte(kCommandtype) = 228;
_oldSubject = objectId;
commandWithOb(36, objectId._type, objectId._index);
}
if (data.word(kMousebutton) == data.word(kOldbutton))
return; // notletgo4
if (data.word(kMousebutton) != 1) {
if (data.word(kMousebutton) == 2)
reExFromOpen();
return;
}
delPointer();
data.byte(kPickup) = 1;
objectId = findOpenPos();
data.byte(kObjecttype) = objectId._type;
data.byte(kItemframe) = objectId._index;
if (data.byte(kObjecttype) != kExObjectType) {
assert(objectId._type == kFreeObjectType);
data.byte(kItemframe) = transferToEx(objectId._index);
data.byte(kObjecttype) = kExObjectType;
}
DynObject *object = getEitherAdCPP();
object->mapad[0] = 20;
object->mapad[1] = 255;
fillOpen();
underTextLine();
readMouse();
useOpened();
showPointer();
workToScreen();
delPointer();
}
void DreamBase::swapWithOpen() {
ObjectRef subject;
subject._type = data.byte(kObjecttype);
subject._index = data.byte(kItemframe);
if (subject != _oldSubject || data.byte(kCommandtype) != 242) {
if (subject == _oldSubject)
data.byte(kCommandtype) = 242;
_oldSubject = subject;
commandWithOb(34, subject._type, subject._index);
}
if (data.word(kMousebutton) == data.word(kOldbutton) || !(data.word(kMousebutton) & 1))
return;
if (isItWorn(getEitherAdCPP())) {
wornError();
return;
}
delPointer();
if (data.byte(kItemframe) == data.byte(kOpenedob) &&
data.byte(kObjecttype) == data.byte(kOpenedtype)) {
errorMessage1();
return;
}
if (!checkObjectSize())
return;
byte prevType = data.byte(kObjecttype);
byte prevFrame = data.byte(kItemframe);
ObjectRef objectId = findOpenPos();
data.byte(kObjecttype) = objectId._type;
data.byte(kItemframe) = objectId._index;
if (data.byte(kObjecttype) != kExObjectType) {
assert(objectId._type == kFreeObjectType);
data.byte(kItemframe) = transferToEx(objectId._index);
data.byte(kObjecttype) = kExObjectType;
}
DynObject *object = getEitherAdCPP();
object->mapad[0] = 20;
object->mapad[1] = 255;
byte prevType2 = data.byte(kObjecttype);
byte prevFrame2 = data.byte(kItemframe);
data.byte(kObjecttype) = prevType;
data.byte(kItemframe) = prevFrame;
object = getEitherAdCPP();
object->mapad[0] = data.byte(kOpenedtype);
object->mapad[1] = data.byte(kOpenedob);
object->mapad[2] = data.byte(kLastinvpos);
object->mapad[3] = data.byte(kReallocation);
data.byte(kObjecttype) = prevType2;
data.byte(kItemframe) = prevFrame2;
fillOpen();
fillRyan();
underTextLine();
readMouse();
useOpened();
showPointer();
workToScreen();
delPointer();
}
ObjectRef DreamBase::findOpenPos() {
uint8 pos = (data.word(kMousex) - kInventx) / kItempicsize;
data.byte(kLastinvpos) = pos;
return _openInvList[pos];
}
byte DreamBase::transferToEx(uint8 from) {
emergencyPurge();
byte pos = getExPos();
DynObject *exObject = getExAd(pos);
DynObject *freeObject = getFreeAd(from);
memcpy(exObject, freeObject, sizeof(DynObject));
exObject->currentLocation = data.byte(kReallocation);
exObject->initialLocation = data.byte(kReallocation);
exObject->index = from;
exObject->mapad[0] = 4;
exObject->mapad[1] = 255;
exObject->mapad[2] = data.byte(kLastinvpos);
transferFrame(from, pos, 0);
transferFrame(from, pos, 1);
transferText(from, pos);
freeObject->mapad[0] = 254;
pickupConts(from, pos);
return pos;
}
void DreamBase::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 DreamBase::findAllOpen() {
memset(_openInvList, 0xFF, 32);
for (uint8 i = 0; i < kNumexobjects; ++i) {
const DynObject *obj = getExAd(i);
if (obj->mapad[1] != data.byte(kOpenedob))
continue;
if (obj->mapad[0] != data.byte(kOpenedtype))
continue;
if (data.byte(kOpenedtype) != kExObjectType && obj->mapad[3] != data.byte(kReallocation))
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] != data.byte(kOpenedob))
continue;
if (obj->mapad[0] != data.byte(kOpenedtype))
continue;
uint8 slot = obj->mapad[2];
_openInvList[slot]._index = i;
_openInvList[slot]._type = kFreeObjectType;
}
}
void DreamBase::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 = data.byte(kReallocation);
exObj->initialLocation = data.byte(kReallocation);
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;
}
}
} // End of namespace DreamGen