FULLPIPE: Implement CInteractionController::handleInteraction()

This commit is contained in:
Eugene Sandulenko 2013-09-08 23:53:02 +03:00
parent 940c686858
commit 747e70a38e
10 changed files with 466 additions and 51 deletions

View file

@ -365,6 +365,95 @@ bool GameObject::canInteractAny(GameObject *obj2, int invId) {
return false;
}
bool GameObject::getPicAniInfo(PicAniInfo *info) {
if (_objtype == kObjTypePictureObject) {
info->type = 2;
info->objectId = _id;
info->sceneId = 0;
info->field_8 = _okeyCode;
info->flags = _flags;
info->field_24 = _field_8;
info->ox = _ox;
info->oy = _oy;
info->priority = _priority;
return true;
}
if (_objtype == kObjTypeStaticANIObject) {
StaticANIObject *ani = (StaticANIObject *)this;
info->type = (ani->_messageQueueId << 16) | 1;
info->objectId = ani->_id;
info->field_8 = ani->_okeyCode;
info->sceneId = ani->_sceneId;
info->flags = ani->_flags;
info->field_24 = ani->_field_8;
if (ani->_movement) {
info->ox = ani->_movement->_ox;
info->oy = ani->_movement->_oy;
} else {
info->ox = ani->_ox;
info->oy = ani->_oy;
}
info->priority = ani->_priority;
if (ani->_statics)
info->staticsId = ani->_statics->_staticsId;
if (ani->_movement) {
info->movementId = ani->_movement->_id;
info->dynamicPhaseIndex = ani->_movement->_currDynamicPhaseIndex;
}
info->someDynamicPhaseIndex = ani->_someDynamicPhaseIndex;
return true;
}
return false;
}
bool GameObject::setPicAniInfo(PicAniInfo *picAniInfo) {
if (!(picAniInfo->type & 3)) {
warning("StaticANIObject::setPicAniInfo(): Wrong type: %d", picAniInfo->type);
return false;
}
if (picAniInfo->type & 3) {
setOXY(picAniInfo->ox, picAniInfo->oy);
_priority = picAniInfo->priority;
_okeyCode = picAniInfo->field_8;
setFlags(picAniInfo->flags);
_field_8 = picAniInfo->field_24;
}
if (picAniInfo->type & 1) {
StaticANIObject *ani = (StaticANIObject *)this;
ani->_messageQueueId = (picAniInfo->type >> 16) & 0xffff;
if (picAniInfo->staticsId) {
ani->_statics = ani->getStaticsById(picAniInfo->staticsId);
} else {
ani->_statics = 0;
}
if (picAniInfo->movementId) {
ani->_movement = ani->getMovementById(picAniInfo->movementId);
if (ani->_movement)
ani->_movement->setDynamicPhaseIndex(picAniInfo->dynamicPhaseIndex);
} else {
ani->_movement = 0;
}
ani->setSomeDynamicPhaseIndex(picAniInfo->someDynamicPhaseIndex);
}
return true;
}
Picture::Picture() {
_x = 0;
_y = 0;

View file

@ -143,6 +143,8 @@ class GameObject : public CObject {
const char *getName() { return _objectName; }
bool canInteractAny(GameObject *obj2, int invId);
bool getPicAniInfo(PicAniInfo *info);
bool setPicAniInfo(PicAniInfo *info);
};
class PictureObject : public GameObject {

View file

@ -25,10 +25,11 @@
#include "fullpipe/interaction.h"
#include "fullpipe/gameloader.h"
#include "fullpipe/statics.h"
#include "fullpipe/motion.h"
namespace Fullpipe {
int handleObjectInteraction(GameObject *subject, GameObject *object, int invId) {
int handleObjectInteraction(StaticANIObject *subject, GameObject *object, int invId) {
return getGameLoaderInteractionController()->handleInteraction(subject, object, invId);
}
@ -72,7 +73,303 @@ void CInteractionController::sortInteractions(int sceneId) {
Common::sort(_interactions.begin(), _interactions.end(), CInteractionController::compareInteractions);
}
bool CInteractionController::handleInteraction(GameObject *subj, GameObject *obj, int invId) {
bool CInteractionController::handleInteraction(StaticANIObject *subj, GameObject *obj, int invId) {
if (subj) {
if (!subj->isIdle() || (subj->_flags & 0x100))
return false;
}
if (!_interactions.size())
return false;
CInteraction *inter = 0;
CInteraction *previnter = 0;
int dur = 0;
int mindur = 0xFFFF;
MessageQueue *mq;
ExCommand *ex;
for (CObList::iterator i = _interactions.begin(); i != _interactions.end(); ++i) {
CInteraction *cinter = (CInteraction *)*i;
if (!cinter->canInteract(subj, obj, invId))
continue;
if ((inter || cinter->_objectId2) && (!obj || cinter->_objectId3 != obj->_id)) {
if (cinter->_messageQueue)
cinter->_messageQueue->calcDuration(subj);
PicAniInfo aniInfo;
obj->getPicAniInfo(&aniInfo);
if (cinter->_staticsId1) {
StaticANIObject *ani = (StaticANIObject *)obj;
ani->_messageQueueId = 0;
ani->changeStatics2(cinter->_staticsId1);
}
int xpos = cinter->_xOffs + obj->_ox;
int ypos = cinter->_yOffs + obj->_oy;
obj->setPicAniInfo(&aniInfo);
if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1) {
mq = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->method4C(subj, xpos, ypos, 1, cinter->_staticsId2);
if (mq) {
dur = mq->calcDuration(subj);
delete mq;
} else {
dur = 0x10000;
}
inter = previnter;
} else {
dur = 0;
}
if (dur < mindur) {
inter = cinter;
mindur = dur;
previnter = cinter;
}
} else {
inter = cinter;
break;
}
}
if (!inter)
return false;
if (!inter->_objectId2) {
StaticANIObject *ani = (StaticANIObject *)obj;
if (!ani->isIdle())
return false;
if (ani->_flags & 0x100)
return false;
if (!inter->_staticsId1 || !(inter->_flags & 1))
goto LABEL_38;
if (ani->_movement || ani->_statics == 0 || ani->_statics->_staticsId != inter->_staticsId1) {
mq = ani->changeStatics1(inter->_staticsId1);
if (!mq)
return false;
ex = new ExCommand((subj ? subj->_id : 0), 55, 0, 0, 0, 0, 1, 0, 0, 0);
ex->_x = obj->_id;
ex->_y = obj->_okeyCode;
ex->_keyCode = subj ? subj->_okeyCode : 0;
ex->_excFlags = 3;
ex->_field_14 = (obj->_objtype != kObjTypePictureObject);
ex->_field_20 = invId;
mq->_exCommands.push_back(ex);
if (mq->_isFinished) {
mq->_isFinished = 0;
ani->queueMessageQueue(mq);
}
} else {
if (ani->getMessageQueue())
ani->queueMessageQueue(0);
LABEL_38:
if (inter->_messageQueue) {
mq = new MessageQueue(inter->_messageQueue, 0, 1);
mq->changeParam28ForObjectId(ani->_id, -1, ani->_okeyCode);
if (!mq->chain(0))
return false;
}
}
return true;
}
if (obj && !subj)
return true;
if (!obj || inter->_objectId3 == obj->_id) {
if (subj) {
if (inter->_messageQueue) {
if (subj->isIdle()) {
mq = new MessageQueue(inter->_messageQueue, 0, 1);
if (!mq->chain(subj)) {
if (mq)
delete mq;
return false;
}
}
}
}
return true;
}
if (inter->isOverlapping(subj, obj)) {
if (obj->_objtype == kObjTypeStaticANIObject) {
StaticANIObject *ani = (StaticANIObject *)obj;
ani->queueMessageQueue(0);
if (inter->_staticsId1)
ani->changeStatics2(inter->_staticsId1);
if (!(inter->_flags & 0x10000))
obj->_flags |= 0x80;
}
if (!inter->_messageQueue)
return false;
subj->setOXY(inter->_xOffs + obj->_ox, inter->_yOffs + obj->_oy);
mq = new MessageQueue(inter->_messageQueue, 0, 1);
mq->changeParam28ForObjectId(obj->_id, -1, obj->_okeyCode);
mq->_flags |= 1;
if (!(inter->_flags & 0x10000)) {
ex = new ExCommand(obj->_id, 34, 0x80, 0, 0, 0, 1, 0, 0, 0);
ex->_keyCode = obj->_okeyCode;
ex->_field_14 = 0x100;
ex->_messageNum = 0;
ex->_excFlags = 3;
mq->_exCommands.push_back(ex);
}
ex = new ExCommand(obj->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0);
ex->_keyCode = obj->_okeyCode;
ex->_field_14 = 0x100;
ex->_messageNum = 0;
ex->_excFlags = 3;
mq->_exCommands.push_back(ex);
ex = new ExCommand(subj->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0);
ex->_keyCode = subj->_okeyCode;
ex->_field_14 = 0x100;
ex->_messageNum = 0;
ex->_excFlags = 3;
mq->_exCommands.push_back(ex);
ex = new ExCommand(subj->_id, 17, 0x40, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
ex->_keyCode = 0;
mq->_exCommands.push_back(ex);
if (!mq->chain(subj)) {
delete mq;
return false;
}
subj->_flags |= 1;
obj->_flags |= 1;
} else {
bool someFlag = false;
PicAniInfo aniInfo;
obj->getPicAniInfo(&aniInfo);
if (obj->_objtype == kObjTypeStaticANIObject && inter->_staticsId1) {
StaticANIObject *ani = (StaticANIObject *)obj;
ani->_messageQueueId = 0;
ani->changeStatics2(inter->_staticsId1);
}
int xpos = inter->_yOffs + obj->_ox;
int ypos = inter->_yOffs + obj->_oy;
obj->setPicAniInfo(&aniInfo);
if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1
|| (inter->_staticsId2 != 0 && (subj->_statics == 0 || subj->_statics->_staticsId != inter->_staticsId2))) {
mq = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->method34(subj, xpos, ypos, 1, inter->_staticsId2);
if (!mq)
return false;
ex = new ExCommand(subj->_id, 55, 0, 0, 0, 0, 1, 0, 0, 0);
ex->_x = obj->_id;
ex->_y = obj->_okeyCode;
ex->_keyCode = subj->_okeyCode;
ex->_excFlags = 3;
ex->_field_20 = invId;
ex->_field_14 = (obj->_objtype != kObjTypePictureObject);
mq->_exCommands.push_back(ex);
someFlag = true;
ex = new ExCommand(subj->_id, 17, 0x40, 0, 0, 0, 1, 0, 0, 0);
ex->_x = xpos;
ex->_y = ypos;
ex->_excFlags |= 3;
ex->_keyCode = 6;
ex->_field_14 = obj->_id;
ex->_field_20 = obj->_okeyCode;
ex->postMessage();
}
if (!inter->_staticsId1 || !(inter->_flags & 1))
return true;
StaticANIObject *ani = (StaticANIObject *)obj;
if (!ani->isIdle())
return false;
if (ani->getMessageQueue())
ani->queueMessageQueue(0);
if (!ani->_statics || ani->_statics->_staticsId != inter->_staticsId1 || ani->_movement) {
mq = ani->changeStatics1(inter->_staticsId1);
if (!mq)
return false;
if (someFlag) {
if (!(inter->_flags & 0x10000)) {
if (mq->_isFinished) {
ani->_flags |= 0x80u;
} else {
ex = new ExCommand(ani->_id, 34, 0x80, 0, 0, 0, 1, 0, 0, 0);
ex->_field_14 = 0x80;
ex->_keyCode = ani->_okeyCode;
ex->_excFlags = 3;
mq->_exCommands.push_back(ex);
}
}
ex = new ExCommand(ani->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0);
ex->_keyCode = ani->_okeyCode;
ex->_field_14 = 0x100;
ex->_excFlags = 3;
mq->_exCommands.push_back(ex);
} else {
ex = new ExCommand(subj->_id, 55, 0, 0, 0, 0, 1, 0, 0, 0);
ex->_x = ani->_id;
ex->_y = ani->_okeyCode;
ex->_keyCode = subj->_okeyCode;
ex->_excFlags = 2;
ex->_field_14 = (obj->_objtype != kObjTypePictureObject);
ex->_field_20 = invId;
mq->_exCommands.push_back(ex);
if (!mq->_isFinished)
return true;
mq->_isFinished = 0;
ani->queueMessageQueue(mq);
}
} else {
obj->_flags |= 1;
if (inter->_flags & 0x10000)
return true;
obj->_flags |= 0x80;
}
}
return true;
}
@ -170,11 +467,13 @@ bool CInteraction::canInteract(GameObject *obj1, GameObject *obj2, int invId) {
return true;
}
bool CInteraction::isOverlapping(StaticANIObject *subj, StaticANIObject *obj) {
bool CInteraction::isOverlapping(StaticANIObject *subj, GameObject *obj) {
StaticANIObject *ani = (StaticANIObject *)obj;
if (abs(_xOffs + obj->_ox - subj->_ox) <= 1
&& abs(obj->_oy + _yOffs - subj->_oy) <= 1) {
if (!this->_staticsId2 || subj->_statics != 0 && subj->_statics->_staticsId == _staticsId2) {
if (!_staticsId1 || !(_flags & 1) || obj->_statics != 0 && obj->_statics->_staticsId == _staticsId1)
if (!_staticsId2 || subj->_statics != 0 && subj->_statics->_staticsId == _staticsId2) {
if (!_staticsId1 || !(_flags & 1) || ani->_statics != 0 && ani->_statics->_staticsId == _staticsId1)
return true;
}
}

View file

@ -31,7 +31,7 @@ class GameObject;
class MessageQueue;
class StaticANIObject;
int handleObjectInteraction(GameObject *subject, GameObject *object, int invId);
int handleObjectInteraction(StaticANIObject *subject, GameObject *object, int invId);
class CInteraction : public CObject {
public:
@ -54,7 +54,7 @@ class CInteraction : public CObject {
CInteraction();
virtual bool load(MfcArchive &file);
bool canInteract(GameObject *obj1, GameObject *obj2, int invId);
bool isOverlapping(StaticANIObject *subj, StaticANIObject *obj);
bool isOverlapping(StaticANIObject *subj, GameObject *obj);
};
class CInteractionController : public CObject {
@ -76,7 +76,7 @@ class CInteractionController : public CObject {
void sortInteractions(int sceneId);
bool handleInteraction(GameObject *subj, GameObject *obj, int invId);
bool handleInteraction(StaticANIObject *subj, GameObject *obj, int invId);
};
struct EntranceInfo {

View file

@ -445,6 +445,38 @@ void MessageQueue::replaceKeyCode(int key1, int key2) {
}
}
int MessageQueue::calcDuration(StaticANIObject *obj) {
int res;
ExCommand *ex;
Movement *mov;
for (uint i = 0; (ex = getExCommandByIndex(i)); i++)
if (ex->_parentId == obj->_id) {
if (ex->_messageKind == 1 || ex->_messageKind == 20) {
if ((mov = obj->getMovementById(ex->_messageNum)) != 0) {
if (ex->_field_14 >= 1)
res += ex->_field_14;
else
res += mov->calcDuration();
}
}
}
return res;
}
void MessageQueue::changeParam28ForObjectId(int objId, int oldParam28, int newParam28) {
for (uint i = 0; i < _exCommands.size(); i++) {
ExCommand *ex = getExCommandByIndex(i);
int k = ex->_messageKind;
if ((k == 1 || k == 20 || k == 5 || k == 6 || k == 2 || k == 18 || k == 19 || k == 22 || k == 55)
&& ex->_keyCode == oldParam28
&& ex->_parentId == objId)
ex->_keyCode = newParam28;
}
}
MessageQueue *GlobalMessageQueueList::getMessageQueueById(int id) {
for (Common::Array<MessageQueue *>::iterator s = begin(); s != end(); ++s) {
if ((*s)->_id == id)

View file

@ -133,6 +133,9 @@ class MessageQueue : public CObject {
bool checkGlobalExCommandList1();
bool checkGlobalExCommandList2();
int calcDuration(StaticANIObject *obj);
void changeParam28ForObjectId(int objId, int oldParam28, int newParam28);
};
class GlobalMessageQueueList : public Common::Array<MessageQueue *> {

View file

@ -76,10 +76,22 @@ void CMctlCompound::addObject(StaticANIObject *obj) {
warning("STUB: CMctlCompound::addObject()");
}
void CMctlCompound::initMovGraph2() {
void CMctlCompound::initMovGraph2() {
warning("STUB: CMctlCompound::initMovGraph2()");
}
MessageQueue *CMctlCompound::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: CMctlCompound::method34()");
return 0;
}
MessageQueue *CMctlCompound::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: CMctlCompound::method4C()");
return 0;
}
bool CMctlCompoundArray::load(MfcArchive &file) {
debug(5, "CMctlCompoundArray::load()");

View file

@ -62,6 +62,9 @@ class CMctlCompound : public CMotionController {
virtual void addObject(StaticANIObject *obj);
void initMovGraph2();
MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
};
class Unk2 : public CObject {

View file

@ -815,46 +815,6 @@ void StaticANIObject::adjustSomeXY() {
warning("STUB: StaticANIObject::adjustSomeXY()");
}
bool StaticANIObject::setPicAniInfo(PicAniInfo *picAniInfo) {
if (!(picAniInfo->type & 3)) {
warning("StaticANIObject::setPicAniInfo(): Wrong type: %d", picAniInfo->type);
return false;
}
debug(0, "StaticANIObject::setPicAniInfo() (%s [%d]) type: %d, statid: %d, movid: %d", transCyrillic((byte *)_objectName), _id, picAniInfo->type, picAniInfo->staticsId, picAniInfo->movementId);
if (picAniInfo->type & 3) {
setOXY(picAniInfo->ox, picAniInfo->oy);
_priority = picAniInfo->priority;
_okeyCode = picAniInfo->field_8;
setFlags(picAniInfo->flags);
_field_8 = picAniInfo->field_24;
}
if (picAniInfo->type & 1) {
_messageQueueId = (picAniInfo->type >> 16) & 0xffff;
if (picAniInfo->staticsId) {
_statics = getStaticsById(picAniInfo->staticsId);
} else {
_statics = 0;
}
if (picAniInfo->movementId) {
_movement = getMovementById(picAniInfo->movementId);
if (_movement)
_movement->setDynamicPhaseIndex(picAniInfo->dynamicPhaseIndex);
} else {
_movement = 0;
}
setSomeDynamicPhaseIndex(picAniInfo->someDynamicPhaseIndex);
}
return true;
}
MessageQueue *StaticANIObject::changeStatics1(int msgNum) {
warning("STUB: StaticANIObject::changeStatics1(%d)", msgNum);
@ -1358,6 +1318,21 @@ void Movement::updateCurrDynamicPhase() {
}
}
int Movement::calcDuration() {
int res = 0;
if (_currMovement)
for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) {
res += ((DynamicPhase *)_currMovement->_dynamicPhases[i])->_initialCountdown;
}
else
for (uint i = 0; i < _dynamicPhases.size(); i++) {
res += ((DynamicPhase *)_dynamicPhases[i])->_initialCountdown;
}
return res;
}
void Movement::setDynamicPhaseIndex(int index) {
debug(7, "Movement::setDynamicPhaseIndex(%d)", index);
while (_currDynamicPhaseIndex < index)

View file

@ -145,6 +145,8 @@ class Movement : public GameObject {
void setDynamicPhaseIndex(int index);
DynamicPhase *getDynamicPhaseByIndex(int idx);
int calcDuration();
void removeFirstPhase();
bool gotoNextFrame(int callback1, void (*callback2)(int *));
bool gotoPrevFrame();
@ -207,8 +209,6 @@ class StaticANIObject : public GameObject {
void initMovements();
void loadMovementsPixelData();
bool setPicAniInfo(PicAniInfo *picAniInfo);
void setSomeDynamicPhaseIndex(int val) { _someDynamicPhaseIndex = val; }
void adjustSomeXY();