Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,293 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/bbdou_bubble.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
#include "illusions/dictionary.h"
#include "illusions/input.h"
namespace Illusions {
BbdouBubble::BbdouBubble(IllusionsEngine_BBDOU *vm, BbdouSpecialCode *bbdou)
: _vm(vm), _bbdou(bbdou) {
}
BbdouBubble::~BbdouBubble() {
}
void BbdouBubble::init() {
static const uint32 kTrailObjectIds[] = {
0x0004003B, 0x0004003C, 0x0004003D, 0x0004003E,
0x0004003F, 0x00040040, 0x00040041, 0x00040042,
0x00040043, 0x00040044, 0x00040045, 0x00040046,
0x00040047, 0x00040048, 0x00040049, 0x0004004A,
0x0004004B, 0x0004004C, 0x0004004D, 0x0004004E,
0x0004004F, 0x00040050, 0x00040051, 0x00040052,
0x00040053, 0x00040054, 0x00040055, 0x00040056,
0x00040057, 0x00040058, 0x00040059, 0x0004005A
};
static const uint32 kIconObjectIds[] = {
0x0004001B, 0x0004001C, 0x0004001D, 0x0004001E,
0x0004001F, 0x00040020, 0x00040021, 0x00040022,
0x00040023, 0x00040024, 0x00040025, 0x00040026,
0x00040027, 0x00040028, 0x00040029, 0x0004002A,
0x0004002B, 0x0004002C, 0x0004002D, 0x0004002E,
0x0004002F, 0x00040030, 0x00040031, 0x00040032,
0x00040033, 0x00040034, 0x00040035, 0x00040036,
0x00040037, 0x00040038, 0x00040039, 0x0004003A
};
_bubbleObjectId1 = 0x4005B;
_bubbleObjectId2 = 0x4005C;
for (uint i = 0; i < 32; ++i) {
_trailObjectIds[i] = kTrailObjectIds[i];
}
for (uint i = 0; i < 32; ++i) {
_icons[i]._objectId = kIconObjectIds[i];
_icons[i]._enabled = false;
_icons[i]._position.x = 0;
_icons[i]._position.y = 0;
_icons[i]._sequenceId = 0;
}
_currBubbleStyle = nullptr;
_showingBubbleStyle = nullptr;
_hidingBubbleStyle = nullptr;
_sourcePt.x = 0;
_sourcePt.y = 0;
_destPt.x = 0;
_destPt.y = 0;
}
void BbdouBubble::addBubbleStyle(uint32 showSequenceId, uint32 hideSequenceId, uint32 progResKeywordId,
uint32 namedPointId, int16 count, uint32 *namedPointIds) {
BubbleStyle style;
style._showSequenceId = showSequenceId;
style._hideSequenceId = hideSequenceId;
style._progResKeywordId = progResKeywordId;
style._baseNamedPointId = namedPointId;
style._count = count;
for (int16 i = 0; i < count; ++i) {
style._namedPointIds[i] = FROM_LE_32(namedPointIds[i]);
}
style._objectId = 0;
style._position.x = 0;
style._position.y = 0;
_bubbleStyles.push_back(style);
}
void BbdouBubble::show() {
if (_showingBubbleStyle) {
hide();
}
_showingBubbleStyle = _currBubbleStyle;
_currBubbleStyle = nullptr;
calcBubbleTrail(_sourcePt, _destPt);
Control *bubbleControl = _vm->_dict->getObjectControl(_showingBubbleStyle->_objectId);
bubbleControl->setActorPosition(_destPt);
bubbleControl->startSequenceActor(0x60057, 2, 0);
bubbleControl->startSequenceActor(_showingBubbleStyle->_showSequenceId, 2, 0);
bubbleControl->appearActor();
bubbleControl->deactivateObject();
for (uint i = 0; i < 32; ++i) {
if (_icons[i]._enabled) {
Control *iconControl = _vm->_dict->getObjectControl(_icons[i]._objectId);
iconControl->setActorPosition(_icons[i]._position);
iconControl->startSequenceActor(_icons[i]._sequenceId, 2, 0);
}
}
}
void BbdouBubble::hide() {
_hidingBubbleStyle = _showingBubbleStyle;
_showingBubbleStyle = nullptr;
if (_hidingBubbleStyle) {
Control *bubbleControl = _vm->_dict->getObjectControl(_hidingBubbleStyle->_objectId);
bubbleControl->startSequenceActor(_hidingBubbleStyle->_hideSequenceId, 2, 0);
for (uint i = 0; i < 32; ++i) {
Control *trailControl = _vm->_dict->getObjectControl(_trailObjectIds[i]);
trailControl->stopActor();
trailControl->disappearActor();
}
for (uint i = 0; i < 32; ++i) {
Control *iconControl = _vm->_dict->getObjectControl(_icons[i]._objectId);
iconControl->stopActor();
iconControl->disappearActor();
}
}
}
void BbdouBubble::selectBubbleStyle(int16 minCount, Common::Point sourcePt, Common::Point destPt, uint32 progResKeywordId) {
for (uint i = 0; i < 32; ++i) {
_icons[i]._enabled = false;
}
int16 maxCount = 32;
for (uint i = 0; i < _bubbleStyles.size(); ++i) {
BubbleStyle *style = &_bubbleStyles[i];
if (style->_count < maxCount && style->_count >= minCount &&
(progResKeywordId == 0 || progResKeywordId == style->_progResKeywordId)) {
maxCount = style->_count;
_currBubbleStyle = style;
}
}
_sourcePt = sourcePt;
_destPt = destPt;
_currBubbleStyle->_position = destPt;
_currBubbleStyle->_objectId = _bubbleObjectId1;
if (_showingBubbleStyle && _showingBubbleStyle->_objectId == _currBubbleStyle->_objectId)
_currBubbleStyle->_objectId = _bubbleObjectId2;
}
uint32 BbdouBubble::addBubbleIcon(uint positionIndex, uint32 sequenceId) {
for (uint i = 0; i < 32; ++i) {
BubbleIcon *icon = &_icons[i];
if (!icon->_enabled) {
Common::Point itemPos = _vm->getNamedPointPosition(_currBubbleStyle->_namedPointIds[positionIndex]);
Common::Point basePos = _vm->getNamedPointPosition(_currBubbleStyle->_baseNamedPointId);
icon->_enabled = true;
icon->_sequenceId = sequenceId;
icon->_position.x = itemPos.x + _currBubbleStyle->_position.x - basePos.x;
icon->_position.y = itemPos.y + _currBubbleStyle->_position.y - basePos.y;
return icon->_objectId;
}
}
return 0;
}
void BbdouBubble::calcBubbleTrail(Common::Point &sourcePt, Common::Point &destPt) {
const int kSequenceIdsCount = 10;
const float kDistanceBetweenPoints = 30.0;
static const uint32 kBubbleTrailSequenceIds[] = {
0x00060042, 0x00060043, 0x00060044, 0x00060045, 0x00060046,
0x00060047, 0x00060048, 0x00060049, 0x0006004A, 0x0006004B
};
static const int kIndexTbl[kSequenceIdsCount] = {4, 0, 8, 2, 6, 5, 1, 9, 3, 7};
int sequenceCounters[kSequenceIdsCount];
bool swapY;
int centerX, centerY;
float currentAngle, radius;
for (int i = 0; i < 32; ++i) {
Control *control = _vm->_dict->getObjectControl(_trailObjectIds[i]);
control->startSequenceActor(0x00060056, 2, 0);
}
for (int i = 0; i < kSequenceIdsCount; ++i) {
sequenceCounters[i] = 0;
}
if (destPt.y >= sourcePt.y) {
swapY = true;
if (sourcePt.x == destPt.x)
destPt.x = destPt.x + 20;
} else {
swapY = false;
if (sourcePt.y == destPt.y)
destPt.y = destPt.y + 20;
}
if (swapY) {
centerX = (destPt.x * destPt.x - (destPt.y - sourcePt.y) * (destPt.y - sourcePt.y) - sourcePt.x * sourcePt.x) / (2 * (destPt.x - sourcePt.x));
centerY = destPt.y;
radius = ABS(destPt.x - centerX);
} else {
centerX = destPt.x;
centerY = (destPt.y * destPt.y - (destPt.x - sourcePt.x) * (destPt.x - sourcePt.x) - sourcePt.y * sourcePt.y) / (2 * (destPt.y - sourcePt.y));
radius = ABS(destPt.y - centerY);
}
const float fullDistance = sqrt((destPt.y - sourcePt.y) * (destPt.y - sourcePt.y) + (destPt.x - sourcePt.x) * (destPt.x - sourcePt.x));
const float arcAngle = 2 * asin(CLIP(0.5 * fullDistance / radius, -1.0, 1.0));
const float arcLength = arcAngle * radius;
int pointsCount = (int)(arcLength / kDistanceBetweenPoints);
float partAngle = ABS(kDistanceBetweenPoints / radius);
for (int i = 0; i < pointsCount; ++i) {
++sequenceCounters[kIndexTbl[i % kSequenceIdsCount]];
}
if (!swapY) {
if (destPt.y < sourcePt.y) {
currentAngle = (float)M_PI * 0.5F;
} else {
currentAngle = (float)M_PI * 1.5F;
partAngle = -partAngle;
}
if (destPt.x < sourcePt.x)
partAngle = -partAngle;
} else {
if (destPt.x <= sourcePt.x) {
currentAngle = (float)M_PI;
} else {
currentAngle = 0.0;
partAngle = -partAngle;
}
if (destPt.y > sourcePt.y)
partAngle = -partAngle;
}
float angleStep = partAngle / (float)pointsCount * 0.5;
float angleIncr = (float)(pointsCount / 2) * angleStep + partAngle;
if (pointsCount > 32)
pointsCount = 32;
for (int i = 0; i < pointsCount; ++i) {
currentAngle += angleIncr;
angleIncr -= angleStep;
Common::Point newPoint(
centerX + _vm->getRandom(8) - 2 + (int)(cos(currentAngle) * radius),
centerY + _vm->getRandom(8) - 2 - (int)(sin(currentAngle) * radius));
Control *trailControl = _vm->_dict->getObjectControl(_trailObjectIds[i]);
for (int index = kSequenceIdsCount - 1; index >= 0; --index) {
if (sequenceCounters[index] > 0) {
--sequenceCounters[index];
trailControl->setActorPosition(newPoint);
trailControl->startSequenceActor(kBubbleTrailSequenceIds[index], 2, 0);
trailControl->appearActor();
trailControl->deactivateObject();
break;
}
}
}
}
} // End of namespace Illusions

View File

