ILLUSIONS: More work on BBDOU specific code (cursor, bubble)

- Add input handling code
This commit is contained in:
johndoe123 2014-03-25 19:57:21 +01:00 committed by Eugene Sandulenko
parent 28cb39eb2b
commit e05a789975
13 changed files with 1011 additions and 38 deletions

View File

@ -95,7 +95,7 @@ Actor::Actor(IllusionsEngine *vm)
_pathCtrY = 0;
_controlRoutine = 0;
setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, Controls>(_vm->_controls, &Controls::actorControlRouine));
setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, Controls>(_vm->_controls, &Controls::actorControlRoutine));
#if 0 // TODO
_field2 = 0;
@ -283,7 +283,7 @@ void Control::activateObject() {
}
void Control::deactivateObject() {
_flags |= ~1;
_flags &= ~1;
if (_actor) {
for (uint i = 0; i < kSubObjectsCount; ++i)
if (_actor->_subobjects[i]) {
@ -377,11 +377,11 @@ int Control::getPriority() {
int16 positionY, priority, priority1;
if (_actor) {
if (_actor->_parentObjectId && (_actor->_flags & 0x40)) {
uint32 objectId2 = getSubActorParent();
Control *control2 = _vm->_dict->getObjectControl(objectId2);
objectId = control2->_objectId;
priority = control2->_priority;
positionY = control2->_actor->_position.y;
uint32 parentObjectId = getSubActorParent();
Control *parentControl = _vm->_dict->getObjectControl(parentObjectId);
objectId = parentControl->_objectId;
priority = parentControl->_priority;
positionY = parentControl->_actor->_position.y;
priority1 = _priority;
} else {
objectId = _objectId;
@ -475,6 +475,24 @@ void Control::getCollisionRectAccurate(Common::Rect &collisionRect) {
}
void Control::getCollisionRect(Common::Rect &collisionRect) {
collisionRect = Common::Rect(_unkPt.x, _unkPt.y, _pt.x, _pt.y);
if (_actor) {
if (_actor->_scale != 100) {
// scaledValue = value * scale div 100
collisionRect.left = collisionRect.left * _actor->_scale / 100;
collisionRect.top = collisionRect.top * _actor->_scale / 100;
collisionRect.right = collisionRect.right * _actor->_scale / 100;
collisionRect.bottom = collisionRect.bottom * _actor->_scale / 100;
}
collisionRect.translate(_actor->_position.x, _actor->_position.y);
}
if (_flags & 8) {
Common::Point screenOffs = _vm->_camera->getScreenOffset();
collisionRect.translate(screenOffs.x, screenOffs.y);
}
}
void Control::setActorUsePan(int usePan) {
if (usePan == 1)
_flags &= ~8;
@ -602,6 +620,14 @@ void Control::sequenceActor() {
}
void Control::setActorIndexTo1() {
_actor->_actorIndex = 1;
}
void Control::setActorIndexTo2() {
_actor->_actorIndex = 2;
}
void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entryTblPtr, uint32 notifyThreadId) {
stopActor();
@ -618,10 +644,18 @@ void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entry
_actor->_path40 = 0;
Sequence *sequence = _vm->_dict->findSequence(sequenceId);
//debug("sequence: %p", (void*)sequence);
_actor->_seqCodeIp = sequence->_sequenceCode;
_actor->_frames = _vm->_actorItems->findSequenceFrames(sequence);
/*
for (int i = 0; i < 64; ++i) {
debugN("%02X ", sequence->_sequenceCode[i]);
}
debug(".");
*/
_actor->_seqCodeValue3 = 0;
_actor->_seqCodeValue1 = 0;
_actor->_seqCodeValue2 = value == 1 ? 350 : 600;
@ -815,7 +849,48 @@ void Controls::unpauseControlsByTag(uint32 tag) {
}
}
void Controls::actorControlRouine(Control *control, uint32 deltaTime) {
bool Controls::getOverlappedObject(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority) {
Control *foundControl = 0;
int foundPriority = 0;
// TODO minPriority = artcntrlGetPriorityFromBase(minPriority);
for (ItemsIterator it = _controls.begin(); it != _controls.end(); ++it) {
Control *testControl = *it;
if (testControl != control && testControl->_pauseCtr == 0 &&
(testControl->_flags & 1) && !(testControl->_flags & 0x10) &&
(!testControl->_actor || (testControl->_actor->_flags & 1))) {
Common::Rect collisionRect;
testControl->getCollisionRect(collisionRect);
debug("collisionRect(%d, %d, %d, %d)", collisionRect.left, collisionRect.top, collisionRect.right, collisionRect.bottom);
debug("pt(%d, %d)", pt.x, pt.y);
if (!collisionRect.isEmpty() && collisionRect.contains(pt)) {
int testPriority = testControl->getPriority();
debug("testPriority: %d; minPriority: %d", testPriority, minPriority);
if ((!foundControl || foundPriority < testPriority) &&
testPriority >= minPriority) {
debug("overlapped() %08X; pauseCtr: %d; flags: %04X",
testControl->_objectId, testControl->_pauseCtr, testControl->_flags);
foundControl = testControl;
foundPriority = testPriority;
}
}
}
}
debug("OVERLAPPED DONE\n");
if (foundControl) {
if (foundControl->_actor && foundControl->_actor->_parentObjectId && (foundControl->_actor->_flags & 0x40)) {
uint32 parentObjectId = foundControl->getSubActorParent();
foundControl = _vm->_dict->getObjectControl(parentObjectId);
}
*outOverlappedControl = foundControl;
}
return foundControl != 0;
}
void Controls::actorControlRoutine(Control *control, uint32 deltaTime) {
Actor *actor = control->_actor;

View File

@ -134,7 +134,6 @@ public:
int _pathCtrY;
int _path40;
};
class Control {
@ -162,6 +161,7 @@ public:
Common::Point calcPosition(Common::Point posDelta);
uint32 getSubActorParent();
void getCollisionRectAccurate(Common::Rect &collisionRect);
void getCollisionRect(Common::Rect &collisionRect);
void setActorUsePan(int usePan);
void setActorFrameIndex(int16 frameIndex);
void stopActor();
@ -169,6 +169,8 @@ public:
void stopSequenceActor();
void startTalkActor(uint32 sequenceId, byte *entryTblPtr, uint32 threadId);
void sequenceActor();
void setActorIndexTo1();
void setActorIndexTo2();
public:
IllusionsEngine *_vm;
uint _flags;
@ -201,7 +203,8 @@ public:
void destroyControlsByTag(uint32 tag);
void pauseControlsByTag(uint32 tag);
void unpauseControlsByTag(uint32 tag);
void actorControlRouine(Control *control, uint32 deltaTime);
bool getOverlappedObject(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority);
void actorControlRoutine(Control *control, uint32 deltaTime);
public:
typedef Common::List<Control*> Items;
typedef Items::iterator ItemsIterator;

View File

@ -0,0 +1,150 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "illusions/illusions.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 *vm, BbdouSpecialCode *bbdou)
: _vm(vm), _bbdou(bbdou) {
}
BbdouBubble::~BbdouBubble() {
}
void BbdouBubble::init() {
static const uint32 kObjectIds3[] = {
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 kObjectIds2[] = {
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
};
_field1414 = 0x4005B;
_field1418 = 0x4005C;
for (uint i = 0; i < 32; ++i)
_objectIds[i] = kObjectIds3[i];
for (uint i = 0; i < 32; ++i) {
_items[i]._objectId = kObjectIds2[i];
_items[i]._enabled = 0;
_items[i]._position.x = 0;
_items[i]._position.y = 0;
_items[i]._sequenceId = 0;
}
_currItem0 = 0;
_prevItem0 = 0;
_someItem0 = 0;
_pt1.x = 0;
_pt1.y = 0;
_pt2.x = 0;
_pt2.y = 0;
}
void BbdouBubble::addItem0(uint32 sequenceId1, uint32 sequenceId2, uint32 progResKeywordId,
uint32 namedPointId, int16 count, uint32 *namedPointIds) {
Item0 item0;
item0._sequenceId1 = sequenceId1;
item0._sequenceId2 = sequenceId2;
item0._progResKeywordId = progResKeywordId;
item0._baseNamedPointId = namedPointId;
item0._count = count;
for (int16 i = 0; i < count; ++i)
item0._namedPointIds[i] = FROM_LE_32(namedPointIds[i]);
item0._objectId = 0;
item0._pt.x = 0;
item0._pt.y = 0;
_item0s.push_back(item0);
}
void BbdouBubble::show() {
if (_prevItem0) {
hide();
}
_prevItem0 = _currItem0;
_currItem0 = 0;
// TODO calcBubbles(_pt1, _pt2);
Control *control = _vm->_dict->getObjectControl(_prevItem0->_objectId);
control->setActorPosition(_pt2);
control->startSequenceActor(0x60057, 2, 0);
control->startSequenceActor(_prevItem0->_sequenceId1, 2, 0);
control->appearActor();
control->deactivateObject();
for (uint i = 0; i < 32; ++i) {
if (_items[i]._enabled == 1) {
Control *subControl = _vm->_dict->getObjectControl(_items[i]._objectId);
subControl->setActorPosition(_items[i]._position);
subControl->startSequenceActor(_items[i]._sequenceId, 2, 0);
}
}
}
void BbdouBubble::hide() {
_someItem0 = _prevItem0;
_prevItem0 = 0;
if (_someItem0) {
Control *control = _vm->_dict->getObjectControl(_someItem0->_objectId);
control->startSequenceActor(_someItem0->_sequenceId2, 2, 0);
for (uint i = 0; i < 32; ++i) {
Control *subControl = _vm->_dict->getObjectControl(_objectIds[i]);
subControl->stopActor();
subControl->disappearActor();
}
for (uint i = 0; i < 32; ++i) {
Control *subControl = _vm->_dict->getObjectControl(_items[i]._objectId);
subControl->stopActor();
subControl->disappearActor();
}
}
}
} // End of namespace Illusions

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 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef ILLUSIONS_BBDOU_BBDOU_BUBBLE_H
#define ILLUSIONS_BBDOU_BBDOU_BUBBLE_H
#include "illusions/specialcode.h"
#include "common/rect.h"
namespace Illusions {
class IllusionsEngine;
class BbdouSpecialCode;
class Control;
struct Item0 {
uint32 _sequenceId1;
uint32 _sequenceId2;
int16 _count;
uint32 _progResKeywordId;
uint32 _baseNamedPointId;
uint32 _namedPointIds[32];
uint32 _objectId;
Common::Point _pt;
Item0() : _count(0) {}
};
struct Item141C {
uint32 _objectId;
int16 _enabled;
Common::Point _position;
int16 _fieldA;
uint32 _sequenceId;
};
class BbdouBubble {
public:
BbdouBubble(IllusionsEngine *vm, BbdouSpecialCode *bbdou);
~BbdouBubble();
void init();
void addItem0(uint32 sequenceId1, uint32 sequenceId2, uint32 progResKeywordId,
uint32 namedPointId, int16 count, uint32 *namedPointIds);
void show();
void hide();
protected:
IllusionsEngine *_vm;
BbdouSpecialCode *_bbdou;
Common::Array<Item0> _item0s;
Item0 *_currItem0;
Item0 *_prevItem0;
Item0 *_someItem0;
uint32 _objectIds[32];
Common::Point _pt1;
Common::Point _pt2;
int _field1414;
int _field1418;
Item141C _items[32];
};
} // End of namespace Illusions
#endif // ILLUSIONS_BBDOU_BBDOU_BUBBLE_H

View File

@ -23,17 +23,178 @@
#include "illusions/illusions.h"
#include "illusions/bbdou/bbdou_cursor.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
#include "illusions/dictionary.h"
#include "illusions/input.h"
namespace Illusions {
BbdouCursor::BbdouCursor(IllusionsEngine *vm)
: _vm(vm) {
// 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(IllusionsEngine *vm, BbdouSpecialCode *bbdou)
: _vm(vm), _bbdou(bbdou) {
}
BbdouCursor::~BbdouCursor() {
}
void BbdouCursor::init() {
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->_actor->setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, BbdouCursor>(this, &BbdouCursor::actorControlRoutine1));
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._item10._field58 = 1;
_data._sequenceId98 = 0;
_data._idleCtr = 0;
_data._item10._verbId = 0x1B0000;
_data._item10._field0 = 1;
_data._item10._playSound48 = 0;
_data._item10._objectIds[0] = 0;
_data._item10._objectIds[1] = 0;
_data._item10._index = 0;
_data._item10._flag56 = 0;
clearCursorDataField14();
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->discardButtons(0xFFFF);
}
void BbdouCursor::disable(uint32 objectId) {
hide(objectId);
}
void BbdouCursor::addCursorSequence(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;
}
int BbdouCursor::findStruct8bsValue(uint32 objectId) {
for (uint i = 0; i < kMaxCursorSequences; ++i)
if (_cursorStruct8bs[i]._objectId == objectId)
return _cursorStruct8bs[i]._value;
return 11;
}
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::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._sequenceId98 = 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;
}
}
void BbdouCursor::clearCursorDataField14() {
for (uint i = 0; i < 32; ++i)
_data._item10._verbActive[i] = 0;
if (_data._item10._field0 == 1) {
_data._item10._verbActive[1] = 1;
_data._item10._verbActive[2] = 1;
_data._item10._verbActive[3] = 1;
_data._item10._verbActive[5] = 1;
} else if (_data._item10._field0 == 3) {
_data._item10._verbActive[1] = 1;
_data._item10._verbActive[2] = 1;
}
}
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);
// TODO item10_sub_10005040(objectId, &cursorData->item10);
_vm->_camera->popCameraMode();
}
_vm->_input->discardButtons(0xFFFF);
}
} // End of namespace Illusions

View File

@ -28,14 +28,85 @@
namespace Illusions {
class IllusionsEngine;
class BbdouSpecialCode;
class Control;
struct Item10;
struct Item10 {
int _field0;
int16 _verbActive[32];
uint32 _verbId;
int16 _playSound48;
//field_4A dw
uint32 _objectIds[2];
int16 _index;
int16 _flag56;
int _field58;
};
struct CursorData {
int _mode;
int _mode2;
uint32 _verbId1;
uint32 _progResKeywordId;
Item10 _item10;
uint32 _currOverlappedObjectId;
uint32 _overlappedObjectId;
uint32 _sequenceId;
uint32 _sequenceId2;
uint32 _holdingObjectId;
uint32 _holdingObjectId2;
int _visibleCtr;
//field_86 dw
uint32 _causeThreadId1;
uint32 _causeThreadId2;
int16 _field90;
//field_92 dw
uint _flags;
uint32 _sequenceId98;
int16 _idleCtr;
//field_9E db
//field_9F db
};
struct CursorSequence {
uint32 _objectId;
uint32 _sequenceId;
CursorSequence() : _objectId(0), _sequenceId(0) {}
};
struct Struct8b {
uint32 _objectId;
int _value;
Struct8b() : _objectId(0), _value(0) {}
};
const uint kMaxCursorSequences = 100;
class BbdouCursor {
public:
BbdouCursor(IllusionsEngine *vm);
BbdouCursor(IllusionsEngine *vm, BbdouSpecialCode *bbdou);
~BbdouCursor();
void init();
protected:
void init(uint32 objectId, uint32 progResKeywordId);
void enable(uint32 objectId);
void disable(uint32 objectId);
void addCursorSequence(uint32 objectId, uint32 sequenceId);
uint32 findCursorSequenceId(uint32 objectId);
int findStruct8bsValue(uint32 objectId);
void saveInfo();
void restoreInfo();
void restoreAfterTrackingCursor();
uint32 getSequenceId1(int sequenceIndex);
public:
IllusionsEngine *_vm;
BbdouSpecialCode *_bbdou;
Control *_control;
CursorData _data;
CursorSequence _cursorSequences[kMaxCursorSequences];
Struct8b _cursorStruct8bs[512];
void clearCursorDataField14();
void show(Control *control);
void hide(uint32 objectId);
};
} // End of namespace Illusions

View File

@ -22,7 +22,13 @@
#include "illusions/illusions.h"
#include "illusions/bbdou/bbdou_specialcode.h"
#include "illusions/bbdou/bbdou_bubble.h"
#include "illusions/bbdou/bbdou_cursor.h"
#include "illusions/actor.h"
#include "illusions/camera.h"
#include "illusions/dictionary.h"
#include "illusions/input.h"
#include "illusions/scriptman.h"
#include "illusions/scriptopcodes.h"
namespace Illusions {
@ -31,15 +37,313 @@ namespace Illusions {
BbdouSpecialCode::BbdouSpecialCode(IllusionsEngine *vm)
: SpecialCode(vm) {
_bubble = new BbdouBubble(_vm, this);
_cursor = new BbdouCursor(_vm, this);
}
BbdouSpecialCode::~BbdouSpecialCode() {
delete _cursor;
delete _bubble;
}
typedef Common::Functor1Mem<OpCall&, void, BbdouSpecialCode> SpecialCodeFunctionI;
#define SPECIAL(id, func) _map[id] = new SpecialCodeFunctionI(this, &BbdouSpecialCode::func);
void BbdouSpecialCode::init() {
// TODO
SPECIAL(0x00160006, spcInitCursor);
SPECIAL(0x00160008, spcEnableCursor);
SPECIAL(0x00160009, spcDisableCursor);
SPECIAL(0x0016000A, spcAddCursorSequence);
SPECIAL(0x00160013, spcInitBubble);
SPECIAL(0x00160014, spcSetupBubble);
SPECIAL(0x00160015, spcSetObjectInteractMode);
}
void BbdouSpecialCode::run(uint32 specialCodeId, OpCall &opCall) {
MapIterator it = _map.find(specialCodeId);
if (it != _map.end()) {
(*(*it)._value)(opCall);
} else {
debug("BbdouSpecialCode::run() Unimplemented special code %08X", specialCodeId);
_vm->notifyThreadId(opCall._callerThreadId);
}
}
// Special codes
// Convenience macros
#define ARG_SKIP(x) opCall.skip(x);
#define ARG_INT16(name) int16 name = opCall.readSint16(); debug("ARG_INT16(" #name " = %d)", name);
#define ARG_UINT32(name) uint32 name = opCall.readUint32(); debug("ARG_UINT32(" #name " = %08X)", name);
void BbdouSpecialCode::spcInitCursor(OpCall &opCall) {
ARG_UINT32(objectId);
ARG_UINT32(progResKeywordId);
_cursor->init(objectId, progResKeywordId);
setCursorControlRoutine(objectId, 0);
_vm->notifyThreadId(opCall._callerThreadId);
}
void BbdouSpecialCode::spcEnableCursor(OpCall &opCall) {
ARG_UINT32(objectId);
_cursor->enable(objectId);
_vm->notifyThreadId(opCall._callerThreadId);
}
void BbdouSpecialCode::spcDisableCursor(OpCall &opCall) {
ARG_UINT32(objectId);
_cursor->disable(objectId);
_vm->notifyThreadId(opCall._callerThreadId);
}
void BbdouSpecialCode::spcAddCursorSequence(OpCall &opCall) {
ARG_SKIP(4);
ARG_UINT32(objectId);
ARG_UINT32(sequenceId);
_cursor->addCursorSequence(objectId, sequenceId);
_vm->notifyThreadId(opCall._callerThreadId);
}
void BbdouSpecialCode::spcInitBubble(OpCall &opCall) {
_bubble->init();
_vm->notifyThreadId(opCall._callerThreadId);
}
void BbdouSpecialCode::spcSetupBubble(OpCall &opCall) {
ARG_UINT32(sequenceId1);
ARG_UINT32(sequenceId2);
ARG_UINT32(progResKeywordId);
ARG_UINT32(namedPointId);
ARG_INT16(count);
_bubble->addItem0(sequenceId1, sequenceId2, progResKeywordId, namedPointId,
count, (uint32*)opCall._code);
_vm->notifyThreadId(opCall._callerThreadId);
}
void BbdouSpecialCode::spcSetObjectInteractMode(OpCall &opCall) {
ARG_SKIP(4);
ARG_UINT32(objectId);
ARG_INT16(value);
// TODO Cursor_updateStruct8bs(objectId, v3);
_vm->notifyThreadId(opCall._callerThreadId);
}
void BbdouSpecialCode::playSoundEffect(int soundIndex) {
static const uint32 kSoundEffectIds[] = {
0, 1,
0x900C1, 2,
0, 3,
0x900C0, 4,
0x900C2, 5,
0, 6
};
uint32 soundEffectId = kSoundEffectIds[2 * soundIndex];
if (soundEffectId) {
// TODO _vm->startSound(soundEffectId, 255, 0);
}
}
void BbdouSpecialCode::resetItem10(uint32 objectId, Item10 *item10) {
if (item10->_playSound48 == 1) {
_bubble->hide();
item10->_verbId = 0x1B0000;
item10->_playSound48 = 0;
item10->_objectIds[0] = 0;
item10->_objectIds[1] = 0;
}
_vm->_input->discardButtons(0xFFFF);
}
bool BbdouSpecialCode::testValueRange(int value) {
return value >= 2 && value <= 7;
}
void BbdouSpecialCode::setCursorControlRoutine(uint32 objectId, int num) {
Control *control = _vm->_dict->getObjectControl(objectId);
if (num == 0)
control->_actor->setControlRoutine(
new Common::Functor2Mem<Control*, uint32, void, BbdouSpecialCode>(this, &BbdouSpecialCode::cursorInteractControlRoutine));
else
control->_actor->setControlRoutine(
new Common::Functor2Mem<Control*, uint32, void, BbdouSpecialCode>(this, &BbdouSpecialCode::cursorControlRoutine2));
}
Common::Point BbdouSpecialCode::getBackgroundCursorPos(Common::Point cursorPos) {
Common::Point pt = _vm->_camera->getScreenOffset();
pt.x += cursorPos.x;
pt.y += cursorPos.y;
return pt;
}
bool BbdouSpecialCode::runCause(Control *control, CursorData &cursorData,
uint32 verbId, uint32 objectId1, uint32 objectId2, int soundIndex) {
// TODO
return false;
}
void BbdouSpecialCode::showBubble(uint32 objectId, uint32 overlappedObjectId, uint32 holdingObjectId,
Item10 *item10, uint32 progResKeywordId) {
// TODO
}
bool BbdouSpecialCode::findVerbId(Item10 *item10, uint32 currOverlappedObjectId, int always0, uint32 &outVerbId) {
// TODO
return false;
}
void BbdouSpecialCode::cursorInteractControlRoutine(Control *cursorControl, uint32 deltaTime) {
Actor *actor = cursorControl->_actor;
CursorData &cursorData = _cursor->_data;
if (cursorData._visibleCtr > 0) {
Common::Point cursorPos = _vm->_input->getCursorPosition();
if (cursorPos == actor->_position) {
cursorData._idleCtr += deltaTime;
if (cursorData._idleCtr > 3600)
cursorData._idleCtr = 0;
} else {
actor->_position.x = cursorPos.x;
actor->_position.y = cursorPos.y;
cursorData._idleCtr = 0;
}
if (updateTrackingCursor(cursorControl))
cursorData._flags |= 1;
else
cursorData._flags &= ~1;
cursorPos = getBackgroundCursorPos(cursorPos);
bool foundOverlapped = false;
Control *overlappedControl = 0;
if (cursorData._flags & 1) {
foundOverlapped = 0;
} else if (_vm->_scriptMan->_activeScenes.getCurrentScene() == 0x1000D) {
/* TODO foundOverlapped = artcntrlGetOverlappedObjectAccurate(cursorControl, cursorPos,
&overlappedControl, cursorData._item10._field58);*/
} else {
foundOverlapped = _vm->_controls->getOverlappedObject(cursorControl, cursorPos,
&overlappedControl, cursorData._item10._field58);
debug("overlappedControl: %p", (void*)overlappedControl);
}
if (foundOverlapped) {
if (overlappedControl->_objectId != cursorData._currOverlappedObjectId) {
if (cursorData._item10._playSound48)
playSoundEffect(4);
resetItem10(cursorControl->_objectId, &cursorData._item10);
int value = _cursor->findStruct8bsValue(overlappedControl->_objectId);
if (!testValueRange(value)) {
if (cursorData._mode == 3)
_cursor->restoreInfo();
_cursor->show(cursorControl);
cursorControl->setActorIndexTo2();
if (cursorData._overlappedObjectId != overlappedControl->_objectId) {
cursorData._overlappedObjectId = overlappedControl->_objectId;
runCause(cursorControl, cursorData, 0x1B0009, 0, overlappedControl->_objectId, 0);
}
if (value == 10) {
if (cursorData._holdingObjectId) {
cursorData._item10._verbId = 0x1B0003;
cursorData._currOverlappedObjectId = overlappedControl->_objectId;
}
else {
cursorData._item10._verbId = 0x1B0002;
cursorData._currOverlappedObjectId = overlappedControl->_objectId;
}
} else {
playSoundEffect(3);
showBubble(cursorControl->_objectId, overlappedControl->_objectId,
cursorData._holdingObjectId, &cursorData._item10,
cursorData._progResKeywordId);
cursorData._currOverlappedObjectId = overlappedControl->_objectId;
}
} else {
if (cursorData._mode != 3) {
_cursor->saveInfo();
cursorData._mode = 3;
cursorData._item10._verbId = 0x1B0006;
cursorData._holdingObjectId = 0;
}
cursorData._sequenceId = _cursor->getSequenceId1(value);
_cursor->show(cursorControl);
cursorData._currOverlappedObjectId = overlappedControl->_objectId;
}
}
} else {
if (cursorData._overlappedObjectId) {
runCause(cursorControl, cursorData, 0x1B0009, 0, 0x40003, 0);
cursorData._overlappedObjectId = 0;
}
if (cursorData._currOverlappedObjectId || cursorData._mode == 3) {
if (cursorData._mode == 3)
_cursor->restoreInfo();
_cursor->show(cursorControl);
cursorControl->setActorIndexTo1();
if (cursorData._item10._playSound48)
playSoundEffect(4);
resetItem10(cursorControl->_objectId, &cursorData._item10);
}
cursorData._currOverlappedObjectId = 0;
}
}
actor->_seqCodeValue1 = 100 * deltaTime;
if (cursorData._visibleCtr <= 0) {
if (cursorData._currOverlappedObjectId || cursorData._mode == 3 || cursorData._mode == 4) {
if (cursorData._mode == 3) {
_cursor->restoreInfo();
} else if (cursorData._mode == 4) {
_cursor->restoreAfterTrackingCursor();
}
cursorControl->setActorIndexTo1();
}
cursorData._currOverlappedObjectId = 0;
} else if (cursorData._currOverlappedObjectId) {
if (_vm->_input->pollButton(1)) {
cursorData._idleCtr = 0;
if (runCause(cursorControl, cursorData, cursorData._item10._verbId, cursorData._holdingObjectId, cursorData._currOverlappedObjectId, 1)) {
resetItem10(cursorControl->_objectId, &cursorData._item10);
cursorData._currOverlappedObjectId = 0;
cursorControl->setActorIndexTo1();
}
} else if (_vm->_input->pollButton(2)) {
uint32 verbId;
cursorData._idleCtr = 0;
if (cursorData._holdingObjectId) {
runCause(cursorControl, cursorData, 0x1B000B, 0, 0x40003, 0);
cursorData._currOverlappedObjectId = 0;
} else if (findVerbId(&cursorData._item10, cursorData._currOverlappedObjectId, 0, verbId) &&
runCause(cursorControl, cursorData, verbId, cursorData._holdingObjectId, cursorData._currOverlappedObjectId, 1)) {
resetItem10(cursorControl->_objectId, &cursorData._item10);
cursorData._currOverlappedObjectId = 0;
cursorControl->setActorIndexTo1();
}
}
} else {
if (_vm->_input->pollButton(1)) {
cursorData._idleCtr = 0;
runCause(cursorControl, cursorData, 0x1B0002, 0, 0x40003, 0);
} else if (_vm->_input->pollButton(4)) {
cursorData._idleCtr = 0;
if (cursorData._item10._field58 <= 1)
runCause(cursorControl, cursorData, cursorData._holdingObjectId != 0 ? 0x1B000B : 0x1B0004, 0, 0x40003, 0);
}
}
}
void BbdouSpecialCode::cursorControlRoutine2(Control *cursorControl, uint32 deltaTime) {
// TODO
}
bool BbdouSpecialCode::updateTrackingCursor(Control *cursorControl) {
// TODO
return false;
}
} // End of namespace Illusions

View File

@ -24,11 +24,17 @@
#define ILLUSIONS_BBDOU_BBDOU_SPECIALCODE_H
#include "illusions/specialcode.h"
#include "common/hashmap.h"
namespace Illusions {
class IllusionsEngine;
class BbdouBubble;
class BbdouCursor;
struct CursorData;
struct Item10;
typedef Common::Functor1<OpCall&, void> SpecialCodeFunction;
class BbdouSpecialCode : public SpecialCode {
public:
@ -37,7 +43,34 @@ public:
virtual void init();
virtual void run(uint32 specialCodeId, OpCall &opCall);
public:
typedef Common::HashMap<uint32, SpecialCodeFunction*> Map;
typedef Map::iterator MapIterator;
Map _map;
BbdouCursor *_cursor;
BbdouBubble *_bubble;
// Special code interface functions
void spcInitCursor(OpCall &opCall);
void spcEnableCursor(OpCall &opCall);
void spcDisableCursor(OpCall &opCall);
void spcAddCursorSequence(OpCall &opCall);
void spcInitBubble(OpCall &opCall);
void spcSetupBubble(OpCall &opCall);
void spcSetObjectInteractMode(OpCall &opCall);
protected:
// Internal functions
void playSoundEffect(int soundIndex);
void resetItem10(uint32 objectId, Item10 *item10);
bool testValueRange(int value);
void setCursorControlRoutine(uint32 objectId, int num);
Common::Point getBackgroundCursorPos(Common::Point cursorPos);
bool runCause(Control *control, CursorData &cursorData,
uint32 verbId, uint32 objectId1, uint32 objectId2, int soundIndex);
void showBubble(uint32 objectId, uint32 overlappedObjectId, uint32 holdingObjectId,
Item10 *item10, uint32 progResKeywordId);
bool findVerbId(Item10 *item10, uint32 currOverlappedObjectId, int always0, uint32 &outVerbId);
void cursorInteractControlRoutine(Control *cursorControl, uint32 deltaTime);
void cursorControlRoutine2(Control *cursorControl, uint32 deltaTime);
bool updateTrackingCursor(Control *cursorControl);
};
} // End of namespace Illusions

View File

@ -213,23 +213,9 @@ bool IllusionsEngine::hasFeature(EngineFeature f) const {
void IllusionsEngine::updateEvents() {
Common::Event event;
while (_eventMan->pollEvent(event)) {
_input->processEvent(event);
switch (event.type) {
case Common::EVENT_KEYDOWN:
break;
case Common::EVENT_KEYUP:
break;
case Common::EVENT_MOUSEMOVE:
break;
case Common::EVENT_LBUTTONDOWN:
break;
case Common::EVENT_LBUTTONUP:
break;
case Common::EVENT_RBUTTONDOWN:
break;
case Common::EVENT_RBUTTONUP:
break;
case Common::EVENT_QUIT:
quitGame();
break;
@ -240,7 +226,9 @@ void IllusionsEngine::updateEvents() {
}
Common::Point *IllusionsEngine::getObjectActorPositionPtr(uint32 objectId) {
// TODO Dummy, to be replaced later
Control *control = _dict->getObjectControl(objectId);
if (control && control->_actor)
return &control->_actor->_position;
return 0;
}
@ -296,6 +284,7 @@ int IllusionsEngine::updateGraphics() {
Common::Point panPoint(0, 0);
uint32 currTime = getCurrentTime();
_camera->update(currTime);
// TODO Move to BackgroundItems class
@ -312,7 +301,7 @@ int IllusionsEngine::updateGraphics() {
panPoint = backgroundItem->_panPoints[i];
}
}
// TODO Move to Controls class
for (Controls::ItemsIterator it = _controls->_controls.begin(); it != _controls->_controls.end(); ++it) {
Control *control = *it;

View File

@ -27,18 +27,45 @@ namespace Illusions {
Input::Input() {
_buttonStates = 0;
_newButtons = 0;
// TODO? _buttonsDown = 0;
// TODO? _unk6 = 0;
_buttonsDown = 0;
_newKeys = 0;
_enabledButtons = 0xFFFF;
_cursorPos.x = 0;
_cursorPos.y = 0;
_prevCursorPos.x = 0;
_prevCursorPos.y = 0;
// TODO Not sure if this is still needed newTimer(40, 0, 0, Input_onTimer);
initKeys();
}
void Input::processEvent(Common::Event event) {
// TODO
switch (event.type) {
case Common::EVENT_KEYDOWN:
handleKey(event.kbd.keycode, MOUSE_NONE, true);
break;
case Common::EVENT_KEYUP:
handleKey(event.kbd.keycode, MOUSE_NONE, false);
break;
case Common::EVENT_MOUSEMOVE:
_cursorPos.x = event.mouse.x;
_cursorPos.y = event.mouse.y;
break;
case Common::EVENT_LBUTTONDOWN:
handleMouseButton(MOUSE_BUTTON0, true);
break;
case Common::EVENT_LBUTTONUP:
handleMouseButton(MOUSE_BUTTON0, false);
break;
case Common::EVENT_RBUTTONDOWN:
handleMouseButton(MOUSE_BUTTON1, true);
break;
case Common::EVENT_RBUTTONUP:
handleMouseButton(MOUSE_BUTTON1, false);
break;
default:
break;
}
}
bool Input::pollButton(uint buttons) {
@ -90,4 +117,59 @@ Common::Point Input::getCursorDelta() {
return deltaPos;
}
void Input::initKeys() {
// NOTE Skipped debugging keys of the original engine, not sure if used
addKeyMapping(Common::KEYCODE_INVALID, MOUSE_BUTTON0, 0x01);
addKeyMapping(Common::KEYCODE_RETURN, MOUSE_NONE, 0x01);
addKeyMapping(Common::KEYCODE_TAB, MOUSE_NONE, 0x04);
addKeyMapping(Common::KEYCODE_INVALID, MOUSE_BUTTON1, 0x04);
addKeyMapping(Common::KEYCODE_ESCAPE, MOUSE_NONE, 0x08);
addKeyMapping(Common::KEYCODE_SPACE, MOUSE_NONE, 0x10);
addKeyMapping(Common::KEYCODE_F1, MOUSE_NONE, 0x20);
addKeyMapping(Common::KEYCODE_UP, MOUSE_NONE, 0x40);
addKeyMapping(Common::KEYCODE_DOWN, MOUSE_NONE, 0x80);
addKeyMapping(Common::KEYCODE_INVALID, MOUSE_BUTTON1, 0x80);
}
void Input::addKeyMapping(Common::KeyCode key, int mouseButton, uint bitMask) {
KeyMapping keyMapping;
keyMapping._key = key;
keyMapping._mouseButton = mouseButton;
keyMapping._bitMask = bitMask;
keyMapping._down = false;
_keyMap.push_back(keyMapping);
}
void Input::handleKey(Common::KeyCode key, int mouseButton, bool down) {
for (KeyMap::iterator it = _keyMap.begin(); it != _keyMap.end(); ++it) {
KeyMapping &keyMapping = *it;
if ((keyMapping._key != Common::KEYCODE_INVALID && keyMapping._key == key) ||
(keyMapping._mouseButton != MOUSE_NONE && keyMapping._mouseButton == mouseButton)) {
if (down && !keyMapping._down) {
_newKeys |= keyMapping._bitMask;
keyMapping._down = true;
} else if (!down)
keyMapping._down = false;
}
}
uint prevButtonStates = _buttonStates;
debug("_newKeys = %08X", _newKeys);
_buttonStates |= _newKeys;
_newKeys = 0;
_newButtons = ~prevButtonStates & _buttonStates;
debug("_buttonStates = %08X", _buttonStates);
}
void Input::handleMouseButton(int mouseButton, bool down) {
if (down)
_buttonsDown |= mouseButton;
else
_buttonsDown &= ~mouseButton;
handleKey(Common::KEYCODE_INVALID, mouseButton, down);
}
} // End of namespace Illusions

View File

@ -23,11 +23,26 @@
#ifndef ILLUSIONS_INPUT_H
#define ILLUSIONS_INPUT_H
#include "common/array.h"
#include "common/events.h"
#include "common/keyboard.h"
#include "common/rect.h"
namespace Illusions {
enum {
MOUSE_NONE = 0,
MOUSE_BUTTON0 = 1,
MOUSE_BUTTON1 = 2
};
struct KeyMapping {
Common::KeyCode _key;
int _mouseButton;
uint _bitMask;
bool _down;
};
class Input {
public:
Input();
@ -43,9 +58,16 @@ public:
void setCursorPosition(Common::Point mousePos);
Common::Point getCursorDelta();
protected:
uint _buttonStates, _newButtons;
typedef Common::Array<KeyMapping> KeyMap;
uint _buttonStates, _newButtons, _buttonsDown;
uint _enabledButtons;
uint _newKeys;
Common::Point _cursorPos, _prevCursorPos;
KeyMap _keyMap;
void initKeys();
void addKeyMapping(Common::KeyCode key, int mouseButton, uint bitMask);
void handleKey(Common::KeyCode key, int mouseButton, bool down);
void handleMouseButton(int mouseButton, bool down);
};
} // End of namespace Illusions

View File

@ -5,6 +5,7 @@ MODULE_OBJS := \
actor.o \
actorresource.o \
backgroundresource.o \
bbdou/bbdou_bubble.o \
bbdou/bbdou_cursor.o \
bbdou/bbdou_specialcode.o \
camera.o \

View File

@ -29,6 +29,7 @@
#include "illusions/scriptman.h"
#include "illusions/scriptresource.h"
#include "illusions/scriptthread.h"
#include "illusions/specialcode.h"
namespace Illusions {
@ -559,11 +560,11 @@ void ScriptOpcodes::opRunSpecialCode(ScriptThread *scriptThread, OpCall &opCall)
ARG_SKIP(2);
ARG_UINT32(specialCodeId);
_vm->_scriptMan->_callerThreadId = opCall._callerThreadId;
// TODO _vm->runSpecialCode(specialCodeId, opCall._code + 8, opCall._threadId);
_vm->_specialCode->run(specialCodeId, opCall);
_vm->_scriptMan->_callerThreadId = 0;
//DEBUG Resume calling thread, later done by the special code
_vm->notifyThreadId(opCall._callerThreadId);
//_vm->notifyThreadId(opCall._callerThreadId);
}