@@ -0,0 +1,82 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_BBDOU_BUBBLE_H
#define ILLUSIONS_BBDOU_BBDOU_BUBBLE_H
#include "illusions/specialcode.h"
#include "common/rect.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
class BbdouSpecialCode;
class Control;
struct BubbleStyle {
uint32 _showSequenceId;
uint32 _hideSequenceId;
int16 _count;
uint32 _progResKeywordId;
uint32 _baseNamedPointId;
uint32 _namedPointIds[32];
uint32 _objectId;
Common::Point _position;
BubbleStyle() : _count(0) {}
};
struct BubbleIcon {
uint32 _objectId;
bool _enabled;
Common::Point _position;
uint32 _sequenceId;
};
class BbdouBubble {
public:
BbdouBubble(IllusionsEngine_BBDOU *vm, BbdouSpecialCode *bbdou);
~BbdouBubble();
void init();
void addBubbleStyle(uint32 showSequenceId, uint32 hideSequenceId, uint32 progResKeywordId,
uint32 namedPointId, int16 count, uint32 *namedPointIds);
void show();
void hide();
void selectBubbleStyle(int16 minCount, Common::Point sourcePt, Common::Point destPt, uint32 progResKeywordId);
uint32 addBubbleIcon(uint positionIndex, uint32 sequenceId);
void calcBubbleTrail(Common::Point &sourcePt, Common::Point &destPt);
protected:
IllusionsEngine_BBDOU *_vm;
BbdouSpecialCode *_bbdou;
Common::Array<BubbleStyle> _bubbleStyles;
BubbleStyle *_currBubbleStyle;
BubbleStyle *_showingBubbleStyle;
BubbleStyle *_hidingBubbleStyle;
uint32 _trailObjectIds[32];
Common::Point _sourcePt;
Common::Point _destPt;
int _bubbleObjectId1;
int _bubbleObjectId2;
BubbleIcon _icons[32];
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_BBDOU_BUBBLE_H

View File

@@ -0,0 +1,244 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/bbdou_credits.h"
#include "illusions/actor.h"
#include "illusions/dictionary.h"
#include "illusions/textdrawer.h"
#include "illusions/time.h"
#include "illusions/resources/scriptresource.h"
namespace Illusions {
BbdouCredits::BbdouCredits(IllusionsEngine_BBDOU *vm)
: _vm(vm) {
}
BbdouCredits::~BbdouCredits() {
}
void BbdouCredits::start(uint32 endSignalPropertyId, float speedModifier) {
_endSignalPropertyId = endSignalPropertyId;
_currFontId = 0x120004;
_currLineIndex = 1;
_split = false;
// convertTextData();
initCreditsItems();
createCreditsThread(speedModifier);
}
void BbdouCredits::stop() {
freeCreditsItems();
}
void BbdouCredits::drawNextLine() {
uint leftIndex, rightIndex;
if (!readNextLine(leftIndex, rightIndex)) {
_vm->_scriptResource->_properties.set(_endSignalPropertyId, true);
return;
}
if (leftIndex) {
const char *leftText = getText(leftIndex);
if (leftText && strlen(leftText) != 0) {
uint32 objectId = getNextFreeObjectId();
int alignment = rightIndex ? 1 : 2;
drawTextToControl(objectId, leftText, alignment);
}
}
if (rightIndex) {
const char *rightText = getText(rightIndex);
if (rightText && strlen(rightText) != 0) {
uint32 objectId = getNextFreeObjectId();
drawTextToControl(objectId, rightText, 4);
}
}
}
void charToWChar(const char *text, uint16 *wtext, uint size) {
while (*text != 0 && size > 1) {
*wtext++ = (byte)*text++;
/*
byte c = (byte)*text++;
if (c > 127) c = 32;
*wtext = c;
debug("%04X", *wtext);
++wtext;
*/
--size;
}
*wtext++ = 0;
}
void BbdouCredits::drawTextToControl(uint32 objectId, const char *text, uint alignment) {
uint16 wtext[128];
charToWChar(text, wtext, ARRAYSIZE(wtext));
Control *control = _vm->getObjectControl(objectId);
FontResource *font = _vm->_dict->findFont(_currFontId);
TextDrawer textDrawer;
WidthHeight dimensions;
uint16 *outText;
control->getActorFrameDimensions(dimensions);
control->fillActor(0);
textDrawer.wrapText(font, wtext, &dimensions, Common::Point(0, 0), alignment, outText);
textDrawer.drawText(_vm->_screen, control->_actor->_surface, 0, 0);
control->_actor->_flags |= Illusions::ACTOR_FLAG_4000;
}
bool BbdouCredits::readNextLine(uint &leftIndex, uint &rightIndex) {
bool done = false;
int textLines = 0;
leftIndex = 0;
rightIndex = 0;
do {
uint lineIndex = _currLineIndex++;
const char *text = getText(lineIndex);
if (text[0] == '@') {
const char *command = text + 1;
if (!strcmp(command, "end"))
done = true;
if (!strcmp(command, "bold"))
_currFontId = 0x120005;
else if (!strcmp(command, "normal"))
_currFontId = 0x120004;
else if (!strcmp(command, "center"))
_split = false;
else if (!strcmp(command, "split"))
_split = true;
else
done = true;
} else {
++textLines;
if (!_split) {
leftIndex = lineIndex;
done = true;
} else if (textLines > 1) {
rightIndex = lineIndex;
done = true;
} else {
leftIndex = lineIndex;
}
}
} while (!done);
return textLines > 0;
}
void BbdouCredits::initCreditsItems() {
for (uint i = 0; i < kCreditsItemsCount; ++i) {
uint32 objectId = _vm->_controls->newTempObjectId();
_vm->_controls->placeActor(0x00050188, Common::Point(320, 480), 0x00060BE1, objectId, 0);
Control *control = _vm->_dict->getObjectControl(objectId);
control->startSequenceActor(0x60BE2, 2, 0);
_items[i].isUsed = false;
_items[i].objectId = objectId;
}
}
void BbdouCredits::freeCreditsItems() {
for (uint i = 0; i < kCreditsItemsCount; ++i) {
Control *control = _vm->_dict->getObjectControl(_items[i].objectId);
control->disappearActor();
}
}
uint32 BbdouCredits::getNextFreeObjectId() {
for (uint i = 0; i < kCreditsItemsCount; ++i) {
if (!_items[i].isUsed) {
_items[i].isUsed = true;
return _items[i].objectId;
}
}
return 0;
}
void BbdouCredits::removeText(uint32 objectId) {
for (uint i = 0; i < kCreditsItemsCount; ++i) {
if (_items[i].objectId == objectId) {
_items[i].isUsed = false;
resetObjectPos(objectId);
}
}
}
void BbdouCredits::resetObjectPos(uint32 objectId) {
Control *control = _vm->_dict->getObjectControl(objectId);
control->setActorPosition(Common::Point(320, 480));
}
void BbdouCredits::createCreditsThread(float speedModifier) {
uint32 tempThreadId = _vm->newTempThreadId();
CreditsThread *creditsThread = new CreditsThread(_vm, this, tempThreadId, speedModifier);
_vm->_threads->startThread(creditsThread);
}
void BbdouCredits::updateTexts(int yIncr) {
for (uint i = 0; i < kCreditsItemsCount; ++i) {
if (_items[i].isUsed) {
Control *control = _vm->_dict->getObjectControl(_items[i].objectId);
Common::Point pt = control->getActorPosition();
pt.y += yIncr;
control->setActorPosition(pt);
if (pt.y <= 0)
removeText(_items[i].objectId);
}
}
}
// CreditsThread
CreditsThread::CreditsThread(IllusionsEngine_BBDOU *vm, BbdouCredits *credits, uint32 threadId, float speedModifier)
: Thread(vm, threadId, 0, 0), _speedModifier(speedModifier), _lastFraction(0.0), _credits(credits) {
_type = kTTSpecialThread;
_lastUpdateTime = getCurrentTime();
}
int CreditsThread::onUpdate() {
uint32 currTime = getCurrentTime();
float fltDelta = (currTime - _lastUpdateTime) * _speedModifier + _lastFraction;
int delta = (int)fltDelta;
_lastFraction = fltDelta - delta;
if (delta != 0)
_credits->updateTexts(-delta);
_lastUpdateTime = currTime;
return 2;
}
void CreditsThread::onNotify() {
_lastUpdateTime = getCurrentTime();
}
void CreditsThread::onResume() {
onNotify();
}
void CreditsThread::onTerminated() {
_credits->stop();
}
} // End of namespace Illusions

View File

@@ -0,0 +1,83 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_BBDOU_CREDITS_H
#define ILLUSIONS_BBDOU_BBDOU_CREDITS_H
#include "illusions/specialcode.h"
#include "illusions/thread.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
class BbdouSpecialCode;
class Control;
struct CreditsItem {
bool isUsed;
uint32 objectId;
};
const uint kCreditsItemsCount = 64;
class BbdouCredits {
public:
BbdouCredits(IllusionsEngine_BBDOU *vm);
~BbdouCredits();
void start(uint32 endSignalPropertyId, float speedModifier);
void stop();
void drawNextLine();
void updateTexts(int yIncr);
protected:
IllusionsEngine_BBDOU *_vm;
uint32 _endSignalPropertyId;
uint32 _currFontId;
uint _currLineIndex;
bool _split;
CreditsItem _items[kCreditsItemsCount];
const char *getText(uint index);
void drawTextToControl(uint32 objectId, const char *text, uint alignment);
bool readNextLine(uint &leftIndex, uint &rightIndex);
void initCreditsItems();
void freeCreditsItems();
uint32 getNextFreeObjectId();
void removeText(uint32 objectId);
void resetObjectPos(uint32 objectId);
void createCreditsThread(float speedModifier);
};
class CreditsThread : public Thread {
public:
CreditsThread(IllusionsEngine_BBDOU *vm, BbdouCredits *credits, uint32 threadId, float speedModifier);
int onUpdate() override;
void onNotify() override;
void onResume() override;
void onTerminated() override;
public:
BbdouCredits *_credits;
float _speedModifier;
float _lastFraction;
uint32 _lastUpdateTime;
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_BBDOU_CREDITS_H

View File

@@ -0,0 +1,298 @@
/* 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 "illusions/bbdou/bbdou_credits.h"
namespace Illusions {
const char *kCreditsText[] = {
"@center",
"@normal",
"Directed by",
"@bold",
"Darren Bartlett",
"@normal",
"",
"Produced by",
"@bold",
"James C\xF6liz, Jr.",
"@normal",
"",
"Developed by",
"@bold",
"The Illusions Gaming Company",
"@normal",
"",
"@split",
"Creative Director",
"Darren Bartlett",
"Designer",
"Ryan Modjeski",
"Associate Designer",
"David Sirlin",
"",
"",
"Technical Director",
"James C\xF6liz, Jr.",
"Lead Programmer",
"Bill Fowler",
"Programmer",
"Chuck Woo",
"",
"",
"3D Artist",
"Eric Chyn",
"",
"Bill Eral",
"Production Artist",
"Jim Eral",
"Asst. Production Artist",
"Eli Remus",
"@center",
"",
"2D Animation by",
"@bold",
"LA West Productions",
"@normal",
"",
"@split",
"Director of Animation",
"Ivan Tomicic",
"Production Manager",
"Susan McGirr",
"Studio Supervisor",
"Danijel Tomicic",
"",
"",
"Lead Animator",
"Dario Pustaj",
"",
"Ivica Horvat",
"Animator",
"Kristijan Dulic",
"",
"Elvis Popovic",
"In-Between",
"Maja Surijak",
"",
"Zlatko Zlatunic",
"",
"",
"Lead Ink & Paint",
"Sasa Zec",
"Ink & Paint",
"Darko Dukaric",
"",
"Marcela Kumparic",
"",
"Vlado Lencur",
"",
"Jura Milinkovic",
"",
"Bernard Ojdanic",
"",
"Peggy Skrlec",
"@center",
"",
"3D Backgrounds by",
"@bold",
"LA West Productions",
"@normal",
"",
"@split",
"3D Artist",
"Daniela Tomicic",
"",
"Diana-Barbara Stepanic",
"@center",
"",
"2D Animation by",
"@bold",
"Six Foot Two Productions",
"@normal",
"",
"@split",
"Director of Animation",
"Tom Arndt",
"Producer",
"Suzanne D. Atherly",
"",
"",
"Character Animator",
"Robbin Atherly",
"",
"Alan Lau",
"",
"David Ball",
"",
"Jeff Nevins",
"",
"",
"Ink & Paint",
"Steve Bellin",
"",
"Corrine Wong",
"",
"Jeff Nevins",
"@center",
"",
"Written by",
"@bold",
"Bo Weinberg",
"@normal",
"",
"Principal Voice by",
"@bold",
"Mike Judge",
"@normal",
"",
"Secondary Voice Recorded at",
"@bold",
"Private Island Trax",
"@normal",
"",
"Secondary Voices by",
"Dean Julian",
"Mia Altieri",
"Nicole Schallig",
"Rick Calvert",
"John Campana",
"Alex Mebane",
"Denise Askew",
"Michael Jamal",
"",
"Studio Engineered by",
"Mark V",
"",
"Sound and Music by",
"@bold",
"Tommy Tallarico Studios",
"@normal",
"",
"@split",
"Sound Designer",
"Joey Kuras",
"Foley",
"Scott Barrett",
"@center",
"",
"Illusions is represented by",
"@bold",
"Interactive Studio Management",
"@normal",
"",
"Published by",
"@bold",
"GT Interactive Software",
"@normal",
"",
"@split",
"Producer",
"Nathan Rose",
"Assistant Producer",
"Jamal Jennings",
"Group Product Manager",
"Evan Stein",
"Product Manager",
"Robert J. Ricci",
"Senior Communications Manager",
"Alan Lewis",
"Director, Product Development Services",
"Mary Steer",
"Director, Creative Services",
"Leslie Mills",
"Creative Director",
"Vic Merritt",
"Art/Traffic Manager",
"Liz Fierro",
"Manual Editor",
"Peter Witcher",
"",
"",
"@center",
"",
"Licensed by",
"@bold",
"MTV Networks",
"@normal",
"",
"@split",
"MTV Executive Producer",
"Allie Eberhardt",
"MTV Producer",
"Tony Calandra",
"MTV Creative Consultants",
"Kristofor Brown",
"",
"David Felton",
"",
"Mike Judge",
"",
"Nick Litwinko",
"MTV Standards and Practices",
"Dr. Thomas Shea",
"MTV Legal Affairs",
"Beth Matthews",
"@center",
"",
"MTV would like to thank",
"Mary Frances Budig",
"George Eichen",
"Matt Farber",
"Rick Holzman",
"Jessica Jarrett",
"Mike Judge",
"Judith McGrath",
"David Milch",
"Abby Terkuhle",
"Van Toffler",
"Paige Wolfson",
"Marcia Zellers",
"",
"@bold",
"Special Thanks",
"@normal",
"Clyde Grossman",
"Hiromi Nobata",
"John Durentas",
"Jeff Teachworth",
"John Lawrence",
"Bill Hendrickson",
"Fred Schiller",
"Sam Fletcher",
"Elizabeth, Stephanie & Hannah",
"Sheila Mendoza",
"Yukari Yamano",
"Hang Yim, King Yip & Wayne",
"Li-Ming, Der-Lin & Fansy",
"Bobbi Eral",
"Miss Melissa",
"Yasmin, Aparna & Jenny",
"Tony the Cat",
"Sammy the Cat",
"@end"
};
const char *BbdouCredits::getText(uint index) {
return kCreditsText[index - 1];
}
} // End of namespace Illusions

View File

@@ -0,0 +1,363 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/bbdou_cursor.h"
#include "illusions/bbdou/bbdou_specialcode.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
#include "illusions/dictionary.h"
#include "illusions/input.h"
namespace Illusions {
// NOTE It's assumed there's only one game cursor object
// The original stores the _data inside the actor, here it's inside the Cursor class.
// BbdouCursor
BbdouCursor::BbdouCursor(IllusionsEngine_BBDOU *vm, BbdouSpecialCode *bbdou)
: _vm(vm), _bbdou(bbdou) {
}
BbdouCursor::~BbdouCursor() {
}
void BbdouCursor::init(uint32 objectId, uint32 progResKeywordId) {
Common::Point pos = _vm->_camera->getCurrentPan();
_vm->_controls->placeActor(0x50001, pos, 0x6000C, objectId, 0);
Control *control = _vm->_dict->getObjectControl(objectId);
control->_flags |= 8;
_data._mode = 1;
_data._mode2 = 0;
_data._verbId1 = 0x1B0000;
_data._progResKeywordId = progResKeywordId;
_data._currOverlappedObjectId = 0;
_data._overlappedObjectId = 0;
_data._sequenceId = 0x6000F;
_data._holdingObjectId = 0;
_data._holdingObjectId2 = 0;
_data._visibleCtr = 0;
_data._causeThreadId1 = 0;
_data._causeThreadId2 = 0;
_data._field90 = 0;
_data._flags = 0;
_data._verbState._minPriority = 1;
_data._currCursorTrackingSequenceId = 0;
_data._idleCtr = 0;
_data._verbState._verbId = 0x1B0000;
_data._verbState._cursorState = 1;
_data._verbState._isBubbleVisible = 0;
_data._verbState._objectIds[0] = 0;
_data._verbState._objectIds[1] = 0;
_data._verbState._index = 0;
_data._verbState._flag56 = false;
resetActiveVerbs();
control->setActorIndexTo1();
}
void BbdouCursor::enable(uint32 objectId) {
++_data._visibleCtr;
if (_data._visibleCtr == 1) {
Control *control = _vm->_dict->getObjectControl(objectId);
show(control);
_vm->_camera->pushCameraMode();
_vm->_camera->panEdgeFollow(objectId, 360);
_data._idleCtr = 0;
}
_vm->_input->discardAllEvents();
}
void BbdouCursor::disable(uint32 objectId) {
hide(objectId);
}
void BbdouCursor::reset(uint32 objectId) {
Control *control = _vm->_dict->getObjectControl(objectId);
_data._verbState._cursorState = 1;
_data._mode = 1;
_data._mode2 = 0;
_data._verbId1 = 0x1B0000;
_data._currOverlappedObjectId = 0;
_data._overlappedObjectId = 0;
_data._sequenceId = 0x6000F;
_data._holdingObjectId = 0;
_data._holdingObjectId2 = 0;
_data._visibleCtr = 0;
_data._causeThreadId1 = 0;
_data._flags = 0;
_data._verbState._minPriority = 1;
_data._currCursorTrackingSequenceId = 0;
_data._idleCtr = 0;
_data._verbState._verbId = 0x1B0000;
_data._verbState._isBubbleVisible = 0;
_data._verbState._objectIds[0] = 0;
_data._verbState._objectIds[1] = 0;
_data._verbState._index = 0;
_data._verbState._flag56 = false;
resetActiveVerbs();
control->setActorIndexTo1();
control->startSequenceActor(0x60029, 2, 0);
_bbdou->hideVerbBubble(control->_objectId, &_data._verbState);
}
void BbdouCursor::addCursorSequenceId(uint32 objectId, uint32 sequenceId) {
for (uint i = 0; i < kMaxCursorSequences; ++i) {
if (_cursorSequences[i]._objectId == 0) {
_cursorSequences[i]._objectId = objectId;
_cursorSequences[i]._sequenceId = sequenceId;
break;
}
}
}
uint32 BbdouCursor::findCursorSequenceId(uint32 objectId) {
for (uint i = 0; i < kMaxCursorSequences; ++i) {
if (_cursorSequences[i]._objectId == objectId)
return _cursorSequences[i]._sequenceId;
}
return 0;
}
bool BbdouCursor::updateTrackingCursor(Control *control) {
uint32 sequenceId;
if (getTrackingCursorSequenceId(control, sequenceId)) {
if (_data._currCursorTrackingSequenceId != sequenceId) {
saveBeforeTrackingCursor(control, sequenceId);
show(control);
_data._currCursorTrackingSequenceId = sequenceId;
}
return true;
} else {
if (_data._currCursorTrackingSequenceId) {
_data._currCursorTrackingSequenceId = 0;
restoreAfterTrackingCursor();
show(control);
}
return false;
}
}
void BbdouCursor::saveInfo() {
_data._mode2 = _data._mode;
_data._sequenceId2 = _data._sequenceId;
_data._holdingObjectId2 = _data._holdingObjectId;
}
void BbdouCursor::restoreInfo() {
_data._mode = _data._mode2;
_data._holdingObjectId = _data._holdingObjectId2;
_data._sequenceId = _data._sequenceId2;
_data._mode2 = 0;
_data._holdingObjectId2 = 0;
_data._sequenceId2 = 0;
}
void BbdouCursor::saveBeforeTrackingCursor(Control *control, uint32 sequenceId) {
if (_data._currOverlappedObjectId || _data._mode == 3) {
if (_data._mode == 3)
restoreInfo();
control->setActorIndexTo1();
if (_data._verbState._isBubbleVisible)
_bbdou->playSoundEffect(4);
_bbdou->hideVerbBubble(control->_objectId, &_data._verbState);
}
_data._currOverlappedObjectId = 0;
if (_data._mode != 4) {
saveInfo();
_data._mode = 4;
_data._holdingObjectId = 0;
}
_data._sequenceId = sequenceId;
}
void BbdouCursor::restoreAfterTrackingCursor() {
_data._holdingObjectId = _data._holdingObjectId2;
if (_data._holdingObjectId2) {
_data._mode = 2;
_data._sequenceId = findCursorSequenceId(_data._holdingObjectId2);
} else {
_data._mode = 1;
_data._sequenceId = 0x6000F;
}
_data._mode2 = 0;
_data._sequenceId2 = 0;
_data._holdingObjectId2 = 0;
_data._currCursorTrackingSequenceId = 0;
}
uint32 BbdouCursor::getSequenceId1(int sequenceIndex) {
switch (sequenceIndex) {
case 2:
return 0x60010;
case 3:
return 0x60011;
case 4:
return 0x60012;
case 5:
return 0x60013;
case 6:
return 0x60015;
case 7:
return 0x60014;
default:
return 0;
}
}
uint BbdouCursor::calcTrackingFlags(Common::Point actorPos, Common::Point trackingLimits) {
uint trackingFlags = 0;
int16 x = actorPos.x - 320;
int16 y = actorPos.y - 240;
if (x < -trackingLimits.x)
trackingFlags = 1;
else if (x > trackingLimits.x)
trackingFlags = 3;
else
trackingFlags = 2;
if (y < -trackingLimits.y)
trackingFlags += 0;
else if (y > trackingLimits.y)
trackingFlags += 6;
else
trackingFlags += 3;
return trackingFlags;
}
uint BbdouCursor::calcTrackingCursorIndex(uint trackingFlags) {
uint cursorIndex = 0;
switch (trackingFlags) {
case 1:
if (_vm->_camera->isAtPanLimit(1)) {
if (!_vm->_camera->isAtPanLimit(3))
cursorIndex = 4;
} else {
if (!_vm->_camera->isAtPanLimit(3))
cursorIndex = 1;
else
cursorIndex = 2;
}
break;
case 2:
if (!_vm->_camera->isAtPanLimit(1))
cursorIndex = 2;
break;
case 3:
if (_vm->_camera->isAtPanLimit(1)) {
if (!_vm->_camera->isAtPanLimit(4))
cursorIndex = 6;
} else {
if (!_vm->_camera->isAtPanLimit(4))
cursorIndex = 3;
else
cursorIndex = 2;
}
break;
case 4:
if (!_vm->_camera->isAtPanLimit(3))
cursorIndex = 4;
break;
case 6:
if (!_vm->_camera->isAtPanLimit(4))
cursorIndex = 6;
break;
case 7:
if (_vm->_camera->isAtPanLimit(2)) {
if (!_vm->_camera->isAtPanLimit(3))
cursorIndex = 4;
} else {
if (!_vm->_camera->isAtPanLimit(3))
cursorIndex = 8;
else
cursorIndex = 7;
}
break;
case 8:
if (!_vm->_camera->isAtPanLimit(2))
cursorIndex = 8;
break;
case 9:
if (_vm->_camera->isAtPanLimit(2)) {
if (!_vm->_camera->isAtPanLimit(4))
cursorIndex = 6;
} else {
if (!_vm->_camera->isAtPanLimit(4))
cursorIndex = 9;
else
cursorIndex = 8;
}
break;
default:
break;
}
return cursorIndex;
}
bool BbdouCursor::getTrackingCursorSequenceId(Control *control, uint32 &outSequenceId) {
static const uint32 kTrackingCursorSequenceIds[] = {
0, 0x000609BF, 0x00060018, 0x000609C0, 0x00060016,
0, 0x00060017, 0x000609C1, 0x00060019, 0x000609C2
};
Common::Point trackingLimits = _vm->_camera->getTrackingLimits();
uint trackingFlags = calcTrackingFlags(control->_actor->_position, trackingLimits);
uint cursorIndex = calcTrackingCursorIndex(trackingFlags);
outSequenceId = kTrackingCursorSequenceIds[cursorIndex];
return outSequenceId != 0;
}
void BbdouCursor::resetActiveVerbs() {
for (uint i = 0; i < 32; ++i) {
_data._verbState._verbActive[i] = false;
}
if (_data._verbState._cursorState == 1) {
_data._verbState._verbActive[1] = true;
_data._verbState._verbActive[2] = true;
_data._verbState._verbActive[3] = true;
_data._verbState._verbActive[5] = true;
} else if (_data._verbState._cursorState == 3) {
_data._verbState._verbActive[1] = true;
_data._verbState._verbActive[2] = true;
}
}
void BbdouCursor::show(Control *control) {
control->startSequenceActor(_data._sequenceId, 2, 0);
control->appearActor();
}
void BbdouCursor::hide(uint32 objectId) {
--_data._visibleCtr;
if (_data._visibleCtr == 0) {
Control *control = _vm->_dict->getObjectControl(objectId);
control->startSequenceActor(0x60029, 2, 0);
_bbdou->hideVerbBubble(objectId, &_data._verbState);
_vm->_camera->popCameraMode();
}
_vm->_input->discardAllEvents();
}
} // End of namespace Illusions

View File

@@ -0,0 +1,105 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_BBDOU_CURSOR_H
#define ILLUSIONS_BBDOU_BBDOU_CURSOR_H
#include "illusions/specialcode.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
class BbdouSpecialCode;
class Control;
struct VerbState {
int _cursorState;
bool _verbActive[32];
uint32 _verbId;
bool _isBubbleVisible;
uint32 _objectIds[2];
int16 _index;
bool _flag56;
int _minPriority;
};
struct CursorData {
int _mode;
int _mode2;
uint32 _verbId1;
uint32 _progResKeywordId;
VerbState _verbState;
uint32 _currOverlappedObjectId;
uint32 _overlappedObjectId;
uint32 _sequenceId;
uint32 _sequenceId2;
uint32 _holdingObjectId;
uint32 _holdingObjectId2;
int _visibleCtr;
uint32 _causeThreadId1;
uint32 _causeThreadId2;
int16 _field90;
uint _flags;
uint32 _currCursorTrackingSequenceId;
int16 _idleCtr;
};
struct CursorSequence {
uint32 _objectId;
uint32 _sequenceId;
CursorSequence() : _objectId(0), _sequenceId(0) {}
};
const uint kMaxCursorSequences = 100;
class BbdouCursor {
public:
BbdouCursor(IllusionsEngine_BBDOU *vm, BbdouSpecialCode *bbdou);
~BbdouCursor();
void init(uint32 objectId, uint32 progResKeywordId);
void enable(uint32 objectId);
void disable(uint32 objectId);
void reset(uint32 objectId);
void addCursorSequenceId(uint32 objectId, uint32 sequenceId);
uint32 findCursorSequenceId(uint32 objectId);
bool updateTrackingCursor(Control *control);
void saveInfo();
void restoreInfo();
void saveBeforeTrackingCursor(Control *control, uint32 sequenceId);
void restoreAfterTrackingCursor();
uint32 getSequenceId1(int sequenceIndex);
uint calcTrackingFlags(Common::Point actorPos, Common::Point trackingLimits);
uint calcTrackingCursorIndex(uint trackingFlags);
bool getTrackingCursorSequenceId(Control *control, uint32 &outSequenceId);
public:
IllusionsEngine_BBDOU *_vm;
BbdouSpecialCode *_bbdou;
Control *_control;
CursorData _data;
CursorSequence _cursorSequences[kMaxCursorSequences];
void resetActiveVerbs();
void show(Control *control);
void hide(uint32 objectId);
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_BBDOU_CURSOR_H

View File

@@ -0,0 +1,148 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/bbdou_foodctl.h"
#include "illusions/actor.h"
#include "illusions/dictionary.h"
#include "illusions/textdrawer.h"
#include "illusions/time.h"
#include "illusions/resources/scriptresource.h"
namespace Illusions {
BbdouFoodCtl::BbdouFoodCtl(IllusionsEngine_BBDOU *vm)
: _vm(vm) {
}
BbdouFoodCtl::~BbdouFoodCtl() {
}
void BbdouFoodCtl::placeFood(uint totalRoundsCount, uint maxRequestedFoodCount) {
_totalRoundsCount = totalRoundsCount;
_maxRequestedFoodCount = maxRequestedFoodCount;
_requestedFoodCount = 0;
_requestedFoodIndex = 0;
placeActors();
}
void BbdouFoodCtl::addFood(uint32 propertyId) {
_foodPropertyIds[_requestedFoodCount++] = propertyId;
}
void BbdouFoodCtl::requestFirstFood() {
_requestedFoodIndex = 1;
_vm->_scriptResource->_properties.set(_foodPropertyIds[0], true);
}
void BbdouFoodCtl::requestNextFood() {
uint32 propertyId = _foodPropertyIds[_requestedFoodIndex++];
_vm->_scriptResource->_properties.set(propertyId, true);
}
void BbdouFoodCtl::nextRound() {
--_totalRoundsCount;
}
bool BbdouFoodCtl::hasReachedRequestedFoodCount() {
return _requestedFoodIndex > _requestedFoodCount;
}
bool BbdouFoodCtl::hasRoundFinished() {
return _totalRoundsCount == 0 || _requestedFoodCount > _maxRequestedFoodCount;
}
void BbdouFoodCtl::serveFood() {
uint32 foodSequenceId = getFoodSequenceId();
uint32 studentObjectId = getCurrentStudentObjectId();
uint32 foodObjectId = _foodItems[_servedFoodCount++].objectId;
Control *foodControl = _vm->_dict->getObjectControl(foodObjectId);
foodControl->startSequenceActor(foodSequenceId, 2, 0);
foodControl->linkToObject(studentObjectId, _servedFoodCount);
}
void BbdouFoodCtl::resetFood() {
for (uint i = 0; i < _servedFoodCount; ++i) {
Control *control = _vm->_dict->getObjectControl(_foodItems[i].objectId);
control->unlinkObject();
_foodItems[i].value = 0;
}
_servedFoodCount = 0;
resetFoodControls();
}
void BbdouFoodCtl::placeActors() {
static const uint32 kFoodSequenceIds[] = {
0x00060932, 0x00060933, 0x00060934,
0x00060935, 0x00060936, 0x00060937
};
for (uint i = 0; i < kFoodCount; ++i) {
uint32 objectId = _vm->_controls->newTempObjectId();
_vm->_controls->placeActor(0x00050119, Common::Point(0, 0), 0x00060931, objectId, 0);
Control *control = _vm->_dict->getObjectControl(objectId);
control->deactivateObject();
control->setPriority(i + 10);
control->startSequenceActor(kFoodSequenceIds[(i + 1) % 6], 2, 0);
_foodItems[i].objectId = objectId;
_foodItems[i].value = 0;
}
_servedFoodCount = 0;
resetFoodControls();
}
void BbdouFoodCtl::resetFoodControls() {
Common::Point pos(-100, 32);
for (uint i = 0; i < kFoodCount; ++i) {
Control *control = _vm->_dict->getObjectControl(_foodItems[i].objectId);
control->setActorPosition(pos);
pos.y += 20;
}
}
uint32 BbdouFoodCtl::getFoodSequenceId() {
if (_vm->_scriptResource->_properties.get(0x000E014A))
return 0x60932;
if (_vm->_scriptResource->_properties.get(0x000E014B))
return 0x60933;
if (_vm->_scriptResource->_properties.get(0x000E014C))
return 0x60934;
if (_vm->_scriptResource->_properties.get(0x000E014D))
return 0x60935;
if (_vm->_scriptResource->_properties.get(0x000E014E))
return 0x60936;
if (_vm->_scriptResource->_properties.get(0x000E014F))
return 0x60937;
return 0;
}
uint32 BbdouFoodCtl::getCurrentStudentObjectId() {
if (_vm->_scriptResource->_properties.get(0x000E0146))
return 0x40077;
if (_vm->_scriptResource->_properties.get(0x000E0147))
return 0x40255;
if (_vm->_scriptResource->_properties.get(0x000E0148))
return 0x40256;
if (_vm->_scriptResource->_properties.get(0x000E0149))
return 0x40257;
return 0;
}
} // End of namespace Illusions

View File

@@ -0,0 +1,69 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_BBDOU_FOODCTL_H
#define ILLUSIONS_BBDOU_BBDOU_FOODCTL_H
#include "illusions/specialcode.h"
#include "illusions/thread.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
const uint kFoodMaxPropertyIdsCount = 15;
const uint kFoodCount = 16;
struct FoodItem {
uint32 objectId;
int value;
};
class BbdouFoodCtl {
public:
BbdouFoodCtl(IllusionsEngine_BBDOU *vm);
~BbdouFoodCtl();
void placeFood(uint totalRoundsCount, uint maxRequestedFoodCount);
void addFood(uint32 propertyId);
void requestFirstFood();
void requestNextFood();
void nextRound();
bool hasReachedRequestedFoodCount();
bool hasRoundFinished();
void serveFood();
void resetFood();
protected:
IllusionsEngine_BBDOU *_vm;
uint _totalRoundsCount, _maxRequestedFoodCount;
uint32 _foodPropertyIds[kFoodMaxPropertyIdsCount];
uint _requestedFoodCount;
uint _requestedFoodIndex;
FoodItem _foodItems[kFoodCount];
uint _servedFoodCount;
void placeActors();
void resetFoodControls();
uint32 getFoodSequenceId();
uint32 getCurrentStudentObjectId();
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_BBDOU_FOODCTL_H

View File

@@ -0,0 +1,396 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/bbdou_inventory.h"
#include "illusions/bbdou/bbdou_cursor.h"
#include "illusions/bbdou/bbdou_specialcode.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
#include "illusions/dictionary.h"
#include "illusions/input.h"
namespace Illusions {
typedef Common::Functor2Mem<TriggerFunction*, uint32, void, BbdouInventory> InventoryTriggerFunctionCallback;
// InventoryItem
InventoryItem::InventoryItem(uint32 objectId, uint32 sequenceId)
: _objectId(objectId), _sequenceId(sequenceId),
_assigned(false), _flag(false), _timesPresent(0), _fieldE(0) {
}
// InventorySlot
InventorySlot::InventorySlot(uint32 namedPointId)
: _namedPointId(namedPointId), _objectId(0), _inventoryItem(nullptr) {
}
// InventoryBag
InventoryBag::InventoryBag(IllusionsEngine_BBDOU *vm, uint32 sceneId)
: _vm(vm), _sceneId(sceneId), _isActive(false), _fieldA(0) {
}
InventoryBag::~InventoryBag() {
for (uint i = 0; i < _inventorySlots.size(); ++i) {
delete _inventorySlots[i];
}
}
void InventoryBag::registerInventorySlot(uint32 namedPointId) {
_inventorySlots.push_back(new InventorySlot(namedPointId));
}
bool InventoryBag::addInventoryItem(InventoryItem *inventoryItem, InventorySlot *inventorySlot) {
// NOTE Skipped support for multiple items per slot, not used in BBDOU
if (!inventorySlot) {
for (auto &slot : _inventorySlots) {
if (!slot->_inventoryItem) {
inventorySlot = slot;
break;
}
}
}
if (inventorySlot) {
inventorySlot->_inventoryItem = inventoryItem;
return true;
}
return false;
}
void InventoryBag::removeInventoryItem(InventoryItem *inventoryItem) {
for (auto &slot : _inventorySlots) {
if (slot->_inventoryItem && slot->_inventoryItem->_objectId == inventoryItem->_objectId)
slot->_inventoryItem = nullptr;
}
}
bool InventoryBag::hasInventoryItem(uint32 objectId) {
for (InventorySlotsIterator it = _inventorySlots.begin();
it != _inventorySlots.end(); ++it) {
InventorySlot *inventorySlot = *it;
InventoryItem *inventoryItem = inventorySlot->_inventoryItem;
if (inventoryItem && inventoryItem->_objectId == objectId)
return true;
}
return false;
}
void InventoryBag::buildItems() {
for (InventorySlotsIterator it = _inventorySlots.begin();
it != _inventorySlots.end(); ++it) {
InventorySlot *inventorySlot = *it;
InventoryItem *inventoryItem = inventorySlot->_inventoryItem;
if (inventoryItem) {
++inventoryItem->_timesPresent;
if (!inventoryItem->_assigned || inventoryItem->_flag || inventoryItem->_timesPresent > 1)
inventorySlot->_inventoryItem = nullptr;
}
}
}
void InventoryBag::clear() {
for (InventorySlotsIterator it = _inventorySlots.begin();
it != _inventorySlots.end(); ++it) {
InventorySlot *inventorySlot = *it;
inventorySlot->_inventoryItem = nullptr;
}
}
InventorySlot *InventoryBag::getInventorySlot(uint32 objectId) {
for (uint i = 0; i < _inventorySlots.size(); ++i) {
if (_inventorySlots[i]->_objectId == objectId)
return _inventorySlots[i];
}
return nullptr;
}
InventorySlot *InventoryBag::findClosestSlot(Common::Point putPos, int index) {
uint minDistance = 0xFFFFFFFF;
InventorySlot *minDistanceSlot = nullptr;
for (auto &inventorySlot : _inventorySlots) {
Common::Point slotPos = _vm->getNamedPointPosition(inventorySlot->_namedPointId);
uint currDistance = (slotPos.y - putPos.y) * (slotPos.y - putPos.y) + (slotPos.x - putPos.x) * (slotPos.x - putPos.x);
if (currDistance < minDistance) {
minDistance = currDistance;
minDistanceSlot = inventorySlot;
}
}
return minDistanceSlot;
}
// BbdouInventory
BbdouInventory::BbdouInventory(IllusionsEngine_BBDOU *vm, BbdouSpecialCode *bbdou)
: _vm(vm), _bbdou(bbdou), _activeInventorySceneId(0) {
}
BbdouInventory::~BbdouInventory() {
for (uint i = 0; i < _inventoryBags.size(); ++i) {
delete _inventoryBags[i];
}
for (uint i = 0; i < _inventoryItems.size(); ++i) {
delete _inventoryItems[i];
}
}
void BbdouInventory::registerInventoryBag(uint32 sceneId) {
_inventoryBags.push_back(new InventoryBag(_vm, sceneId));
_activeBagSceneId = sceneId;
}
void BbdouInventory::registerInventoryItem(uint32 objectId, uint32 sequenceId) {
_activeBagSceneId = 0;
_inventoryItems.push_back(new InventoryItem(objectId, sequenceId));
}
void BbdouInventory::registerInventorySlot(uint32 namedPointId) {
InventoryBag *inventoryBag = getInventoryBag(_activeBagSceneId);
inventoryBag->registerInventorySlot(namedPointId);
}
void BbdouInventory::addInventoryItem(uint32 objectId) {
_activeBagSceneId = 0;
InventoryItem *inventoryItem = getInventoryItem(objectId);
bool assigned = inventoryItem->_assigned;
inventoryItem->_assigned = true;
if (!assigned && !inventoryItem->_flag) {
for (uint i = 0; i < _inventoryBags.size(); ++i) {
if (!_inventoryBags[i]->addInventoryItem(inventoryItem, nullptr))
inventoryItem->_assigned = false;
}
}
if (_activeInventorySceneId)
refresh();
}
void BbdouInventory::removeInventoryItem(uint32 objectId) {
InventoryItem *inventoryItem = getInventoryItem(objectId);
bool flag = inventoryItem->_flag;
inventoryItem->_flag = true;
if (!flag && inventoryItem->_assigned) {
if (_activeInventorySceneId) {
InventoryBag *inventoryBag = getInventoryBag(_activeInventorySceneId);
inventoryBag->removeInventoryItem(inventoryItem);
}
refresh();
}
}
bool BbdouInventory::hasInventoryItem(uint32 objectId) {
for (uint i = 0; i < _inventoryItems.size(); ++i) {
if (_inventoryItems[i]->_objectId == objectId &&
_inventoryItems[i]->_assigned)
return true;
}
return false;
}
void BbdouInventory::open() {
_activeBagSceneId = 0;
InventoryBag *inventoryBag = getInventoryBag(_vm->getCurrentScene());
buildItems(inventoryBag);
if (_activeInventorySceneId) {
refresh();
refresh();
} else {
_activeInventorySceneId = _vm->getCurrentScene();
_index = 1;
inventoryBag->_isActive = true;
for (InventoryBag::InventorySlotsIterator it = inventoryBag->_inventorySlots.begin();
it != inventoryBag->_inventorySlots.end(); ++it) {
InventorySlot *inventorySlot = *it;
Common::Point slotPos = _vm->getNamedPointPosition(inventorySlot->_namedPointId);
Control *control = _vm->_dict->getObjectControl(inventorySlot->_objectId);
if (control) {
control->setActorPosition(slotPos);
control->startSequenceActor(0x0006005A, 2, 0);
} else {
inventorySlot->_objectId = _vm->_controls->newTempObjectId();
_vm->_controls->placeActor(0x00050012, slotPos, 0x0006005A, inventorySlot->_objectId, 0);
}
_vm->causeDeclare(0x1B0002, 0, inventorySlot->_objectId, new InventoryTriggerFunctionCallback(this, &BbdouInventory::cause0x1B0002));
_vm->causeDeclare(0x1B0001, 0, inventorySlot->_objectId, new InventoryTriggerFunctionCallback(this, &BbdouInventory::cause0x1B0001));
_vm->causeDeclare(0x1B0008, 0, inventorySlot->_objectId, new InventoryTriggerFunctionCallback(this, &BbdouInventory::cause0x1B0001));
}
refresh();
}
}
void BbdouInventory::close() {
if (!_activeInventorySceneId)
return;
InventoryBag *inventoryBag = getInventoryBag(_vm->getCurrentScene());
for (InventoryBag::InventorySlotsIterator it = inventoryBag->_inventorySlots.begin();
it != inventoryBag->_inventorySlots.end(); ++it) {
InventorySlot *inventorySlot = *it;
Control *control = _vm->_dict->getObjectControl(inventorySlot->_objectId);
control->startSequenceActor(0x00060187, 2, 0);
}
inventoryBag->_isActive = false;
_activeInventorySceneId = 0;
}
InventoryBag *BbdouInventory::getInventoryBag(uint32 sceneId) {
for (uint i = 0; i < _inventoryBags.size(); ++i) {
if (_inventoryBags[i]->_sceneId == sceneId)
return _inventoryBags[i];
}
return nullptr;
}
InventoryItem *BbdouInventory::getInventoryItem(uint32 objectId) {
for (uint i = 0; i < _inventoryItems.size(); ++i) {
if (_inventoryItems[i]->_objectId == objectId)
return _inventoryItems[i];
}
return nullptr;
}
void BbdouInventory::refresh() {
if (!_activeInventorySceneId)
return;
InventoryBag *inventoryBag = getInventoryBag(_activeInventorySceneId);
for (InventoryBag::InventorySlotsIterator it = inventoryBag->_inventorySlots.begin();
it != inventoryBag->_inventorySlots.end(); ++it) {
InventorySlot *inventorySlot = *it;
Control *control = _vm->_dict->getObjectControl(inventorySlot->_objectId);
InventoryItem *inventoryItem = inventorySlot->_inventoryItem;
if (inventoryItem) {
control->startSequenceActor(inventoryItem->_sequenceId, 2, 0);
control->appearActor();
} else {
control->startSequenceActor(0x00060187, 2, 0);
}
}
}
void BbdouInventory::buildItems(InventoryBag *inventoryBag) {
for (auto &inventoryItem : _inventoryItems) {
inventoryItem->_timesPresent = 0;
}
inventoryBag->buildItems();
for (auto &inventoryItem : _inventoryItems) {
if (inventoryItem->_assigned && !inventoryItem->_flag &&
inventoryItem->_timesPresent == 0 &&
inventoryItem->_objectId != _bbdou->_cursor->_data._holdingObjectId)
inventoryBag->addInventoryItem(inventoryItem, nullptr);
}
}
void BbdouInventory::clear() {
for (auto &inventoryItem : _inventoryItems) {
inventoryItem->_assigned = false;
inventoryItem->_flag = false;
}
for (uint i = 0; i < _inventoryBags.size(); ++i) {
_inventoryBags[i]->clear();
}
}
void BbdouInventory::cause0x1B0001(TriggerFunction *triggerFunction, uint32 callingThreadId) {
uint32 foundSceneId, foundVerbId, foundObjectId2, foundObjectId;
bool found = false;
InventoryBag *inventoryBag = getInventoryBag(_activeInventorySceneId);
InventorySlot *inventorySlot = inventoryBag->getInventorySlot(triggerFunction->_objectId);
uint32 objectId = inventorySlot->_inventoryItem->_objectId;
foundSceneId = _activeInventorySceneId;
foundVerbId = triggerFunction->_verbId;
foundObjectId = 0;
foundObjectId2 = 0;
if (triggerFunction->_verbId == 0x1B0008) {
foundVerbId = 0x1B0003;
foundObjectId2 = _bbdou->_cursor->_data._holdingObjectId;
}
if (_vm->causeIsDeclared(_activeInventorySceneId, foundVerbId, foundObjectId2, objectId)) {
foundSceneId = _activeInventorySceneId;
foundObjectId = objectId;
found = true;
} else if (foundVerbId == 0x1B0003 && _vm->causeIsDeclared(_activeInventorySceneId, 0x1B0008, 0, objectId)) {
foundSceneId = _activeInventorySceneId;
foundVerbId = 0x1B0008;
foundObjectId2 = 0;
foundObjectId = objectId;
found = true;
} else if (_vm->causeIsDeclared(_activeInventorySceneId, foundVerbId, foundObjectId2, 0x40001)) {
foundSceneId = _activeInventorySceneId;
foundObjectId = 0x40001;
found = true;
} else if (_vm->causeIsDeclared(0x10003, foundVerbId, foundObjectId2, objectId)) {
foundSceneId = 0x10003;
foundObjectId = objectId;
found = true;
} else if (foundVerbId == 0x1B0003 && _vm->causeIsDeclared(0x10003, 0x1B0008, 0, objectId)) {
foundSceneId = 0x10003;
foundVerbId = 0x1B0008;
foundObjectId2 = 0;
foundObjectId = objectId;
found = true;
} else if (_vm->causeIsDeclared(0x10003, foundVerbId, foundObjectId2, 0x40001)) {
foundSceneId = 0x10003;
foundObjectId = 0x40001;
found = true;
}
if (found)
_vm->causeTrigger(foundSceneId, foundVerbId, foundObjectId2, foundObjectId, callingThreadId);
else
_vm->notifyThreadId(callingThreadId);
}
void BbdouInventory::cause0x1B0002(TriggerFunction *triggerFunction, uint32 callingThreadId) {
InventoryBag *inventoryBag = getInventoryBag(_activeInventorySceneId);
InventorySlot *inventorySlot = inventoryBag->getInventorySlot(triggerFunction->_objectId);
uint32 objectId = inventorySlot->_inventoryItem->_objectId;
if (_vm->causeIsDeclared(_activeInventorySceneId, triggerFunction->_verbId, 0, objectId)) {
_vm->causeTrigger(_activeInventorySceneId, triggerFunction->_verbId, 0, objectId, callingThreadId);
} else {
_bbdou->startHoldingObjectId(0x4001A, objectId, 0);
_vm->notifyThreadId(callingThreadId);
}
}
void BbdouInventory::putBackInventoryItem(uint32 objectId, Common::Point cursorPosition) {
InventoryItem *inventoryItem = getInventoryItem(objectId);
bool flag = inventoryItem->_flag;
inventoryItem->_flag = false;
if (!flag && !inventoryItem->_assigned)
return;
for (uint i = 0; i < _inventoryBags.size(); ++i) {
InventoryBag *inventoryBag = _inventoryBags[i];
if (inventoryBag->_sceneId == _activeInventorySceneId) {
InventorySlot *inventorySlot = inventoryBag->findClosestSlot(cursorPosition, _index);
inventoryBag->addInventoryItem(inventoryItem, inventorySlot);
} else {
if (!inventoryBag->hasInventoryItem(objectId))
inventoryBag->addInventoryItem(inventoryItem, nullptr);
}
}
refresh();
}
} // End of namespace Illusions

View File

@@ -0,0 +1,111 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_BBDOU_INVENTORY_H
#define ILLUSIONS_BBDOU_BBDOU_INVENTORY_H
#include "illusions/specialcode.h"
#include "common/array.h"
#include "common/rect.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
class BbdouSpecialCode;
class Control;
struct TriggerFunction;
struct InventoryItem {
uint32 _objectId;
uint32 _sequenceId;
bool _assigned;
bool _flag;
int _timesPresent;
int _fieldE;
InventoryItem(uint32 objectId, uint32 sequenceId);
};
struct InventorySlot {
uint32 _namedPointId;
uint32 _objectId;
InventoryItem *_inventoryItem;
InventorySlot(uint32 namedPointId);
};
class InventoryBag {
public:
InventoryBag(IllusionsEngine_BBDOU *vm, uint32 sceneId);
~InventoryBag();
void registerInventorySlot(uint32 namedPointId);
bool addInventoryItem(InventoryItem *inventoryItem, InventorySlot *inventorySlot);
void removeInventoryItem(InventoryItem *inventoryItem);
bool hasInventoryItem(uint32 objectId);
void buildItems();
void clear();
InventorySlot *getInventorySlot(uint32 objectId);
InventorySlot *findClosestSlot(Common::Point putPos, int index);
protected:
public:
typedef Common::Array<InventorySlot*> InventorySlots;
typedef InventorySlots::iterator InventorySlotsIterator;
IllusionsEngine_BBDOU *_vm;
uint32 _sceneId;
InventorySlots _inventorySlots;
bool _isActive;
int _fieldA;
};
class BbdouInventory {
public:
BbdouInventory(IllusionsEngine_BBDOU *vm, BbdouSpecialCode *bbdou);
~BbdouInventory();
void registerInventoryBag(uint32 sceneId);
void registerInventoryItem(uint32 objectId, uint32 sequenceId);
void registerInventorySlot(uint32 namedPointId);
void addInventoryItem(uint32 objectId);
void removeInventoryItem(uint32 objectId);
bool hasInventoryItem(uint32 objectId);
void open();
void close();
InventoryBag *getInventoryBag(uint32 sceneId);
InventoryItem *getInventoryItem(uint32 objectId);
void refresh();
void buildItems(InventoryBag *inventoryBag);
void clear();
void cause0x1B0001(TriggerFunction *triggerFunction, uint32 callingThreadId);
void cause0x1B0002(TriggerFunction *triggerFunction, uint32 callingThreadId);
void putBackInventoryItem(uint32 objectId, Common::Point cursorPosition);
protected:
typedef Common::Array<InventoryItem*> InventoryItems;
typedef InventoryItems::iterator InventoryItemsIterator;
IllusionsEngine_BBDOU *_vm;
BbdouSpecialCode *_bbdou;
Common::Array<InventoryBag*> _inventoryBags;
InventoryItems _inventoryItems;
uint32 _activeBagSceneId;
uint32 _activeInventorySceneId;
int _index;
//field_12 dw
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_BBDOU_INVENTORY_H

View File

@@ -0,0 +1,58 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/bbdou_menukeys.h"
#include "illusions/bbdou/menusystem_bbdou.h"
#include "illusions/input.h"
#include "illusions/screen.h"
namespace Illusions {
// BBDOUMenuKeys
BBDOUMenuKeys::BBDOUMenuKeys(IllusionsEngine_BBDOU *vm)
: _vm(vm) {
}
BBDOUMenuKeys::~BBDOUMenuKeys() {
}
void BBDOUMenuKeys::addMenuKey(uint bitMask, uint32 threadId) {
MenuKey menuKey;
menuKey.bitMask = bitMask;
menuKey.threadId = threadId;
_menuKeys.push_back(menuKey);
}
void BBDOUMenuKeys::update() {
if (_vm->_screen->isDisplayOn() && !_vm->_menuSystem->isActive()) {
for (auto &menuKey : _menuKeys) {
if (_vm->_input->pollButton(menuKey.bitMask)) {
_vm->startScriptThread(menuKey.threadId, 0, 0, 0, 0);
break;
}
}
}
}
} // End of namespace Illusions

View File

@@ -0,0 +1,52 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_BBDOU_MENUKEYS_H
#define ILLUSIONS_BBDOU_BBDOU_MENUKEYS_H
#include "illusions/specialcode.h"
#include "illusions/thread.h"
#include "common/array.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
struct MenuKey {
uint bitMask;
uint32 threadId;
};
class BBDOUMenuKeys {
public:
BBDOUMenuKeys(IllusionsEngine_BBDOU *vm);
~BBDOUMenuKeys();
void addMenuKey(uint bitMask, uint32 threadId);
void update();
protected:
typedef Common::Array<MenuKey> MenuKeys;
IllusionsEngine_BBDOU *_vm;
MenuKeys _menuKeys;
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_BBDOU_MENUKEYS_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,203 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_BBDOU_SPECIALCODE_H
#define ILLUSIONS_BBDOU_BBDOU_SPECIALCODE_H
#include "illusions/specialcode.h"
#include "illusions/thread.h"
#include "common/hashmap.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
class BbdouBubble;
class BbdouCredits;
class BbdouCursor;
class BbdouFoodCtl;
class BbdouInventory;
struct CursorData;
struct VerbState;
typedef Common::Functor1<OpCall&, void> SpecialCodeFunction;
class BbdouSpecialCode;
struct Struct10 {
uint32 _verbId;
uint32 _sequenceId1;
uint32 _sequenceId2;
uint32 _sequenceId3;
};
class CauseThread_BBDOU : public Thread {
public:
CauseThread_BBDOU(IllusionsEngine_BBDOU *vm, uint32 threadId, uint32 callingThreadId,
BbdouSpecialCode *bbdou, uint32 cursorObjectId, uint32 sceneId,
uint32 verbId, uint32 objectId2, uint32 objectId);
void onNotify() override;
void onTerminated() override;
public:
BbdouSpecialCode *_bbdou;
uint32 _cursorObjectId;
uint32 _sceneId;
uint32 _verbId;
uint32 _objectId2;
uint32 _objectId;
};
struct RadarMicrophoneZone {
int16 _x;
uint32 _threadId;
};
class RadarMicrophoneThread : public Thread {
public:
RadarMicrophoneThread(IllusionsEngine_BBDOU *vm, uint32 threadId,
uint32 callingThreadId, uint32 cursorObjectId);
int onUpdate() override;
void addZone(uint32 threadId);
void initZones();
public:
uint32 _cursorObjectId;
uint _zonesCount;
uint _currZoneIndex;
RadarMicrophoneZone _zones[8];
};
struct ShooterStatus {
int gridX;
bool flag;
};
struct ObjectInteractMode {
uint32 _objectId;
int _interactMode;
ObjectInteractMode() : _objectId(0), _interactMode(0) {}
};
class ObjectInteractModeMap {
public:
ObjectInteractModeMap();
void setObjectInteractMode(uint32 objectId, int value);
int getObjectInteractMode(uint32 objectId);
protected:
ObjectInteractMode _objectVerbs[512];
};
class BbdouSpecialCode : public SpecialCode {
public:
BbdouSpecialCode(IllusionsEngine_BBDOU *vm);
~BbdouSpecialCode() override;
void init() override;
void run(uint32 specialCodeId, OpCall &opCall) override;
void resetBeforeResumeSavegame() override;
public:
typedef Common::HashMap<uint32, SpecialCodeFunction*> Map;
typedef Map::iterator MapIterator;
IllusionsEngine_BBDOU *_vm;
Map _map;
BbdouCursor *_cursor;
BbdouBubble *_bubble;
BbdouInventory *_inventory;
BbdouCredits *_credits;
// Salad
uint _saladCount;
uint32 _saladObjectIds[12];
// Shooter
ShooterStatus _shooterStatus[2];
uint _shooterObjectIdIndex;
BbdouFoodCtl *_foodCtl;
ObjectInteractModeMap _objectInteractModeMap;
// Special code interface functions
void spcInitCursor(OpCall &opCall);
void spcEnableCursor(OpCall &opCall);
void spcDisableCursor(OpCall &opCall);
void spcAddCursorSequence(OpCall &opCall);
void spcCursorStartHoldingObjectId(OpCall &opCall);
void spcCursorStopHoldingObjectId(OpCall &opCall);
void spcSetCursorState(OpCall &opCall);
void spcInitBubble(OpCall &opCall);
void spcSetupBubble(OpCall &opCall);
void spcSetObjectInteractMode(OpCall &opCall);
void spcInitInventory(OpCall &opCall);
void spcClearInventory(OpCall &opCall);
void spcRegisterInventoryBag(OpCall &opCall);
void spcRegisterInventorySlot(OpCall &opCall);
void spcRegisterInventoryItem(OpCall &opCall);
void spcOpenInventory(OpCall &opCall);
void spcAddInventoryItem(OpCall &opCall);
void spcRemoveInventoryItem(OpCall &opCall);
void spcHasInventoryItem(OpCall &opCall);
void spcCloseInventory(OpCall &opCall);
void spcInitConversation(OpCall &opCall);
void spcClearConversation(OpCall &opCall);
void spcClearBlockCounter(OpCall &opCall);
void spcResetCursor(OpCall &opCall);
void spcSetCursorField90(OpCall &opCall);
void spcFoodCtl(OpCall &opCall);
void spcTestFoodCtl(OpCall &opCall);
void spcInitMenu(OpCall &opCall);
void spcIsCursorHoldingObjectId(OpCall &opCall);
void spcInitRadarMicrophone(OpCall &opCall);
void spcCreditsCtl(OpCall &opCall);
void spcSaladCtl(OpCall &opCall);
void spcRunCause(OpCall &opCall);
void playSoundEffect(int soundIndex);
void hideVerbBubble(uint32 objectId, VerbState *verbState);
void startHoldingObjectId(uint32 objectId1, uint32 holdingObjectId, bool doPlaySound);
void stopHoldingObjectId(uint32 objectId1, bool doPlaySound);
bool isHoldingObjectId(uint32 objectId);
protected:
// Internal functions
bool testInteractModeRange(int value);
void setCursorControlRoutine(uint32 objectId, int num);
Common::Point getBackgroundCursorPos(Common::Point cursorPos);
void showBubble(uint32 objectId, uint32 overlappedObjectId, uint32 holdingObjectId,
VerbState *verbState, uint32 progResKeywordId);
bool findVerbId(VerbState *verbState, uint32 currOverlappedObjectId, int always0, uint32 &outVerbId);
void cursorInteractControlRoutine(Control *cursorControl, uint32 deltaTime);
void cursorCrosshairControlRoutine(Control *cursorControl, uint32 deltaTime);
bool testVerbId(uint32 verbId, uint32 holdingObjectId, uint32 overlappedObjectId);
bool getCause(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId,
uint32 &outVerbId, uint32 &outObjectId2, uint32 &outObjectId);
bool runCause(Control *cursorControl, CursorData &cursorData,
uint32 verbId, uint32 objectId2, uint32 objectId, int soundIndex);
uint32 startCauseThread(uint32 cursorObjectId, uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId);
// Salad
void initSalad();
void addSalad(uint32 sequenceId);
// Shooter
bool getShooterCause(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId,
uint32 &outSceneId, uint32 &outVerbId, uint32 &outObjectId2, uint32 &outObjectId);
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_BBDOU_SPECIALCODE_H

View File

@@ -0,0 +1,81 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/bbdou_triggerfunctions.h"
namespace Illusions {
// TriggerFunction
TriggerFunction::TriggerFunction(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, TriggerFunctionCallback *callback)
: _sceneId(sceneId), _verbId(verbId), _objectId2(objectId2), _objectId(objectId), _callback(callback) {
}
TriggerFunction::~TriggerFunction() {
delete _callback;
}
void TriggerFunction::run(uint32 callingThreadId) {
(*_callback)(this, callingThreadId);
}
// TriggerFunctions
void TriggerFunctions::add(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, TriggerFunctionCallback *callback) {
ItemsIterator it = findInternal(sceneId, verbId, objectId2, objectId);
if (it != _triggerFunctions.end()) {
delete *it;
_triggerFunctions.erase(it);
}
_triggerFunctions.push_back(new TriggerFunction(sceneId, verbId, objectId2, objectId, callback));
}
TriggerFunction *TriggerFunctions::find(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId) {
ItemsIterator it = findInternal(sceneId, verbId, objectId2, objectId);
if (it != _triggerFunctions.end())
return (*it);
return nullptr;
}
void TriggerFunctions::removeBySceneId(uint32 sceneId) {
ItemsIterator it = _triggerFunctions.begin();
while (it != _triggerFunctions.end()) {
if ((*it)->_sceneId == sceneId) {
delete *it;
it = _triggerFunctions.erase(it);
} else
++it;
}
}
TriggerFunctions::ItemsIterator TriggerFunctions::findInternal(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId) {
ItemsIterator it = _triggerFunctions.begin();
for (; it != _triggerFunctions.end(); ++it) {
TriggerFunction *triggerFunction = *it;
if (triggerFunction->_sceneId == sceneId && triggerFunction->_verbId == verbId &&
triggerFunction->_objectId2 == objectId2 && triggerFunction->_objectId == objectId)
break;
}
return it;
}
} // End of namespace Illusions

View File

@@ -0,0 +1,59 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_BBDOU_TRIGGERFUNCTIONS_H
#define ILLUSIONS_BBDOU_BBDOU_TRIGGERFUNCTIONS_H
#include "common/algorithm.h"
#include "common/stack.h"
namespace Illusions {
struct TriggerFunction;
typedef Common::Functor2<TriggerFunction*, uint32, void> TriggerFunctionCallback;
struct TriggerFunction {
uint32 _sceneId;
uint32 _verbId;
uint32 _objectId2;
uint32 _objectId;
TriggerFunctionCallback *_callback;
TriggerFunction(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, TriggerFunctionCallback *callback);
~TriggerFunction();
void run(uint32 callingThreadId);
};
class TriggerFunctions {
public:
void add(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, TriggerFunctionCallback *callback);
TriggerFunction *find(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId);
void removeBySceneId(uint32 sceneId);
public:
typedef Common::List<TriggerFunction*> Items;
typedef Items::iterator ItemsIterator;
Items _triggerFunctions;
ItemsIterator findInternal(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId);
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_BBDOU_TRIGGERFUNCTIONS_H

View File

@@ -0,0 +1,108 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/bbdou_videoplayer.h"
#include "illusions/actor.h"
#include "illusions/dictionary.h"
#include "illusions/input.h"
#include "illusions/screen.h"
#include "engines/util.h"
namespace Illusions {
// BBDOUVideoPlayer
BBDOUVideoPlayer::BBDOUVideoPlayer(IllusionsEngine_BBDOU *vm)
: _vm(vm), _videoDecoder(nullptr), _callingThreadId(0), _objectId(0) {
}
BBDOUVideoPlayer::~BBDOUVideoPlayer() {
delete _videoDecoder;
}
void BBDOUVideoPlayer::start(uint32 videoId, uint32 objectId, uint32 priority, uint32 callingThreadId) {
debug(0, "BBDOUVideoPlayer::play(%08X, %08X, %d, %08X)", videoId, objectId, priority, callingThreadId);
notifyCallingThread();
_objectId = objectId;
_callingThreadId = callingThreadId;
Control *videoControl = _vm->_dict->getObjectControl(objectId);
videoControl->_flags |= 0x0008;
_vm->_input->discardAllEvents();
Common::Path filename(Common::String::format("%08x.avi", videoId));
_videoDecoder = new Video::AVIDecoder();
if (!_videoDecoder->loadFile(filename)) {
delete _videoDecoder;
_videoDecoder = nullptr;
warning("Unable to open video %s", filename.toString().c_str());
notifyCallingThread();
return;
}
_videoDecoder->start();
}
void BBDOUVideoPlayer::stop() {
_vm->_input->discardAllEvents();
delete _videoDecoder;
_videoDecoder = nullptr;
notifyCallingThread();
_objectId = 0;
}
void BBDOUVideoPlayer::update() {
if (_vm->_input->pollEvent(kEventAbort) || _videoDecoder->endOfVideo()) {
stop();
} else if (_videoDecoder->needsUpdate()) {
Control *videoControl = _vm->_dict->getObjectControl(_objectId);
const Graphics::Surface *frame = _videoDecoder->decodeNextFrame();
Graphics::Surface *backSurface = videoControl->_actor->_surface;
if (frame->format.bytesPerPixel == g_system->getScreenFormat().bytesPerPixel) {
const int width = MIN(frame->w, backSurface->w) * frame->format.bytesPerPixel;
const int height = MIN(frame->h, backSurface->h);
const byte *src = (const byte*)frame->getPixels();
byte *dest = (byte*)backSurface->getPixels();
for (int yc = 0; yc < height; ++yc) {
memcpy(dest, src, width);
src += frame->pitch;
dest += backSurface->pitch;
}
}
ActorType *actorType = _vm->_dict->findActorType(videoControl->_actorTypeId);
videoControl->_actor->_frameIndex = 1;
videoControl->_actor->_surfInfo = actorType->_surfInfo;
videoControl->appearActor();
videoControl->deactivateObject();
videoControl->_actor->_flags &= ~0x2000;
}
}
bool BBDOUVideoPlayer::isPlaying() const {
return _videoDecoder != nullptr;
}
void BBDOUVideoPlayer::notifyCallingThread() {
if (_callingThreadId != 0) {
_vm->notifyThreadId(_callingThreadId);
_callingThreadId = 0;
}
}
} // End of namespace Illusions

View File

@@ -0,0 +1,51 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_VIDEOPLAYER_H
#define ILLUSIONS_BBDOU_VIDEOPLAYER_H
#include "illusions/illusions.h"
#include "video/avi_decoder.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
class BBDOUVideoPlayer {
public:
BBDOUVideoPlayer(IllusionsEngine_BBDOU *vm);
~BBDOUVideoPlayer();
void start(uint32 videoId, uint32 objectId, uint32 priority, uint32 callingThreadId);
void stop();
void update();
bool isPlaying() const;
public:
IllusionsEngine_BBDOU *_vm;
Video::VideoDecoder *_videoDecoder;
uint32 _objectId;
int _priority;
uint32 _callingThreadId;
void notifyCallingThread();
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_VIDEOPLAYER_H

View File

@@ -0,0 +1,52 @@
/* 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 "illusions/bbdou/gamestate_bbdou.h"
#include "illusions/bbdou/illusions_bbdou.h"
#include "illusions/resources/scriptresource.h"
namespace Illusions {
BBDOU_GameState::BBDOU_GameState(IllusionsEngine_BBDOU *vm)
: _vm(vm) {
}
uint32 BBDOU_GameState::calcWriteBufferSizeInternal() {
return
4 + // uint32 prevSceneId
_vm->_scriptResource->_properties.getSize() +
_vm->_scriptResource->_blockCounters.getSize();
}
bool BBDOU_GameState::readStateInternal(Common::ReadStream *in) {
_vm->_prevSceneId = in->readUint32LE();
return
_vm->_scriptResource->_properties.readFromStream(in) &&
_vm->_scriptResource->_blockCounters.readFromStream(in);
}
void BBDOU_GameState::writeStateInternal(Common::WriteStream *out) {
out->writeUint32LE(_vm->_prevSceneId);
_vm->_scriptResource->_properties.writeToStream(out);
_vm->_scriptResource->_blockCounters.writeToStream(out);
}
} // End of namespace Illusions

View File

@@ -0,0 +1,43 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_GAMESTATE_BBDOU_H
#define ILLUSIONS_BBDOU_GAMESTATE_BBDOU_H
#include "illusions/gamestate.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
class BBDOU_GameState : public GameState {
public:
BBDOU_GameState(IllusionsEngine_BBDOU *vm);
protected:
IllusionsEngine_BBDOU *_vm;
uint32 calcWriteBufferSizeInternal() override;
bool readStateInternal(Common::ReadStream *in) override;
void writeStateInternal(Common::WriteStream *out) override;
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_GAMESTATE_BBDOU_H

View File

@@ -0,0 +1,704 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/bbdou_menukeys.h"
#include "illusions/bbdou/bbdou_videoplayer.h"
#include "illusions/bbdou/gamestate_bbdou.h"
#include "illusions/bbdou/menusystem_bbdou.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
#include "illusions/console.h"
#include "illusions/cursor.h"
#include "illusions/dictionary.h"
#include "illusions/fileresourcereader.h"
#include "illusions/graphics.h"
#include "illusions/input.h"
#include "illusions/resources/actorresource.h"
#include "illusions/resources/backgroundresource.h"
#include "illusions/resources/fontresource.h"
#include "illusions/resources/scriptresource.h"
#include "illusions/resources/soundresource.h"
#include "illusions/resources/talkresource.h"
#include "illusions/resourcesystem.h"
#include "illusions/screen.h"
#include "illusions/screentext.h"
#include "illusions/scriptstack.h"
#include "illusions/bbdou/scriptopcodes_bbdou.h"
#include "illusions/sound.h"
#include "illusions/specialcode.h"
#include "illusions/bbdou/bbdou_specialcode.h"
#include "illusions/thread.h"
#include "illusions/time.h"
#include "illusions/updatefunctions.h"
#include "illusions/threads/abortablethread.h"
#include "illusions/threads/scriptthread.h"
#include "illusions/threads/talkthread.h"
#include "illusions/threads/timerthread.h"
#include "audio/audiostream.h"
#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "common/error.h"
#include "common/fs.h"
#include "common/timer.h"
#include "engines/util.h"
#include "graphics/cursorman.h"
#include "graphics/font.h"
#include "graphics/fontman.h"
#include "graphics/surface.h"
namespace Illusions {
// ActiveScenes
ActiveScenes::ActiveScenes() {
clear();
}
void ActiveScenes::clear() {
_stack.clear();
}
void ActiveScenes::push(uint32 sceneId) {
ActiveScene activeScene;
activeScene._sceneId = sceneId;
activeScene._pauseCtr = 0;
_stack.push(activeScene);
}
void ActiveScenes::pop() {
_stack.pop();
}
void ActiveScenes::pauseActiveScene() {
++_stack.top()._pauseCtr;
}
void ActiveScenes::unpauseActiveScene() {
--_stack.top()._pauseCtr;
}
uint ActiveScenes::getActiveScenesCount() {
return _stack.size();
}
void ActiveScenes::getActiveSceneInfo(uint index, uint32 *sceneId, int *pauseCtr) {
if (sceneId)
*sceneId = _stack[index - 1]._sceneId;
if (pauseCtr)
*pauseCtr = _stack[index - 1]._pauseCtr;
}
uint32 ActiveScenes::getCurrentScene() {
if (_stack.size() > 0)
return _stack.top()._sceneId;
return 0;
}
bool ActiveScenes::isSceneActive(uint32 sceneId) {
for (uint i = 0; i < _stack.size(); ++i) {
if (_stack[i]._sceneId == sceneId && _stack[i]._pauseCtr <= 0)
return true;
}
return false;
}
// IllusionsEngine_BBDOU
IllusionsEngine_BBDOU::IllusionsEngine_BBDOU(OSystem *syst, const IllusionsGameDescription *gd)
: IllusionsEngine(syst, gd) {
}
Common::Error IllusionsEngine_BBDOU::run() {
// Init search paths
const Common::FSNode gameDataDir(ConfMan.getPath("path"));
SearchMan.addSubDirectoryMatching(gameDataDir, "music");
SearchMan.addSubDirectoryMatching(gameDataDir, "resource");
SearchMan.addSubDirectoryMatching(gameDataDir, "resrem");
SearchMan.addSubDirectoryMatching(gameDataDir, "savegame");
SearchMan.addSubDirectoryMatching(gameDataDir, "sfx", 0, 2);
SearchMan.addSubDirectoryMatching(gameDataDir, "video");
SearchMan.addSubDirectoryMatching(gameDataDir, "voice");
_dict = new Dictionary();
_resReader = new ResourceReaderFileReader();
_resSys = new ResourceSystem(this);
_resSys->addResourceLoader(0x00060000, new ActorResourceLoader(this));
_resSys->addResourceLoader(0x00080000, new SoundGroupResourceLoader(this));
_resSys->addResourceLoader(0x000D0000, new ScriptResourceLoader(this));
_resSys->addResourceLoader(0x000F0000, new TalkResourceLoader(this));
_resSys->addResourceLoader(0x00100000, new ActorResourceLoader(this));
_resSys->addResourceLoader(0x00110000, new BackgroundResourceLoader(this));
_resSys->addResourceLoader(0x00120000, new FontResourceLoader(this));
_resSys->addResourceLoader(0x00170000, new SpecialCodeLoader(this));
setDebugger(new Console(this));
_screen = new Screen16Bit(this, 640, 480);
_screenPalette = new NullScreenPalette();
_screenText = new ScreenText(this);
_input = new Input();
_actorInstances = new ActorInstanceList(this);
_backgroundInstances = new BackgroundInstanceList(this);
_camera = new Camera(this);
_controls = new Controls(this);
_cursor = new Cursor(this);
_talkItems = new TalkInstanceList(this);
_triggerFunctions = new TriggerFunctions();
_threads = new ThreadList(this);
_updateFunctions = new UpdateFunctions();
_soundMan = new SoundMan(this);
_menuSystem = new BBDOUMenuSystem(this);
_videoPlayer = new BBDOUVideoPlayer(this);
_gameState = new BBDOU_GameState(this);
_menuKeys = new BBDOUMenuKeys(this);
_screen->setColorKey1(0xF81F);
initInput();
initUpdateFunctions();
_fader = nullptr;
_scriptOpcodes = new ScriptOpcodes_BBDOU(this);
_stack = new ScriptStack();
_resGetCtr = 0;
_unpauseControlActorFlag = false;
_lastUpdateTime = 0;
_pauseCtr = 0;
_field8 = 1;
_fieldA = 0;
ConfMan.registerDefault("talkspeed", 240);
_subtitleDuration = (uint16)ConfMan.getInt("talkspeed");
_globalSceneId = 0x00010003;
setDefaultTextCoords();
_resSys->loadResource(0x000D0001, 0, 0);
_doScriptThreadInit = false;
startScriptThread(0x00020004, 0, 0, 0, 0);
_doScriptThreadInit = true;
if (ConfMan.hasKey("save_slot")) {
loadGameState(ConfMan.getInt("save_slot"));
}
_walkthroughStarted = false;
_canResumeFromSavegame = false;
while (!shouldQuit()) {
if (_walkthroughStarted) {
//enterScene(0x10003, 0);
startScriptThread(0x00020404, 0, 0, 0, 0);
_walkthroughStarted = false;
}
if (_resumeFromSavegameRequested && _canResumeFromSavegame) {
resumeFromSavegame();
_resumeFromSavegameRequested = false;
}
runUpdateFunctions();
_system->updateScreen();
updateEvents();
}
unloadSpecialCode(0);
_resSys->unloadAllResources();
delete _stack;
delete _scriptOpcodes;
delete _menuKeys;
delete _gameState;
delete _videoPlayer;
delete _menuSystem;
delete _soundMan;
delete _updateFunctions;
delete _threads;
delete _triggerFunctions;
delete _talkItems;
delete _cursor;
delete _controls;
delete _camera;
delete _backgroundInstances;
delete _actorInstances;
delete _input;
delete _screenText;
delete _screenPalette;
delete _screen;
delete _resSys;
delete _resReader;
delete _dict;
debug("Ok");
return Common::kNoError;
}
bool IllusionsEngine_BBDOU::hasFeature(EngineFeature f) const {
return
(f == kSupportsReturnToLauncher) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
void IllusionsEngine_BBDOU::initInput() {
_input->setInputEvent(kEventLeftClick, 0x01)
.addMouseButton(MOUSE_LEFT_BUTTON);
_input->setInputEvent(kEventRightClick, 0x02)
.addMouseButton(MOUSE_RIGHT_BUTTON);
_input->setInputEvent(kEventInventory, 0x04)
.addMouseButton(MOUSE_RIGHT_BUTTON)
.addKey(kActionInventory);
_input->setInputEvent(kEventAbort, 0x08)
.addKey(kActionAbort);
_input->setInputEvent(kEventSkip, 0x10)
.addKey(kActionSkip);
_input->setInputEvent(kEventF1, 0x20)
.addKey(kActionCheatMode);
_input->setInputEvent(kEventUp, 0x40)
.addKey(kActionCursorUp);
_input->setInputEvent(kEventDown, 0x80)
.addMouseButton(MOUSE_RIGHT_BUTTON)
.addKey(kActionCursorDown);
}
#define UPDATEFUNCTION(priority, sceneId, callback) \
_updateFunctions->add(priority, sceneId, new Common::Functor1Mem<uint, int, IllusionsEngine_BBDOU> \
(this, &IllusionsEngine_BBDOU::callback));
void IllusionsEngine_BBDOU::initUpdateFunctions() {
UPDATEFUNCTION(30, 0, updateScript);
UPDATEFUNCTION(50, 0, updateActors);
UPDATEFUNCTION(60, 0, updateMenuKeys);
UPDATEFUNCTION(60, 0, updateSequences);
UPDATEFUNCTION(70, 0, updateGraphics);
UPDATEFUNCTION(70, 0, updateVideoPlayer);
UPDATEFUNCTION(90, 0, updateSprites);
UPDATEFUNCTION(120, 0, updateSoundMan);
}
#undef UPDATEFUNCTION
int IllusionsEngine_BBDOU::updateScript(uint flags) {
_threads->updateThreads();
return kUFNext;
}
int IllusionsEngine_BBDOU::updateMenuKeys(uint flags) {
_menuKeys->update();
return kUFNext;
}
bool IllusionsEngine_BBDOU::causeIsDeclared(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId) {
uint32 codeOffs;
return
_triggerFunctions->find(sceneId, verbId, objectId2, objectId) ||
findTriggerCause(sceneId, verbId, objectId2, objectId, codeOffs);
}
void IllusionsEngine_BBDOU::causeDeclare(uint32 verbId, uint32 objectId2, uint32 objectId, TriggerFunctionCallback *callback) {
_triggerFunctions->add(getCurrentScene(), verbId, objectId2, objectId, callback);
}
uint32 IllusionsEngine_BBDOU::causeTrigger(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 callingThreadId) {
uint32 codeOffs;
uint32 causeThreadId = 0;
TriggerFunction *triggerFunction = _triggerFunctions->find(sceneId, verbId, objectId2, objectId);
if (triggerFunction) {
triggerFunction->run(callingThreadId);
} else if (findTriggerCause(sceneId, verbId, objectId2, objectId, codeOffs)) {
causeThreadId = startTempScriptThread(_scriptResource->getCode(codeOffs),
callingThreadId, verbId, objectId2, objectId);
}
return causeThreadId;
}
int IllusionsEngine_BBDOU::updateVideoPlayer(uint flags) {
if (_videoPlayer->isPlaying())
_videoPlayer->update();
return kUFNext;
}
void IllusionsEngine_BBDOU::playVideo(uint32 videoId, uint32 objectId, uint32 priority, uint32 callingThreadId) {
_videoPlayer->start(videoId, objectId, priority, callingThreadId);
}
bool IllusionsEngine_BBDOU::isVideoPlaying() {
return _videoPlayer->isPlaying();
}
void IllusionsEngine_BBDOU::setDefaultTextCoords() {
WidthHeight dimensions;
dimensions._width = 480;
dimensions._height = 48;
Common::Point pt(320, 448);
setDefaultTextDimensions(dimensions);
setDefaultTextPosition(pt);
}
void IllusionsEngine_BBDOU::loadSpecialCode(uint32 resId) {
_specialCode = new BbdouSpecialCode(this);
_specialCode->init();
}
void IllusionsEngine_BBDOU::unloadSpecialCode(uint32 resId) {
delete _specialCode;
_specialCode = nullptr;
}
void IllusionsEngine_BBDOU::notifyThreadId(uint32 &threadId) {
if (threadId) {
uint32 tempThreadId = threadId;
threadId = 0;
_threads->notifyId(tempThreadId);
}
}
bool IllusionsEngine_BBDOU::testMainActorFastWalk(Control *control) {
return false;
}
bool IllusionsEngine_BBDOU::testMainActorCollision(Control *control) {
// Not used in BBDOU
return false;
}
Control *IllusionsEngine_BBDOU::getObjectControl(uint32 objectId) {
return _dict->getObjectControl(objectId);
}
Common::Point IllusionsEngine_BBDOU::getNamedPointPosition(uint32 namedPointId) {
Common::Point pt;
if (_backgroundInstances->findActiveBackgroundNamedPoint(namedPointId, pt) ||
_actorInstances->findNamedPoint(namedPointId, pt) ||
_controls->findNamedPoint(namedPointId, pt))
return pt;
// TODO
switch (namedPointId) {
case 0x70001:
return Common::Point(0, 0);
case 0x70002:
return Common::Point(640, 0);
case 0x70023:
return Common::Point(320, 240);
default:
break;
}
debug("getNamedPointPosition(%08X) UNKNOWN", namedPointId);
return Common::Point(0, 0);
}
uint32 IllusionsEngine_BBDOU::getPriorityFromBase(int16 priority) {
return 32000000 * priority;
}
uint32 IllusionsEngine_BBDOU::getCurrentScene() {
return _activeScenes.getCurrentScene();
}
uint32 IllusionsEngine_BBDOU::getPrevScene() {
return _prevSceneId;
}
bool IllusionsEngine_BBDOU::isCursorObject(uint32 actorTypeId, uint32 objectId) {
return actorTypeId == 0x50001 && objectId == Illusions::CURSOR_OBJECT_ID;
}
void IllusionsEngine_BBDOU::setCursorControlRoutine(Control *control) {
control->_actor->setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, IllusionsEngine_BBDOU>
(this, &IllusionsEngine_BBDOU::cursorControlRoutine));
}
void IllusionsEngine_BBDOU::placeCursorControl(Control *control, uint32 sequenceId) {
_cursor->place(control, sequenceId);
}
void IllusionsEngine_BBDOU::setCursorControl(Control *control) {
_cursor->setControl(control);
}
void IllusionsEngine_BBDOU::showCursor() {
_cursor->show();
}
void IllusionsEngine_BBDOU::hideCursor() {
_cursor->hide();
}
void IllusionsEngine_BBDOU::cursorControlRoutine(Control *control, uint32 deltaTime) {
control->_actor->_seqCodeValue1 = 100 * deltaTime;
if (control->_actor->_flags & Illusions::ACTOR_FLAG_IS_VISIBLE) {
switch (_cursor->_status) {
case 2:
// Unused nullsub_1(control);
break;
case 3:
_menuSystem->update(control);
break;
default:
break;
}
}
}
void IllusionsEngine_BBDOU::startScriptThreadSimple(uint32 threadId, uint32 callingThreadId) {
startScriptThread(threadId, callingThreadId, 0, 0, 0);
}
void IllusionsEngine_BBDOU::startScriptThread(uint32 threadId, uint32 callingThreadId,
uint32 value8, uint32 valueC, uint32 value10) {
if (threadId == 0x0002041E && ConfMan.hasKey("save_slot")) {
// Skip intro videos when loading a savegame from the launcher (kludge)
notifyThreadId(callingThreadId);
return;
}
debug(2, "Starting script thread %08X", threadId);
byte *scriptCodeIp = _scriptResource->getThreadCode(threadId);
newScriptThread(threadId, callingThreadId, 0, scriptCodeIp, value8, valueC, value10);
}
void IllusionsEngine_BBDOU::startAnonScriptThread(int32 threadId, uint32 callingThreadId,
uint32 value8, uint32 valueC, uint32 value10) {
debug(2, "Starting anonymous script thread %08X", threadId);
uint32 tempThreadId = newTempThreadId();
byte *scriptCodeIp = _scriptResource->getThreadCode(threadId);
scriptCodeIp = _scriptResource->getThreadCode(threadId);
newScriptThread(tempThreadId, callingThreadId, 0, scriptCodeIp, value8, valueC, value10);
}
uint32 IllusionsEngine_BBDOU::startAbortableTimerThread(uint32 duration, uint32 threadId) {
return newTimerThread(duration, threadId, true);
}
uint32 IllusionsEngine_BBDOU::startTimerThread(uint32 duration, uint32 threadId) {
return newTimerThread(duration, threadId, false);
}
uint32 IllusionsEngine_BBDOU::startAbortableThread(byte *scriptCodeIp1, byte *scriptCodeIp2, uint32 callingThreadId) {
uint32 tempThreadId = newTempThreadId();
debug(2, "Starting abortable thread %08X", tempThreadId);
uint32 scriptThreadId = startTempScriptThread(scriptCodeIp1, tempThreadId, 0, 0, 0);
AbortableThread *abortableThread = new AbortableThread(this, tempThreadId, callingThreadId, 0,
scriptThreadId, scriptCodeIp2);
_threads->startThread(abortableThread);
return tempThreadId;
}
uint32 IllusionsEngine_BBDOU::startTalkThread(int16 duration, uint32 objectId, uint32 talkId, uint32 sequenceId1,
uint32 sequenceId2, uint32 namedPointId, uint32 callingThreadId) {
debug(2, "Starting talk thread");
uint32 tempThreadId = newTempThreadId();
_threads->endTalkThreadsNoNotify();
TalkThread *talkThread = new TalkThread(this, tempThreadId, callingThreadId, 0,
duration, objectId, talkId, sequenceId1, sequenceId2, namedPointId);
_threads->startThread(talkThread);
return tempThreadId;
}
uint32 IllusionsEngine_BBDOU::startTempScriptThread(byte *scriptCodeIp, uint32 callingThreadId,
uint32 value8, uint32 valueC, uint32 value10) {
uint32 tempThreadId = newTempThreadId();
debug(2, "Starting temp script thread %08X", tempThreadId);
newScriptThread(tempThreadId, callingThreadId, 0, scriptCodeIp, value8, valueC, value10);
return tempThreadId;
}
void IllusionsEngine_BBDOU::newScriptThread(uint32 threadId, uint32 callingThreadId, uint notifyFlags,
byte *scriptCodeIp, uint32 value8, uint32 valueC, uint32 value10) {
ScriptThread *scriptThread = new ScriptThread(this, threadId, callingThreadId, notifyFlags,
scriptCodeIp, value8, valueC, value10);
_threads->startThread(scriptThread);
if (_pauseCtr > 0)
scriptThread->pause();
if (_doScriptThreadInit) {
int updateResult = kTSRun;
while (scriptThread->_pauseCtr <= 0 && updateResult != kTSTerminate && updateResult != kTSYield) {
updateResult = scriptThread->update();
}
}
}
uint32 IllusionsEngine_BBDOU::newTimerThread(uint32 duration, uint32 callingThreadId, bool isAbortable) {
uint32 tempThreadId = newTempThreadId();
TimerThread *timerThread = new TimerThread(this, tempThreadId, callingThreadId, 0,
duration, isAbortable);
_threads->startThread(timerThread);
return tempThreadId;
}
uint32 IllusionsEngine_BBDOU::newTempThreadId() {
uint32 threadId = _nextTempThreadId + 2 * _scriptResource->_codeCount;
if (threadId > 65535) {
_nextTempThreadId = 0;
threadId = 2 * _scriptResource->_codeCount;
}
++_nextTempThreadId;
return 0x00020000 | threadId;
}
bool IllusionsEngine_BBDOU::enterScene(uint32 sceneId, uint32 threadId) {
SceneInfo *sceneInfo = _scriptResource->getSceneInfo(sceneId & 0xFFFF);
if (!sceneInfo) {
dumpActiveScenes(_globalSceneId, threadId);
sceneId = _theSceneId;
}
_activeScenes.push(sceneId);
if (sceneId == 0x0001007D) {
// Savegame loading from the ScummVM GUI or command line is only
// possible after resources have been initialized by the startup script.
// Once that script is done, it switches to the start menu scene.
// After that the game is ready and a savegame can finally be loaded.
_canResumeFromSavegame = true;
}
return sceneInfo != nullptr;
}
void IllusionsEngine_BBDOU::exitScene(uint32 threadId) {
uint32 sceneId = _activeScenes.getCurrentScene();
_updateFunctions->terminateByScene(sceneId);
_threads->terminateThreadsBySceneId(sceneId, threadId);
_controls->destroyControlsBySceneId(sceneId);
_triggerFunctions->removeBySceneId(sceneId);
_resSys->unloadResourcesBySceneId(sceneId);
_activeScenes.pop();
}
void IllusionsEngine_BBDOU::enterPause(uint32 threadId) {
uint32 sceneId = _activeScenes.getCurrentScene();
_camera->pushCameraMode();
_threads->suspendThreadsBySceneId(sceneId, threadId);
_controls->pauseControlsBySceneId(sceneId);
_actorInstances->pauseBySceneId(sceneId);
_backgroundInstances->pauseBySceneId(sceneId);
_activeScenes.pauseActiveScene();
}
void IllusionsEngine_BBDOU::leavePause(uint32 threadId) {
uint32 sceneId = _activeScenes.getCurrentScene();
_backgroundInstances->unpauseBySceneId(sceneId);
_actorInstances->unpauseBySceneId(sceneId);
_controls->unpauseControlsBySceneId(sceneId);
_threads->notifyThreadsBySceneId(sceneId, threadId);
_camera->popCameraMode();
_activeScenes.unpauseActiveScene();
}
void IllusionsEngine_BBDOU::dumpActiveScenes(uint32 sceneId, uint32 threadId) {
uint activeScenesCount = _activeScenes.getActiveScenesCount();
while (activeScenesCount > 0) {
uint32 activeSceneId;
_activeScenes.getActiveSceneInfo(activeScenesCount, &activeSceneId, nullptr);
if (activeSceneId == sceneId)
break;
exitScene(threadId);
--activeScenesCount;
}
_camera->clearCameraModeStack();
}
void IllusionsEngine_BBDOU::pause(uint32 callerThreadId) {
if (++_pauseCtr == 1) {
_threads->pauseThreads(callerThreadId);
_camera->pause();
pauseFader();
_controls->pauseActors(0x40004);
}
}
void IllusionsEngine_BBDOU::unpause(uint32 callerThreadId) {
if (--_pauseCtr == 0) {
_controls->unpauseActors(0x40004);
unpauseFader();
_camera->unpause();
_threads->unpauseThreads(callerThreadId);
}
}
void IllusionsEngine_BBDOU::enterMenuPause() {
// TODO suspendAudio();
_screenText->clearText();
}
void IllusionsEngine_BBDOU::leaveMenuPause() {
_screenText->removeText();
// TODO unsuspendAudio();
}
void IllusionsEngine_BBDOU::setSceneIdThreadId(uint32 theSceneId, uint32 theThreadId) {
_theSceneId = theSceneId;
_theThreadId = theThreadId;
}
bool IllusionsEngine_BBDOU::findTriggerCause(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &codeOffs) {
SceneInfo *sceneInfo = _scriptResource->getSceneInfo(sceneId & 0xFFFF);
if (sceneInfo)
return sceneInfo->findTriggerCause(verbId, objectId2, objectId, codeOffs);
return false;
}
void IllusionsEngine_BBDOU::reset() {
_scriptResource->_blockCounters.clear();
_scriptResource->_properties.clear();
setTextDuration(1, 0);
}
void IllusionsEngine_BBDOU::loadSavegameFromScript(int16 slotNum, uint32 callingThreadId) {
// NOTE Just loads the savegame, doesn't activate it yet
Common::String fileName = getSavegameFilename(_targetName, _savegameSlotNum);
_loadGameResult = loadgame(fileName.c_str());
}
void IllusionsEngine_BBDOU::saveSavegameFromScript(int16 slotNum, uint32 callingThreadId) {
// TODO
// Common::String fileName = getSavegameFilename(_targetName, slotNum);
_saveGameResult = false;//savegame(fileName.c_str(), _savegameDescription.c_str());
}
void IllusionsEngine_BBDOU::activateSavegame(uint32 callingThreadId) {
uint32 sceneId, threadId;
_prevSceneId = 0x10000;
_gameState->readState(sceneId, threadId);
enterScene(sceneId, callingThreadId);
// TODO Check if value8, valueC, value10 are needed at all
startAnonScriptThread(threadId, 0, 0, 0, 0);
_gameState->deleteReadStream();
}
void IllusionsEngine_BBDOU::resumeFromSavegame() {
// Resetting the game is usually done by the script, when loading from the ScummVM menu or
// command line this has to be done manually.
_specialCode->resetBeforeResumeSavegame();
dumpActiveScenes(0x00010003, 0);
activateSavegame(0);
}
} // End of namespace Illusions

View File

@@ -0,0 +1,164 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_ILLUSIONS_BBDOU_H
#define ILLUSIONS_ILLUSIONS_BBDOU_H
#include "illusions/illusions.h"
#include "illusions/bbdou/bbdou_triggerfunctions.h"
#include "common/algorithm.h"
#include "common/stack.h"
namespace Illusions {
class Dictionary;
class ScriptMan;
class ScriptStack;
class BBDOUVideoPlayer;
class BBDOUMenuKeys;
class BBDOUMenuSystem;
struct ActiveScene {
uint32 _sceneId;
int _pauseCtr;
};
class ActiveScenes {
public:
ActiveScenes();
void clear();
void push(uint32 sceneId);
void pop();
void pauseActiveScene();
void unpauseActiveScene();
uint getActiveScenesCount();
void getActiveSceneInfo(uint index, uint32 *sceneId, int *pauseCtr);
uint32 getCurrentScene();
bool isSceneActive(uint32 sceneId);
protected:
Common::FixedStack<ActiveScene, 16> _stack;
};
class IllusionsEngine_BBDOU : public IllusionsEngine {
public:
IllusionsEngine_BBDOU(OSystem *syst, const IllusionsGameDescription *gd);
protected:
Common::Error run() override;
bool hasFeature(EngineFeature f) const override;
public:
ScriptMan *_scriptMan;
TriggerFunctions *_triggerFunctions;
Cursor *_cursor;
ActiveScenes _activeScenes;
uint32 _prevSceneId;
uint32 _theSceneId;
uint32 _theThreadId;
uint32 _globalSceneId;
bool _loadGameResult, _saveGameResult;
BBDOUMenuSystem *_menuSystem;
BBDOUVideoPlayer *_videoPlayer;
BBDOUMenuKeys *_menuKeys;
bool _walkthroughStarted;
bool _canResumeFromSavegame;
void initInput();
void initUpdateFunctions();
int updateScript(uint flags);
int updateMenuKeys(uint flags);
bool causeIsDeclared(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId);
void causeDeclare(uint32 verbId, uint32 objectId2, uint32 objectId, TriggerFunctionCallback *callback);
uint32 causeTrigger(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 callingThreadId);
int updateVideoPlayer(uint flags);
void playVideo(uint32 videoId, uint32 objectId, uint32 priority, uint32 callingThreadId);
bool isVideoPlaying() override;
void setDefaultTextCoords() override;
void loadSpecialCode(uint32 resId) override;
void unloadSpecialCode(uint32 resId) override;
void notifyThreadId(uint32 &threadId) override;
bool testMainActorFastWalk(Control *control) override;
bool testMainActorCollision(Control *control) override;
Control *getObjectControl(uint32 objectId) override;
Common::Point getNamedPointPosition(uint32 namedPointId) override;
uint32 getPriorityFromBase(int16 priority) override;
uint32 getCurrentScene() override;
uint32 getPrevScene() override;
bool isCursorObject(uint32 actorTypeId, uint32 objectId) override;
void setCursorControlRoutine(Control *control) override;
void placeCursorControl(Control *control, uint32 sequenceId) override;
void setCursorControl(Control *control) override;
void showCursor() override;
void hideCursor() override;
void cursorControlRoutine(Control *control, uint32 deltaTime);
void startScriptThreadSimple(uint32 threadId, uint32 callingThreadId) override;
void startScriptThread(uint32 threadId, uint32 callingThreadId,
uint32 value8, uint32 valueC, uint32 value10);
void startAnonScriptThread(int32 threadId, uint32 callingThreadId,
uint32 value8, uint32 valueC, uint32 value10);
uint32 startAbortableTimerThread(uint32 duration, uint32 threadId);
uint32 startTimerThread(uint32 duration, uint32 threadId);
uint32 startAbortableThread(byte *scriptCodeIp1, byte *scriptCodeIp2, uint32 callingThreadId);
uint32 startTalkThread(int16 duration, uint32 objectId, uint32 talkId, uint32 sequenceId1,
uint32 sequenceId2, uint32 namedPointId, uint32 callingThreadId);
uint32 startTempScriptThread(byte *scriptCodeIp, uint32 callingThreadId,
uint32 value8, uint32 valueC, uint32 value10) override;
void newScriptThread(uint32 threadId, uint32 callingThreadId, uint notifyFlags,
byte *scriptCodeIp, uint32 value8, uint32 valueC, uint32 value10);
uint32 newTimerThread(uint32 duration, uint32 callingThreadId, bool isAbortable);
uint32 newTempThreadId();
bool enterScene(uint32 sceneId, uint32 threadId);
void exitScene(uint32 threadId);
void enterPause(uint32 threadId);
void leavePause(uint32 threadId);
void dumpActiveScenes(uint32 sceneId, uint32 threadId);
void pause(uint32 callerThreadId);
void unpause(uint32 callerThreadId);
void enterMenuPause();
void leaveMenuPause();
void setSceneIdThreadId(uint32 theSceneId, uint32 theThreadId);
bool findTriggerCause(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &codeOffs);
void reset();
void loadSavegameFromScript(int16 slotNum, uint32 callingThreadId);
void saveSavegameFromScript(int16 slotNum, uint32 callingThreadId);
void activateSavegame(uint32 callingThreadId);
void resumeFromSavegame();
};
} // End of namespace Illusions
#endif // ILLUSIONS_ILLUSIONS_H

View File

@@ -0,0 +1,173 @@
/* 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 "illusions/illusions.h"
#include "illusions/actor.h"
#include "illusions/cursor.h"
#include "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/menusystem_bbdou.h"
namespace Illusions {
// BBDOUMenuSystem
BBDOUMenuSystem::BBDOUMenuSystem(IllusionsEngine_BBDOU *vm)
: BaseMenuSystem(vm), _vm(vm) {
clearMenus();
}
BBDOUMenuSystem::~BBDOUMenuSystem() {
freeMenus();
}
void BBDOUMenuSystem::runMenu(MenuChoiceOffsets menuChoiceOffsets, int16 *menuChoiceOffset,
uint32 menuId, uint32 duration, uint timeOutMenuChoiceIndex, uint32 menuCallerThreadId) {
debug(0, "BBDOUMenuSystem::runMenu(%08X)", menuId);
setTimeOutDuration(duration, timeOutMenuChoiceIndex);
setMenuCallerThreadId(menuCallerThreadId);
setMenuChoiceOffsets(menuChoiceOffsets, menuChoiceOffset);
int rootMenuId = convertRootMenuId(menuId);
BaseMenu *rootMenu = getMenuById(rootMenuId);
openMenu(rootMenu);
}
void BBDOUMenuSystem::clearMenus() {
for (int i = 0; i < kBBDOULastMenuIndex; ++i) {
_menus[i] = nullptr;
}
}
void BBDOUMenuSystem::freeMenus() {
for (int i = 0; i < kBBDOULastMenuIndex; ++i) {
delete _menus[i];
}
}
BaseMenu *BBDOUMenuSystem::getMenuById(int menuId) {
if (!_menus[menuId])
_menus[menuId] = createMenuById(menuId);
return _menus[menuId];
}
BaseMenu *BBDOUMenuSystem::createMenuById(int menuId) {
switch (menuId) {
case kBBDOUMainMenu:
return createMainMenu();
case kBBDOUPauseMenu:
return createPauseMenu();
// TODO Other menus
default:
error("BBDOUMenuSystem::createMenuById() Invalid menu id %d", menuId);
}
}
BaseMenu *BBDOUMenuSystem::createMainMenu() {
return nullptr; // TODO
}
BaseMenu *BBDOUMenuSystem::createLoadGameMenu() {
return nullptr; // TODO
}
BaseMenu *BBDOUMenuSystem::createOptionsMenu() {
return nullptr; // TODO
}
BaseMenu *BBDOUMenuSystem::createPauseMenu() {
BaseMenu *menu = new BaseMenu(this, 0x00120003, 218, 150, 80, 20, 1);
menu->addText(" Game Paused");
menu->addText("-------------------");
menu->addMenuItem(new MenuItem("Resume", new MenuActionReturnChoice(this, 1)));
// menu->addMenuItem(new MenuItem("Load Game", new MenuActionLoadGame(this, 1)));
// TODO menu->addMenuItem(new MenuItem("Save Game", new MenuActionSaveGame(this, 11)));
// TODO menu->addMenuItem(new MenuItem("Restart Game", new MenuActionEnterQueryMenu(this, kDuckmanQueryRestartMenu, 2)));
// TODO menu->addMenuItem(new MenuItem("Options", new MenuActionEnterMenu(this, kDuckmanOptionsMenu)));
// menu->addMenuItem(new MenuItem("Quit Game", new MenuActionEnterQueryMenu(this, kDuckmanQueryQuitMenu, 23)));
return menu;
}
int BBDOUMenuSystem::convertRootMenuId(uint32 menuId) {
switch (menuId) {
case 0x1C0001:
return kBBDOUMainMenu;
case 0x1C0002:
return kBBDOUPauseMenu;
case 0x1C0006:
return kBBDOULoadGameMenu;
case 0x1C0007:
return kBBDOUSaveGameMenu;
case 0x1C0008:
return kBBDOUGameSavedMenu;
case 0x1C0009:
return kBBDOUSaveFailedMenu;
case 0x1C000A:
return kBBDOULoadFailedMenu;
/* Unused/unimplemented debug menus
case 0x1C0003: debugStartMenu
case 0x1C0004: debugPauseMenu
case 0x1C0005: unitTestsMenu
*/
default:
error("BBDOUMenuSystem() Menu ID %08X not found", menuId);
}
}
bool BBDOUMenuSystem::initMenuCursor() {
bool cursorInitialVisibleFlag = false;
Control *cursorControl = _vm->getObjectControl(0x40004);
if (cursorControl) {
if (cursorControl->_flags & 1) {
cursorInitialVisibleFlag = false;
} else {
cursorInitialVisibleFlag = true;
cursorControl->appearActor();
}
} else {
Common::Point pos = _vm->getNamedPointPosition(0x70023);
_vm->_controls->placeActor(0x50001, pos, 0x60001, 0x40004, 0);
cursorControl = _vm->getObjectControl(0x40004);
}
return cursorInitialVisibleFlag;
}
int BBDOUMenuSystem::getGameState() {
return _vm->_cursor->_status;
}
void BBDOUMenuSystem::setMenuCursorNum(int cursorNum) {
Control *mouseCursor = _vm->getObjectControl(0x40004);
_vm->_cursor->setActorIndex(5, cursorNum, 0);
mouseCursor->startSequenceActor(0x60001, 2, 0);
}
void BBDOUMenuSystem::setGameState(int gameState) {
_vm->_cursor->_status = gameState;
}
void BBDOUMenuSystem::playSoundEffect(int sfxId) {
// TODO
}
} // End of namespace Illusions

View File

@@ -0,0 +1,73 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_MENUSYSTEM_BBDOU_H
#define ILLUSIONS_BBDOU_MENUSYSTEM_BBDOU_H
#include "illusions/menusystem.h"
namespace Illusions {
enum {
kBBDOUMainMenu,
kBBDOUPauseMenu,
kBBDOULoadGameMenu,
kBBDOUSaveGameMenu,
kBBDOUGameSavedMenu,
kBBDOUSaveFailedMenu,
kBBDOULoadFailedMenu,
kBBDOULastMenuIndex
};
class IllusionsEngine_BBDOU;
class BBDOUMenuSystem : public BaseMenuSystem {
public:
BBDOUMenuSystem(IllusionsEngine_BBDOU *vm);
~BBDOUMenuSystem() override;
void runMenu(MenuChoiceOffsets menuChoiceOffsets, int16 *menuChoiceOffset,
uint32 menuId, uint32 duration, uint timeOutMenuChoiceIndex, uint32 menuCallerThreadId);
public://protected:
IllusionsEngine_BBDOU *_vm;
BaseMenu *_menus[kBBDOULastMenuIndex];
void clearMenus();
void freeMenus();
BaseMenu *getMenuById(int menuId) override;
BaseMenu *createMenuById(int menuId);
BaseMenu *createMainMenu();
BaseMenu *createPauseMenu();
BaseMenu *createLoadGameMenu();
BaseMenu *createSaveGameMenu();
BaseMenu *createGameSavedMenu();
BaseMenu *createSaveFailedMenu();
BaseMenu *createLoadFailedMenu();
BaseMenu *createOptionsMenu();
int convertRootMenuId(uint32 menuId);
bool initMenuCursor() override;
int getGameState() override;
void setGameState(int gameState) override;
void setMenuCursorNum(int cursorNum) override;
void playSoundEffect(int sfxId) override;
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_MENUSYSTEM_BBDOU_H

View File

@@ -0,0 +1,992 @@
/* 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 "illusions/bbdou/illusions_bbdou.h"
#include "illusions/bbdou/scriptopcodes_bbdou.h"
#include "illusions/bbdou/bbdou_menukeys.h"
#include "illusions/bbdou/gamestate_bbdou.h"
#include "illusions/bbdou/menusystem_bbdou.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
#include "illusions/dictionary.h"
#include "illusions/input.h"
#include "illusions/resources/scriptresource.h"
#include "illusions/resources/talkresource.h"
#include "illusions/screen.h"
#include "illusions/scriptstack.h"
#include "illusions/sound.h"
#include "illusions/specialcode.h"
#include "illusions/threads/scriptthread.h"
namespace Illusions {
// ScriptOpcodes_BBDOU
ScriptOpcodes_BBDOU::ScriptOpcodes_BBDOU(IllusionsEngine_BBDOU *vm)
: ScriptOpcodes(vm), _vm(vm) {
initOpcodes();
}
ScriptOpcodes_BBDOU::~ScriptOpcodes_BBDOU() {
freeOpcodes();
}
typedef Common::Functor2Mem<ScriptThread*, OpCall&, void, ScriptOpcodes_BBDOU> ScriptOpcodeI;
#define OPCODE(op, func) \
_opcodes[op] = new ScriptOpcodeI(this, &ScriptOpcodes_BBDOU::func); \
_opcodeNames[op] = #func;
void ScriptOpcodes_BBDOU::initOpcodes() {
// First clear everything
for (uint i = 0; i < 256; ++i) {
_opcodes[i] = nullptr;
}
// Register opcodes
OPCODE(2, opSuspend);
OPCODE(3, opYield);
OPCODE(4, opTerminate);
OPCODE(5, opJump);
OPCODE(6, opStartScriptThread);
// 7 unused
OPCODE(8, opStartTempScriptThread);
OPCODE(9, opStartTimerThread);
// 10-11 unused
OPCODE(12, opNotifyThreadId);
// 13 unused
OPCODE(14, opSetThreadSceneId);
OPCODE(15, opEndTalkThreads);
OPCODE(16, opLoadResource);
OPCODE(17, opUnloadResource);
OPCODE(18, opEnterMenuPause);
OPCODE(19, opLeaveMenuPause);
OPCODE(20, opEnterScene);
OPCODE(21, opLeaveScene);
OPCODE(22, opEnterPause);
OPCODE(23, opLeavePause);
OPCODE(24, opUnloadActiveScenes);
OPCODE(25, opChangeScene);
OPCODE(26, opStartModalScene);
OPCODE(27, opExitModalScene);
// 28-29 unused
OPCODE(30, opEnterCloseUpScene);
OPCODE(31, opExitCloseUpScene);
OPCODE(32, opPanCenterObject);
// 33 unused
OPCODE(34, opPanToObject);
OPCODE(35, opPanToNamedPoint);
OPCODE(36, opPanToPoint);
OPCODE(37, opPanStop);
OPCODE(39, opSetDisplay);
OPCODE(40, opSetCameraBounds);
OPCODE(41, opSetCameraBoundsToMasterBg);
OPCODE(42, opIncBlockCounter);
OPCODE(43, opClearBlockCounter);
// 44 unused
OPCODE(45, opSetProperty);
OPCODE(46, opPlaceActor);
OPCODE(47, opFaceActor);
OPCODE(48, opFaceActorToObject);
OPCODE(49, opStartSequenceActor);
// 50 unused
OPCODE(51, opStartMoveActor);
// 52 unused
OPCODE(53, opSetActorToNamedPoint);
OPCODE(54, opSetActorPosition);
// 55 unused
OPCODE(56, opStartTalkThread);
OPCODE(57, opAppearActor);
OPCODE(58, opDisappearActor);
OPCODE(59, opIsActorVisible);
OPCODE(60, opActivateObject);
OPCODE(61, opDeactivateObject);
OPCODE(62, opSetDefaultSequence);
OPCODE(63, opSetSelectSfx);
OPCODE(64, opSetMoveSfx);
OPCODE(65, opSetDenySfx);
OPCODE(66, opSetAdjustUpSfx);
OPCODE(67, opSetAdjustDnSfx);
// 68 unused
OPCODE(69, opPause);
OPCODE(70, opResume);
OPCODE(71, opStartSound);
OPCODE(72, opStartSoundAtPosition);
OPCODE(73, opStartSoundAtActor);
OPCODE(74, opStopSound);
OPCODE(75, opStartMusic);
OPCODE(76, opStopMusic);
// 77 unused
OPCODE(78, opStackPushRandom);
OPCODE(79, opIfLte);
OPCODE(80, opAddMenuChoice);
OPCODE(81, opDisplayMenu);
OPCODE(82, opSwitchMenuChoice);
OPCODE(83, opQuitGame);
OPCODE(84, opResetGame);
OPCODE(85, opSaveGame);
OPCODE(86, opRestoreGameState);
OPCODE(87, opDeactivateButton);
OPCODE(88, opActivateButton);
OPCODE(89, opNop);
// 90 unused
OPCODE(91, opNop);
// 92-102 unused
OPCODE(103, opJumpIf);
OPCODE(104, opIsPrevSceneId);
OPCODE(105, opIsCurrentSceneId);
OPCODE(106, opIsActiveSceneId);
OPCODE(107, opNot);
OPCODE(108, opAnd);
OPCODE(109, opOr);
OPCODE(110, opGetProperty);
OPCODE(111, opCompareBlockCounter);
OPCODE(126, opDebug126);
OPCODE(127, opDebug127);
OPCODE(144, opPlayVideo);
OPCODE(146, opStackPop);
OPCODE(147, opStackDup);
OPCODE(148, opLoadSpecialCodeModule);
OPCODE(150, opRunSpecialCode);
OPCODE(152, opLinkObjectToObject);
OPCODE(153, opUnlinkObject);
OPCODE(160, opStopActor);
OPCODE(161, opSetActorUsePan);
OPCODE(168, opStartAbortableThread);
OPCODE(169, opKillThread);
OPCODE(170, opLoadGame);
OPCODE(171, opPushLoadgameResult);
OPCODE(172, opPushSavegameResult);
// 173, 174 unused
OPCODE(175, opSetSceneIdThreadId);
OPCODE(176, opStackPush0);
OPCODE(177, opSetFontId);
OPCODE(178, opAddMenuKey);
OPCODE(179, opChangeSceneAll);
}
#undef OPCODE
void ScriptOpcodes_BBDOU::freeOpcodes() {
for (uint i = 0; i < 256; ++i) {
delete _opcodes[i];
}
}
// Opcodes
void ScriptOpcodes_BBDOU::opSuspend(ScriptThread *scriptThread, OpCall &opCall) {
opCall._result = kTSSuspend;
}
void ScriptOpcodes_BBDOU::opYield(ScriptThread *scriptThread, OpCall &opCall) {
opCall._result = kTSYield;
}
void ScriptOpcodes_BBDOU::opTerminate(ScriptThread *scriptThread, OpCall &opCall) {
opCall._result = kTSTerminate;
}
void ScriptOpcodes_BBDOU::opJump(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(jumpOffs);
opCall._deltaOfs += jumpOffs;
}
void ScriptOpcodes_BBDOU::opStartScriptThread(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(threadId);
_vm->startScriptThread(threadId, opCall._threadId,
scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10);
}
void ScriptOpcodes_BBDOU::opStartTempScriptThread(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(codeOffs);
_vm->startTempScriptThread(opCall._code + codeOffs,
opCall._threadId, scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10);
}
void ScriptOpcodes_BBDOU::opStartTimerThread(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(isAbortable);
ARG_INT16(duration);
ARG_INT16(maxDuration);
if (maxDuration)
duration += _vm->getRandom(maxDuration);
//duration = 1;//DEBUG Speeds up things
if (isAbortable)
_vm->startAbortableTimerThread(duration, opCall._threadId);
else
_vm->startTimerThread(duration, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opNotifyThreadId(ScriptThread *scriptThread, OpCall &opCall) {
Thread *thread = _vm->_threads->findThread(opCall._callerThreadId);
if (!(thread->_notifyFlags & 1))
_vm->notifyThreadId(thread->_callingThreadId);
}
void ScriptOpcodes_BBDOU::opSetThreadSceneId(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
_vm->_threads->setThreadSceneId(opCall._callerThreadId, sceneId);
}
void ScriptOpcodes_BBDOU::opEndTalkThreads(ScriptThread *scriptThread, OpCall &opCall) {
_vm->_threads->endTalkThreads();
}
void ScriptOpcodes_BBDOU::opLoadResource(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(resourceId);
// NOTE Skipped checking for stalled resources
uint32 sceneId = _vm->getCurrentScene();
_vm->_resSys->loadResource(resourceId, sceneId, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opUnloadResource(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(resourceId);
// NOTE Skipped checking for stalled resources
_vm->_resSys->unloadResourceById(resourceId);
}
void ScriptOpcodes_BBDOU::opEnterMenuPause(ScriptThread *scriptThread, OpCall &opCall) {
_vm->enterMenuPause();
}
void ScriptOpcodes_BBDOU::opLeaveMenuPause(ScriptThread *scriptThread, OpCall &opCall) {
_vm->leaveMenuPause();
}
void ScriptOpcodes_BBDOU::opEnterScene(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
uint scenesCount = _vm->_activeScenes.getActiveScenesCount();
if (scenesCount > 0) {
uint32 currSceneId;
_vm->_activeScenes.getActiveSceneInfo(scenesCount, &currSceneId, nullptr);
// TODO krnfileDump(currSceneId);
}
if (!_vm->enterScene(sceneId, opCall._callerThreadId))
opCall._result = kTSTerminate;
}
void ScriptOpcodes_BBDOU::opLeaveScene(ScriptThread *scriptThread, OpCall &opCall) {
_vm->exitScene(opCall._callerThreadId);
}
void ScriptOpcodes_BBDOU::opEnterPause(ScriptThread *scriptThread, OpCall &opCall) {
_vm->enterPause(opCall._callerThreadId);
_vm->_talkItems->pauseBySceneId(_vm->getCurrentScene());
}
void ScriptOpcodes_BBDOU::opLeavePause(ScriptThread *scriptThread, OpCall &opCall) {
_vm->leavePause(opCall._callerThreadId);
}
void ScriptOpcodes_BBDOU::opUnloadActiveScenes(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
_vm->dumpActiveScenes(sceneId, opCall._callerThreadId);
}
//DEBUG Scenes
//uint32 dsceneId = 0x00010031, dthreadId = 0x00020036;//MAP
//uint32 dsceneId = 0x00010028, dthreadId = 0x000202A1;
//uint32 dsceneId = 0x00010007, dthreadId = 0x0002000C;//Auditorium
//uint32 dsceneId = 0x0001000B, dthreadId = 0x00020010;
//uint32 dsceneId = 0x00010013, dthreadId = 0x00020018;//Therapist
//uint32 dsceneId = 0x00010016, dthreadId = 0x0002001B;//Dorms ext
//uint32 dsceneId = 0x00010017, dthreadId = 0x0002001C;//Dorms int
//uint32 dsceneId = 0x0001000D, dthreadId = 0x00020012;//Food minigame
//uint32 dsceneId = 0x00010067, dthreadId = 0x0002022A;
uint32 dsceneId = 0x0001000C, dthreadId = 0x00020011;//Cafeteria
//uint32 dsceneId = 0x0001000B, dthreadId = 0x00020010;
//uint32 dsceneId = 0x0001001A, dthreadId = 0x0002001F;
//uint32 dsceneId = 0x00010047, dthreadId = 0x0002005F;
//uint32 dsceneId = 0x0001007D, dthreadId = 0x000203B9;
// uint32 dsceneId = 0x0001000D, dthreadId = 0x00020012; // Food minigame
void ScriptOpcodes_BBDOU::opChangeScene(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
ARG_UINT32(threadId);
if (dsceneId) {
//#define RUN_WALKTHROUGH
#ifdef RUN_WALKTHROUGH
_vm->_walkthroughStarted = true;
dsceneId = 0;
return;
#endif
sceneId = dsceneId;
threadId = dthreadId;
dsceneId = 0;
}
// NOTE Skipped checking for stalled resources
_vm->_input->discardAllEvents();
_vm->_prevSceneId = _vm->getCurrentScene();
_vm->exitScene(opCall._callerThreadId);
_vm->enterScene(sceneId, opCall._callerThreadId);
_vm->_gameState->writeState(sceneId, threadId);
_vm->startAnonScriptThread(threadId, 0,
scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10);
}
void ScriptOpcodes_BBDOU::opStartModalScene(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
ARG_UINT32(threadId);
// NOTE Skipped checking for stalled resources
_vm->_input->discardAllEvents();
_vm->enterPause(opCall._callerThreadId);
_vm->_talkItems->pauseBySceneId(_vm->getCurrentScene());
_vm->enterScene(sceneId, opCall._callerThreadId);
_vm->startScriptThread(threadId, 0,
scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10);
opCall._result = kTSSuspend;
}
void ScriptOpcodes_BBDOU::opExitModalScene(ScriptThread *scriptThread, OpCall &opCall) {
// NOTE Skipped checking for stalled resources
_vm->_input->discardAllEvents();
_vm->exitScene(opCall._callerThreadId);
_vm->leavePause(opCall._callerThreadId);
_vm->_talkItems->unpauseBySceneId(_vm->getCurrentScene());
}
void ScriptOpcodes_BBDOU::opEnterCloseUpScene(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
// NOTE Skipped checking for stalled resources
_vm->_input->discardAllEvents();
_vm->enterPause(opCall._callerThreadId);
_vm->enterScene(sceneId, opCall._callerThreadId);
}
void ScriptOpcodes_BBDOU::opExitCloseUpScene(ScriptThread *scriptThread, OpCall &opCall) {
_vm->exitScene(opCall._callerThreadId);
_vm->leavePause(opCall._callerThreadId);
opCall._result = kTSYield;
}
void ScriptOpcodes_BBDOU::opPanCenterObject(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(speed);
ARG_UINT32(objectId);
_vm->_camera->panCenterObject(objectId, speed);
}
void ScriptOpcodes_BBDOU::opPanToObject(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(speed);
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
Common::Point pos = control->getActorPosition();
_vm->_camera->panToPoint(pos, speed, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opPanToNamedPoint(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(speed);
ARG_UINT32(namedPointId);
Common::Point pos = _vm->getNamedPointPosition(namedPointId);
_vm->_camera->panToPoint(pos, speed, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opPanToPoint(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(speed);
ARG_INT16(x);
ARG_INT16(y);
_vm->_camera->panToPoint(Common::Point(x, y), speed, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opPanStop(ScriptThread *scriptThread, OpCall &opCall) {
_vm->_camera->stopPan();
}
void ScriptOpcodes_BBDOU::opSetDisplay(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(flag);
_vm->_screen->setDisplayOn(flag != 0);
}
void ScriptOpcodes_BBDOU::opSetCameraBounds(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_INT16(x1);
ARG_INT16(y1);
ARG_INT16(x2);
ARG_INT16(y2);
_vm->_camera->setBounds(Common::Point(x1, y1), Common::Point(x2, y2));
}
void ScriptOpcodes_BBDOU::opSetCameraBoundsToMasterBg(ScriptThread *scriptThread, OpCall &opCall) {
WidthHeight bgDimensions = _vm->_backgroundInstances->getMasterBgDimensions();
_vm->_camera->setBoundsToDimensions(bgDimensions);
}
void ScriptOpcodes_BBDOU::opIncBlockCounter(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(index);
byte value = _vm->_scriptResource->_blockCounters.get(index) + 1;
if (value <= 63)
_vm->_scriptResource->_blockCounters.set(index, value);
}
void ScriptOpcodes_BBDOU::opClearBlockCounter(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(index);
_vm->_scriptResource->_blockCounters.set(index, 0);
}
void ScriptOpcodes_BBDOU::opSetProperty(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(value);
ARG_UINT32(propertyId);
_vm->_scriptResource->_properties.set(propertyId, value != 0);
}
void ScriptOpcodes_BBDOU::opPlaceActor(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
ARG_UINT32(actorTypeId);
ARG_UINT32(sequenceId);
ARG_UINT32(namedPointId);
Common::Point pos = _vm->getNamedPointPosition(namedPointId);
_vm->_controls->placeActor(actorTypeId, pos, sequenceId, objectId, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opFaceActor(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(facing);
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
control->faceActor(facing);
}
void ScriptOpcodes_BBDOU::opFaceActorToObject(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId1);
ARG_UINT32(objectId2);
Control *control1 = _vm->_dict->getObjectControl(objectId1);
Control *control2 = _vm->_dict->getObjectControl(objectId2);
Common::Point pos1 = control1->getActorPosition();
Common::Point pos2 = control2->getActorPosition();
uint facing;
if (_vm->calcPointDirection(pos1, pos2, facing))
control1->faceActor(facing);
}
void ScriptOpcodes_BBDOU::opStartSequenceActor(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
ARG_UINT32(sequenceId);
// NOTE Skipped checking for stalled sequence, not sure if needed
Control *control = _vm->_dict->getObjectControl(objectId);
control->startSequenceActor(sequenceId, 2, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opStartMoveActor(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
ARG_UINT32(sequenceId);
ARG_UINT32(namedPointId);
// NOTE Skipped checking for stalled sequence, not sure if needed
Control *control = _vm->_dict->getObjectControl(objectId);
if (!control) { return; }// TODO CHECKME
Common::Point pos = _vm->getNamedPointPosition(namedPointId);
control->startMoveActor(sequenceId, pos, opCall._callerThreadId, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opSetActorToNamedPoint(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
ARG_UINT32(namedPointId);
Control *control = _vm->_dict->getObjectControl(objectId);
Common::Point pos = _vm->getNamedPointPosition(namedPointId);
control->stopActor();
control->setActorPosition(pos);
}
void ScriptOpcodes_BBDOU::opSetActorPosition(ScriptThread *scriptThread, OpCall &opCall) {
ARG_UINT32(objectId);
ARG_INT16(x);
ARG_INT16(y);
Control *control = _vm->_dict->getObjectControl(objectId);
Common::Point pos(x, y);
control->setActorPosition(pos);
}
void ScriptOpcodes_BBDOU::opStartTalkThread(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(duration);
ARG_UINT32(objectId);
ARG_UINT32(talkId);
ARG_UINT32(sequenceId1);
ARG_UINT32(sequenceId2);
ARG_UINT32(namedPointId);
_vm->startTalkThread(duration, objectId, talkId, sequenceId1, sequenceId2, namedPointId, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opAppearActor(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
if (!control) {
Common::Point pos = _vm->getNamedPointPosition(0x70023);
_vm->_controls->placeActor(0x50001, pos, 0x60001, objectId, 0);
control = _vm->_dict->getObjectControl(objectId);
control->startSequenceActor(0x60001, 2, 0);
}
control->appearActor();
}
void ScriptOpcodes_BBDOU::opDisappearActor(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
control->disappearActor();
}
void ScriptOpcodes_BBDOU::opIsActorVisible(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
const bool visible = control && control->isActorVisible();
_vm->_stack->push(visible ? 1 : 0);
}
void ScriptOpcodes_BBDOU::opActivateObject(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
if (control)
control->activateObject();
}
void ScriptOpcodes_BBDOU::opDeactivateObject(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
control->deactivateObject();
}
void ScriptOpcodes_BBDOU::opSetDefaultSequence(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
ARG_UINT32(defaultSequenceId);
ARG_UINT32(sequenceId);
Control *control = _vm->_dict->getObjectControl(objectId);
control->_actor->_defaultSequences.set(sequenceId, defaultSequenceId);
}
void ScriptOpcodes_BBDOU::opSetSelectSfx(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(soundEffectId);
// TODO _vm->setSelectSfx(soundEffectId);
}
void ScriptOpcodes_BBDOU::opSetMoveSfx(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(soundEffectId);
// TODO _vm->setMoveSfx(soundEffectId);
}
void ScriptOpcodes_BBDOU::opSetDenySfx(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(soundEffectId);
// TODO _vm->setDenySfx(soundEffectId);
}
void ScriptOpcodes_BBDOU::opSetAdjustUpSfx(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(soundEffectId);
// TODO _vm->setAdjustUpSfx(soundEffectId);
}
void ScriptOpcodes_BBDOU::opSetAdjustDnSfx(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(soundEffectId);
// TODO _vm->setAdjustDnSfx(soundEffectId);
}
void ScriptOpcodes_BBDOU::opPause(ScriptThread *scriptThread, OpCall &opCall) {
_vm->pause(opCall._callerThreadId);
}
void ScriptOpcodes_BBDOU::opResume(ScriptThread *scriptThread, OpCall &opCall) {
_vm->unpause(opCall._callerThreadId);
}
void ScriptOpcodes_BBDOU::opStartSound(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_INT16(volume);
ARG_INT16(pan);
ARG_UINT32(soundEffectId);
_vm->_soundMan->playSound(soundEffectId, volume, pan);
}
void ScriptOpcodes_BBDOU::opStartSoundAtPosition(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(volume);
ARG_UINT32(soundEffectId);
ARG_UINT32(namedPointId);
Common::Point pos = _vm->getNamedPointPosition(namedPointId);
int16 pan = _vm->convertPanXCoord(pos.x);
_vm->_soundMan->playSound(soundEffectId, volume, pan);
}
void ScriptOpcodes_BBDOU::opStartSoundAtActor(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(volume);
ARG_UINT32(objectId);
ARG_UINT32(soundEffectId);
Control *control = _vm->_dict->getObjectControl(objectId);
Common::Point pos = control->getActorPosition();
int16 pan = _vm->convertPanXCoord(pos.x);
_vm->_soundMan->playSound(soundEffectId, volume, pan);
}
void ScriptOpcodes_BBDOU::opStopSound(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(soundEffectId);
_vm->_soundMan->stopSound(soundEffectId);
}
void ScriptOpcodes_BBDOU::opStartMusic(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_INT16(volume);
ARG_INT16(pan);
ARG_UINT32(musicId);
ARG_UINT32(type);
_vm->_soundMan->playMusic(musicId, type, volume, pan, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opStopMusic(ScriptThread *scriptThread, OpCall &opCall) {
_vm->_soundMan->stopMusic();
}
void ScriptOpcodes_BBDOU::opStackPushRandom(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(maxValue);
_vm->_stack->push(_vm->getRandom(maxValue) + 1);
}
void ScriptOpcodes_BBDOU::opIfLte(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_INT16(rvalue);
ARG_INT16(elseJumpOffs);
int16 lvalue = _vm->_stack->pop();
if (!(lvalue <= rvalue))
opCall._deltaOfs += elseJumpOffs;
}
void ScriptOpcodes_BBDOU::opAddMenuChoice(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_INT16(jumpOffs);
ARG_INT16(endMarker);
_vm->_stack->push(endMarker);
_vm->_stack->push(jumpOffs);
}
void ScriptOpcodes_BBDOU::opDisplayMenu(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(timeoutChoiceOfs);
ARG_UINT32(menuId);
ARG_UINT32(timeOutDuration);
MenuChoiceOffsets menuChoiceOffsets;
// Load menu choices from the stack
do {
int16 choiceOffs = _vm->_stack->pop();
menuChoiceOffsets.push_back(choiceOffs);
} while (_vm->_stack->pop() == 0);
// TODO DBEUG Start menu not yet implemented, fake selection of "Start game"
if (menuId == 0x001C0001) {
_vm->_menuChoiceOfs = 88;
_vm->notifyThreadId(opCall._callerThreadId);
return;
}
// Duckman has the timeout choice offset on the stack and the index as parameter
// BBDOU instead has only the choice offset as parameter
// So we just add the timeout choice offset and use its index.
menuChoiceOffsets.push_back(timeoutChoiceOfs);
uint timeOutMenuChoiceIndex = menuChoiceOffsets.size() - 1;
_vm->_menuSystem->runMenu(menuChoiceOffsets, &_vm->_menuChoiceOfs,
menuId, timeOutDuration, timeOutMenuChoiceIndex,
opCall._callerThreadId);
}
void ScriptOpcodes_BBDOU::opSwitchMenuChoice(ScriptThread *scriptThread, OpCall &opCall) {
opCall._deltaOfs += _vm->_menuChoiceOfs;
}
void ScriptOpcodes_BBDOU::opQuitGame(ScriptThread *scriptThread, OpCall &opCall) {
_vm->quitGame();
}
void ScriptOpcodes_BBDOU::opResetGame(ScriptThread *scriptThread, OpCall &opCall) {
_vm->_threads->terminateThreads(opCall._callerThreadId);
_vm->reset();
_vm->_input->activateButton(0xFFFF);
// TODO _vm->stopMusic();
// TODO _vm->_gameStates->clear();
}
void ScriptOpcodes_BBDOU::opSaveGame(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_INT16(bankNum)
ARG_INT16(slotNum)
_vm->saveSavegameFromScript(slotNum, opCall._callerThreadId);
}
void ScriptOpcodes_BBDOU::opRestoreGameState(ScriptThread *scriptThread, OpCall &opCall) {
_vm->activateSavegame(opCall._callerThreadId);
}
void ScriptOpcodes_BBDOU::opDeactivateButton(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(button)
_vm->_input->deactivateButton(button);
}
void ScriptOpcodes_BBDOU::opActivateButton(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(button)
_vm->_input->activateButton(button);
}
void ScriptOpcodes_BBDOU::opNop(ScriptThread *scriptThread, OpCall &opCall) {
// Opcode empty but still called
}
void ScriptOpcodes_BBDOU::opJumpIf(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(jumpOffs);
int16 value = _vm->_stack->pop();
if (value == 0)
opCall._deltaOfs += jumpOffs;
}
void ScriptOpcodes_BBDOU::opIsPrevSceneId(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
_vm->_stack->push(_vm->_prevSceneId == sceneId ? 1 : 0);
}
void ScriptOpcodes_BBDOU::opIsCurrentSceneId(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
_vm->_stack->push(_vm->getCurrentScene() == sceneId ? 1 : 0);
}
void ScriptOpcodes_BBDOU::opIsActiveSceneId(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
_vm->_stack->push(_vm->_activeScenes.isSceneActive(sceneId) ? 1 : 0);
}
void ScriptOpcodes_BBDOU::opNot(ScriptThread *scriptThread, OpCall &opCall) {
int16 value = _vm->_stack->pop();
_vm->_stack->push(value != 0 ? 0 : 1);
}
void ScriptOpcodes_BBDOU::opAnd(ScriptThread *scriptThread, OpCall &opCall) {
int16 value1 = _vm->_stack->pop();
int16 value2 = _vm->_stack->pop();
_vm->_stack->push(value1 & value2);
}
void ScriptOpcodes_BBDOU::opOr(ScriptThread *scriptThread, OpCall &opCall) {
int16 value1 = _vm->_stack->pop();
int16 value2 = _vm->_stack->pop();
_vm->_stack->push(value1 | value2);
}
void ScriptOpcodes_BBDOU::opGetProperty(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(propertyId)
bool value = _vm->_scriptResource->_properties.get(propertyId);
_vm->_stack->push(value ? 1 : 0);
}
void ScriptOpcodes_BBDOU::opCompareBlockCounter(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(index);
ARG_INT16(compareOp);
ARG_INT16(rvalue);
int16 lvalue = _vm->_scriptResource->_blockCounters.get(index);
bool compareResult = false;
switch (compareOp) {
case 1:
compareResult = lvalue == rvalue;
break;
case 2:
compareResult = lvalue != rvalue;
break;
case 3:
compareResult = lvalue < rvalue;
break;
case 4:
compareResult = lvalue > rvalue;
break;
case 5:
compareResult = lvalue >= rvalue;
break;
case 6:
compareResult = lvalue <= rvalue;
break;
default:
break;
}
_vm->_stack->push(compareResult ? 1 : 0);
}
void ScriptOpcodes_BBDOU::opDebug126(ScriptThread *scriptThread, OpCall &opCall) {
// NOTE Prints some debug text
debug(1, "[DBG126] %s", (char*)opCall._code);
}
void ScriptOpcodes_BBDOU::opDebug127(ScriptThread *scriptThread, OpCall &opCall) {
// NOTE Prints some debug text
debug(1, "[DBG127] %s", (char*)opCall._code);
}
void ScriptOpcodes_BBDOU::opPlayVideo(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
ARG_UINT32(videoId);
ARG_UINT32(priority);
#if 0 // TODO DEBUG Set to 0 to skip videos
_vm->playVideo(videoId, objectId, priority, opCall._threadId);
#else
//DEBUG Resume calling thread, later done by the video player
_vm->notifyThreadId(opCall._callerThreadId);
#endif
}
void ScriptOpcodes_BBDOU::opStackPop(ScriptThread *scriptThread, OpCall &opCall) {
_vm->_stack->pop();
}
void ScriptOpcodes_BBDOU::opStackDup(ScriptThread *scriptThread, OpCall &opCall) {
int16 value = _vm->_stack->peek();
_vm->_stack->push(value);
}
void ScriptOpcodes_BBDOU::opLoadSpecialCodeModule(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(specialCodeModuleId);
_vm->_resSys->loadResource(specialCodeModuleId, 0, 0);
}
void ScriptOpcodes_BBDOU::opRunSpecialCode(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(specialCodeId);
_vm->_specialCode->run(specialCodeId, opCall);
}
void ScriptOpcodes_BBDOU::opLinkObjectToObject(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
ARG_UINT32(parentObjectId);
ARG_UINT32(linkedObjectValue);
Control *control = _vm->_dict->getObjectControl(objectId);
control->linkToObject(parentObjectId, linkedObjectValue);
}
void ScriptOpcodes_BBDOU::opUnlinkObject(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
control->unlinkObject();
}
void ScriptOpcodes_BBDOU::opStopActor(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
control->stopActor();
}
void ScriptOpcodes_BBDOU::opSetActorUsePan(ScriptThread *scriptThread, OpCall &opCall) {
ARG_INT16(usePan)
ARG_UINT32(objectId);
Control *control = _vm->_dict->getObjectControl(objectId);
control->setActorUsePan(usePan);
}
void ScriptOpcodes_BBDOU::opStartAbortableThread(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_INT16(codeOffs);
ARG_INT16(skipOffs);
_vm->startAbortableThread(opCall._code + codeOffs,
opCall._code + skipOffs, opCall._threadId);
}
void ScriptOpcodes_BBDOU::opKillThread(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(threadId);
_vm->_threads->killThread(threadId);
}
void ScriptOpcodes_BBDOU::opLoadGame(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_INT16(bankNum)
ARG_INT16(slotNum)
_vm->loadSavegameFromScript(slotNum, opCall._callerThreadId);
}
void ScriptOpcodes_BBDOU::opPushLoadgameResult(ScriptThread *scriptThread, OpCall &opCall) {
_vm->_stack->push(_vm->_loadGameResult ? 1 : 0);
}
void ScriptOpcodes_BBDOU::opPushSavegameResult(ScriptThread *scriptThread, OpCall &opCall) {
_vm->_stack->push(_vm->_saveGameResult ? 1 : 0);
}
void ScriptOpcodes_BBDOU::opSetSceneIdThreadId(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
ARG_UINT32(threadId);
_vm->setSceneIdThreadId(sceneId, threadId);
}
void ScriptOpcodes_BBDOU::opStackPush0(ScriptThread *scriptThread, OpCall &opCall) {
_vm->_stack->push(0);
}
void ScriptOpcodes_BBDOU::opSetFontId(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(fontId);
_vm->setCurrFontId(fontId);
}
void ScriptOpcodes_BBDOU::opAddMenuKey(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(key);
ARG_UINT32(threadId);
_vm->_menuKeys->addMenuKey(key, threadId);
}
void ScriptOpcodes_BBDOU::opChangeSceneAll(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
ARG_UINT32(sceneId);
ARG_UINT32(threadId);
// NOTE Skipped checking for stalled resources
_vm->_input->discardAllEvents();
_vm->_prevSceneId = _vm->getCurrentScene();
_vm->dumpActiveScenes(_vm->_globalSceneId, opCall._callerThreadId);
_vm->enterScene(sceneId, opCall._callerThreadId);
_vm->_gameState->writeState(sceneId, threadId);
_vm->startAnonScriptThread(threadId, 0,
scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10);
}
} // End of namespace Illusions

View File

@@ -0,0 +1,152 @@
/* 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/>.
*
*/
#ifndef ILLUSIONS_BBDOU_SCRIPTOPCODES_BBDOU_H
#define ILLUSIONS_BBDOU_SCRIPTOPCODES_BBDOU_H
#include "illusions/scriptopcodes.h"
#include "common/func.h"
namespace Illusions {
class IllusionsEngine_BBDOU;
class ScriptThread;
class ScriptOpcodes_BBDOU : public ScriptOpcodes {
public:
ScriptOpcodes_BBDOU(IllusionsEngine_BBDOU *vm);
~ScriptOpcodes_BBDOU() override;
void initOpcodes() override;
void freeOpcodes() override;
protected:
IllusionsEngine_BBDOU *_vm;
// Opcodes
void opSuspend(ScriptThread *scriptThread, OpCall &opCall);
void opYield(ScriptThread *scriptThread, OpCall &opCall);
void opTerminate(ScriptThread *scriptThread, OpCall &opCall);
void opJump(ScriptThread *scriptThread, OpCall &opCall);
void opStartScriptThread(ScriptThread *scriptThread, OpCall &opCall);
void opStartTempScriptThread(ScriptThread *scriptThread, OpCall &opCall);
void opStartTimerThread(ScriptThread *scriptThread, OpCall &opCall);
void opNotifyThreadId(ScriptThread *scriptThread, OpCall &opCall);
void opSetThreadSceneId(ScriptThread *scriptThread, OpCall &opCall);
void opEndTalkThreads(ScriptThread *scriptThread, OpCall &opCall);
void opLoadResource(ScriptThread *scriptThread, OpCall &opCall);
void opUnloadResource(ScriptThread *scriptThread, OpCall &opCall);
void opEnterMenuPause(ScriptThread *scriptThread, OpCall &opCall);
void opLeaveMenuPause(ScriptThread *scriptThread, OpCall &opCall);
void opEnterScene(ScriptThread *scriptThread, OpCall &opCall);
void opLeaveScene(ScriptThread *scriptThread, OpCall &opCall);
void opEnterPause(ScriptThread *scriptThread, OpCall &opCall);
void opLeavePause(ScriptThread *scriptThread, OpCall &opCall);
void opUnloadActiveScenes(ScriptThread *scriptThread, OpCall &opCall);
void opChangeScene(ScriptThread *scriptThread, OpCall &opCall);
void opStartModalScene(ScriptThread *scriptThread, OpCall &opCall);
void opExitModalScene(ScriptThread *scriptThread, OpCall &opCall);
void opEnterCloseUpScene(ScriptThread *scriptThread, OpCall &opCall);
void opExitCloseUpScene(ScriptThread *scriptThread, OpCall &opCall);
void opPanCenterObject(ScriptThread *scriptThread, OpCall &opCall);
void opPanToObject(ScriptThread *scriptThread, OpCall &opCall);
void opPanToNamedPoint(ScriptThread *scriptThread, OpCall &opCall);
void opPanToPoint(ScriptThread *scriptThread, OpCall &opCall);
void opPanStop(ScriptThread *scriptThread, OpCall &opCall);
void opSetDisplay(ScriptThread *scriptThread, OpCall &opCall);
void opSetCameraBounds(ScriptThread *scriptThread, OpCall &opCall);
void opSetCameraBoundsToMasterBg(ScriptThread *scriptThread, OpCall &opCall);
void opIncBlockCounter(ScriptThread *scriptThread, OpCall &opCall);
void opClearBlockCounter(ScriptThread *scriptThread, OpCall &opCall);
void opSetProperty(ScriptThread *scriptThread, OpCall &opCall);
void opPlaceActor(ScriptThread *scriptThread, OpCall &opCall);
void opFaceActor(ScriptThread *scriptThread, OpCall &opCall);
void opFaceActorToObject(ScriptThread *scriptThread, OpCall &opCall);
void opStartSequenceActor(ScriptThread *scriptThread, OpCall &opCall);
void opStartMoveActor(ScriptThread *scriptThread, OpCall &opCall);
void opSetActorToNamedPoint(ScriptThread *scriptThread, OpCall &opCall);
void opSetActorPosition(ScriptThread *scriptThread, OpCall &opCall);
void opStartTalkThread(ScriptThread *scriptThread, OpCall &opCall);
void opAppearActor(ScriptThread *scriptThread, OpCall &opCall);
void opDisappearActor(ScriptThread *scriptThread, OpCall &opCall);
void opIsActorVisible(ScriptThread *scriptThread, OpCall &opCall);
void opActivateObject(ScriptThread *scriptThread, OpCall &opCall);
void opDeactivateObject(ScriptThread *scriptThread, OpCall &opCall);
void opSetDefaultSequence(ScriptThread *scriptThread, OpCall &opCall);
void opSetSelectSfx(ScriptThread *scriptThread, OpCall &opCall);
void opSetMoveSfx(ScriptThread *scriptThread, OpCall &opCall);
void opSetDenySfx(ScriptThread *scriptThread, OpCall &opCall);
void opSetAdjustUpSfx(ScriptThread *scriptThread, OpCall &opCall);
void opSetAdjustDnSfx(ScriptThread *scriptThread, OpCall &opCall);
void opPause(ScriptThread *scriptThread, OpCall &opCall);
void opResume(ScriptThread *scriptThread, OpCall &opCall);
void opStartSound(ScriptThread *scriptThread, OpCall &opCall);
void opStartSoundAtPosition(ScriptThread *scriptThread, OpCall &opCall);
void opStartSoundAtActor(ScriptThread *scriptThread, OpCall &opCall);
void opStopSound(ScriptThread *scriptThread, OpCall &opCall);
void opStartMusic(ScriptThread *scriptThread, OpCall &opCall);
void opStopMusic(ScriptThread *scriptThread, OpCall &opCall);
void opStackPushRandom(ScriptThread *scriptThread, OpCall &opCall);
void opIfLte(ScriptThread *scriptThread, OpCall &opCall);
void opAddMenuChoice(ScriptThread *scriptThread, OpCall &opCall);
void opDisplayMenu(ScriptThread *scriptThread, OpCall &opCall);
void opSwitchMenuChoice(ScriptThread *scriptThread, OpCall &opCall);
void opQuitGame(ScriptThread *scriptThread, OpCall &opCall);
void opResetGame(ScriptThread *scriptThread, OpCall &opCall);
void opSaveGame(ScriptThread *scriptThread, OpCall &opCall);
void opRestoreGameState(ScriptThread *scriptThread, OpCall &opCall);
void opDeactivateButton(ScriptThread *scriptThread, OpCall &opCall);
void opActivateButton(ScriptThread *scriptThread, OpCall &opCall);
void opNop(ScriptThread *scriptThread, OpCall &opCall);
void opJumpIf(ScriptThread *scriptThread, OpCall &opCall);
void opIsPrevSceneId(ScriptThread *scriptThread, OpCall &opCall);
void opIsCurrentSceneId(ScriptThread *scriptThread, OpCall &opCall);
void opIsActiveSceneId(ScriptThread *scriptThread, OpCall &opCall);
void opNot(ScriptThread *scriptThread, OpCall &opCall);
void opAnd(ScriptThread *scriptThread, OpCall &opCall);
void opOr(ScriptThread *scriptThread, OpCall &opCall);
void opGetProperty(ScriptThread *scriptThread, OpCall &opCall);
void opCompareBlockCounter(ScriptThread *scriptThread, OpCall &opCall);
void opDebug126(ScriptThread *scriptThread, OpCall &opCall);
void opDebug127(ScriptThread *scriptThread, OpCall &opCall);
void opPlayVideo(ScriptThread *scriptThread, OpCall &opCall);
void opStackPop(ScriptThread *scriptThread, OpCall &opCall);
void opStackDup(ScriptThread *scriptThread, OpCall &opCall);
void opLoadSpecialCodeModule(ScriptThread *scriptThread, OpCall &opCall);
void opRunSpecialCode(ScriptThread *scriptThread, OpCall &opCall);
void opLinkObjectToObject(ScriptThread *scriptThread, OpCall &opCall);
void opUnlinkObject(ScriptThread *scriptThread, OpCall &opCall);
void opStopActor(ScriptThread *scriptThread, OpCall &opCall);
void opSetActorUsePan(ScriptThread *scriptThread, OpCall &opCall);
void opStartAbortableThread(ScriptThread *scriptThread, OpCall &opCall);
void opKillThread(ScriptThread *scriptThread, OpCall &opCall);
void opLoadGame(ScriptThread *scriptThread, OpCall &opCall);
void opPushLoadgameResult(ScriptThread *scriptThread, OpCall &opCall);
void opPushSavegameResult(ScriptThread *scriptThread, OpCall &opCall);
void opSetSceneIdThreadId(ScriptThread *scriptThread, OpCall &opCall);
void opStackPush0(ScriptThread *scriptThread, OpCall &opCall);
void opSetFontId(ScriptThread *scriptThread, OpCall &opCall);
void opAddMenuKey(ScriptThread *scriptThread, OpCall &opCall);
void opChangeSceneAll(ScriptThread *scriptThread, OpCall &opCall);
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_SCRIPTOPCODES_BBDOU_H