scummvm/engines/ngi/lift.cpp
2021-12-26 18:48:43 +01:00

521 lines
12 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ngi/ngi.h"
#include "ngi/objects.h"
#include "ngi/objectnames.h"
#include "ngi/constants.h"
#include "ngi/scene.h"
#include "ngi/statics.h"
#include "ngi/messages.h"
#include "ngi/gameloader.h"
#include "ngi/motion.h"
namespace NGI {
int NGIEngine::lift_getButtonIdP(int objid) {
switch (objid) {
case ST_LBN_0N:
return ST_LBN_0P;
case ST_LBN_1N:
return ST_LBN_1P;
case ST_LBN_2N:
return ST_LBN_2P;
case ST_LBN_3N:
return ST_LBN_3P;
case ST_LBN_4N:
return ST_LBN_4P;
case ST_LBN_5N:
return ST_LBN_5P;
case ST_LBN_6N:
return ST_LBN_6P;
case ST_LBN_7N:
return ST_LBN_7P;
case ST_LBN_8N:
return ST_LBN_8P;
case ST_LBN_9N:
return ST_LBN_9P;
default:
return 0;
}
}
int NGIEngine::lift_getButtonIdH(int objid) {
switch (objid) {
case ST_LBN_0P:
return ST_LBN_0H;
case ST_LBN_1P:
return ST_LBN_1H;
case ST_LBN_2P:
return ST_LBN_2H;
case ST_LBN_3P:
return ST_LBN_3H;
case ST_LBN_4P:
return ST_LBN_4H;
case ST_LBN_5P:
return ST_LBN_5H;
case ST_LBN_6P:
return ST_LBN_6H;
case ST_LBN_7P:
return ST_LBN_7H;
case ST_LBN_8P:
return ST_LBN_8H;
case ST_LBN_9P:
return ST_LBN_9H;
default:
return 0;
}
}
int NGIEngine::lift_getButtonIdN(int objid) {
switch (objid) {
case ST_LBN_0H:
case ST_LBN_0N:
case ST_LBN_0P:
return ST_LBN_0N;
case ST_LBN_1H:
case ST_LBN_1N:
case ST_LBN_1P:
return ST_LBN_1N;
case ST_LBN_2H:
case ST_LBN_2N:
case ST_LBN_2P:
return ST_LBN_2N;
case ST_LBN_3H:
case ST_LBN_3N:
case ST_LBN_3P:
return ST_LBN_3N;
case ST_LBN_4H:
case ST_LBN_4N:
case ST_LBN_4P:
return ST_LBN_4N;
case ST_LBN_5H:
case ST_LBN_5N:
case ST_LBN_5P:
return ST_LBN_5N;
case ST_LBN_6H:
case ST_LBN_6N:
case ST_LBN_6P:
return ST_LBN_6N;
case ST_LBN_7H:
case ST_LBN_7N:
case ST_LBN_7P:
return ST_LBN_7N;
case ST_LBN_8H:
case ST_LBN_8N:
case ST_LBN_8P:
return ST_LBN_8N;
case ST_LBN_9H:
case ST_LBN_9N:
case ST_LBN_9P:
return ST_LBN_9N;
default:
return 0;
}
}
void NGIEngine::lift_setButton(const char *name, int state) {
GameVar *var = g_nmi->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons);
if (var)
var->setSubVarAsInt(name, state);
}
void NGIEngine::lift_init(Scene *sc, int enterSeq, int exitSeq) {
_lastLiftButton = nullptr;
_liftEnterMQ = sc->getMessageQueueById(enterSeq);
if (!_liftEnterMQ)
return;
_liftExitMQ = sc->getMessageQueueById(exitSeq);
if (!_liftExitMQ)
return;
ExCommand *ex = _liftEnterMQ->getExCommandByIndex(0);
if (!ex)
return;
_liftX = ex->_x;
_liftY = ex->_y;
_lift = sc->getStaticANIObject1ById(ANI_LIFT, -1);
for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) {
StaticANIObject *ani = sc->_staticANIObjectList1[i];
if (ani->_id == ANI_LIFTBUTTON)
ani->_statics = ani->getStaticsById(lift_getButtonIdP(ani->_statics->_staticsId));
}
GameVar *var = getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons);
if (var) {
for (var = var->_subVars; var; var = var->_nextVarObj) {
for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) {
StaticANIObject *ani = sc->_staticANIObjectList1[i];
if (ani->_id == ANI_LIFTBUTTON) {
int id = lift_getButtonIdN(ani->_statics->_staticsId);
if (id == var->_value.intValue)
ani->_statics = ani->getStaticsById(id);
}
}
}
}
}
void NGIEngine::lift_exitSeq(ExCommand *cmd) {
if (cmd) {
MessageQueue *mq = _globalMessageQueueList->getMessageQueueById(cmd->_parId);
if (mq)
mq->activateExCommandsByKind(34);
}
_lift->changeStatics2(ST_LFT_CLOSED);
MessageQueue *mq = new MessageQueue(_globalMessageQueueList->compact());
ExCommand *ex = new ExCommand(_aniMan->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0);
ex->_z = 256;
ex->_messageNum = 256;
ex->_excFlags |= 3;
mq->addExCommandToEnd(ex);
if (!cmd) {
ex = new ExCommand(_aniMan->_id, 2, 40, 0, 0, 0, 1, 0, 0, 0);
ex->_param = _aniMan->_odelay;
ex->_excFlags |= 2;
mq->addExCommandToEnd(ex);
}
ex = new ExCommand(_lift->_id, 1, MV_LFT_OPEN, 0, 0, 0, 1, 0, 0, 0);
ex->_param = _lift->_odelay;
ex->_excFlags |= 2;
mq->addExCommandToEnd(ex);
ex = new ExCommand(_aniMan->_id, 1, MV_MAN_STARTD, 0, 0, 0, 1, 0, 0, 0);
ex->_param = _aniMan->_odelay;
ex->_excFlags |= 2;
mq->addExCommandToEnd(ex);
ex = new ExCommand(_aniMan->_id, 5, -1, 0, 0, 0, 1, 0, 0, 0);
ex->_param = _aniMan->_odelay;
ex->_z = 10;
ex->_x = -1;
ex->_y = -1;
ex->_excFlags |= 3;
mq->addExCommandToEnd(ex);
ex = new ExCommand(_aniMan->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
ex->_z = 256;
ex->_messageNum = 0;
mq->addExCommandToEnd(ex);
ex = new ExCommand(0, 17, MSG_LIFT_STARTEXITQUEUE, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
mq->addExCommandToEnd(ex);
ex = new ExCommand(_lift->_id, 1, MV_LFT_CLOSE, 0, 0, 0, 1, 0, 0, 0);
ex->_param = _lift->_odelay;
ex->_excFlags |= 2;
mq->addExCommandToEnd(ex);
mq->chain(nullptr);
}
void NGIEngine::lift_closedoorSeq() {
if (_lift->_movement) {
if (_lift->_movement->_id == MV_LFT_CLOSE) {
_lift->queueMessageQueue(nullptr);
} else if (_lift->_movement->_id == MV_LFT_OPEN) {
int ph = _lift->_movement->_currDynamicPhaseIndex;
_lift->changeStatics2(ST_LFT_OPEN_NEW);
_lift->startAnim(MV_LFT_CLOSE, 0, -1);
if (_lift->_movement->_currMovement)
_lift->_movement->setDynamicPhaseIndex(_lift->_movement->_currMovement->_dynamicPhases.size() - ph);
else
_lift->_movement->setDynamicPhaseIndex(_lift->_movement->_dynamicPhases.size() - ph);
} else {
_lift->changeStatics2(ST_LFT_OPEN_NEW);
_lift->startAnim(MV_LFT_CLOSE, 0, -1);
}
} else {
if (_lift->_statics->_staticsId == ST_LFT_CLOSED ) {
_lift->changeStatics2(ST_LFT_CLOSED);
} else {
_lift->startAnim(MV_LFT_CLOSE, 0, -1);
}
}
MessageQueue *mq = new MessageQueue(_globalMessageQueueList->compact());
ExCommand *ex = new ExCommand(0, 17, MSG_LIFT_GO, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
mq->addExCommandToEnd(ex);
if (!mq->chain(_lift))
delete mq;
}
void NGIEngine::lift_walkAndGo() {
MessageQueue *mq;
ExCommand *ex;
if (abs(_liftX - _aniMan->_ox) > 1 || abs(_liftY - _aniMan->_oy) > 1 || _aniMan->_movement || _aniMan->_statics->_staticsId != ST_MAN_UP) {
mq = getCurrSceneSc2MotionController()->startMove(_aniMan, _liftX, _liftY, 1, ST_MAN_UP);
if (mq) {
ex = new ExCommand(0, 17, MSG_LIFT_CLICKBUTTON, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
mq->addExCommandToEnd(ex);
}
} else {
lift_openLift();
mq = new MessageQueue(_liftEnterMQ, 0, 0);
mq->setFlags(mq->getFlags() | 1);
ex = new ExCommand(_aniMan->_id, 2, 15, 0, 0, 0, 1, 0, 0, 0);
ex->_param = _aniMan->_odelay;
ex->_excFlags |= 2;
mq->addExCommand(ex);
ex = new ExCommand(_aniMan->_id, 5, -1, 0, 0, 0, 1, 0, 0, 0);
ex->_param = _aniMan->_odelay;
ex->_z = _lift->_priority + 1;
ex->_x = -1;
ex->_y = -1;
ex->_excFlags |= 3;
mq->addExCommandToEnd(ex);
ex = new ExCommand(0, 17, MSG_LIFT_CLOSEDOOR, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
mq->addExCommandToEnd(ex);
mq->chain(nullptr);
_aniMan->_flags |= 0x100;
}
}
void NGIEngine::lift_openLift() {
if (_lift->_movement) {
if (_lift->_movement->_id == MV_LFT_OPEN) {
_lift->queueMessageQueue(nullptr);
} else if (_lift->_movement->_id == MV_LFT_CLOSE) {
int idx = _lift->_movement->_currDynamicPhaseIndex;
_lift->changeStatics2(ST_LFT_CLOSED);
_lift->startAnim(MV_LFT_OPEN, 0, -1);
if (_lift->_movement->_currMovement)
_lift->_movement->setDynamicPhaseIndex(_lift->_movement->_currMovement->_dynamicPhases.size() - idx);
else
_lift->_movement->setDynamicPhaseIndex(_lift->_movement->_dynamicPhases.size() - idx);
} else {
_lift->changeStatics2(ST_LFT_CLOSED);
_lift->startAnim(MV_LFT_OPEN, 0, -1);
}
} else if (_lift->_statics->_staticsId == ST_LFT_OPEN_NEW) {
_lift->changeStatics2(ST_LFT_OPEN_NEW);
} else {
_lift->startAnim(MV_LFT_OPEN, 0, -1);
}
}
void NGIEngine::lift_clickButton() {
if (_lastLiftButton)
lift_walkAndGo();
}
void NGIEngine::lift_goAnimation() {
if (_lastLiftButton) {
int parentId = _currentScene->_sceneId;
int buttonId = lift_getButtonIdN(_lastLiftButton->_statics->_staticsId);
if (!buttonId)
return;
int numItems = _gameLoader->_preloadItems.size();
for (int i = 0; i < numItems; i++) {
PreloadItem &pre = _gameLoader->_preloadItems[i];
if (pre.preloadId2 == buttonId && pre.preloadId1 == _currentScene->_sceneId) {
MessageQueue *mq = new MessageQueue(_globalMessageQueueList->compact());
ExCommand *ex = new ExCommand(ANI_MAN, 1, (pre.param != LiftDown ? MV_MAN_LIFTDOWN : MV_MAN_LIFTUP), 0, 0, 0, 1, 0, 0, 0);
ex->_param = -1;
ex->_field_24 = 1;
ex->_excFlags |= 2;
mq->addExCommandToEnd(ex);
ex = new ExCommand(parentId, 17, 61, 0, 0, 0, 1, 0, 0, 0);
ex->_param = buttonId;
ex->_excFlags |= 3;
mq->addExCommandToEnd(ex);
_aniMan->_flags &= ~0x100;
if (!mq->chain(_aniMan))
delete mq;
_aniMan->_flags |= 0x100;
return;
}
}
}
lift_exitSeq(nullptr);
if (_lastLiftButton) {
_lastLiftButton->_statics = _lastLiftButton->getStaticsById(lift_getButtonIdN(_lastLiftButton->_statics->_staticsId));
_lastLiftButton = nullptr;
}
}
void NGIEngine::lift_animateButton(StaticANIObject *button) {
int butId = lift_getButtonIdP(button->_statics->_staticsId);
if (butId && butId != button->_statics->_staticsId) {
if (button == _lastLiftButton) {
playSound(SND_CMN_032, 0);
} else {
if (_lastLiftButton) {
int id = lift_getButtonIdN(_lastLiftButton->_statics->_staticsId);
if (id)
_lastLiftButton->_statics = _lastLiftButton->getStaticsById(id);
_lastLiftButton = nullptr;
}
if (_aniMan->isIdle() && !(_aniMan->_flags & 0x100)) {
_lastLiftButton = button;
button->_statics = button->getStaticsById(butId);
ExCommand *ex = new ExCommand(0, 35, SND_CMN_032, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
ex->_z = 1;
ex->postMessage();
int id = lift_getButtonIdH(_lastLiftButton->_statics->_staticsId);
if (id) {
_lastLiftButton->_statics = _lastLiftButton->getStaticsById(id);
lift_walkAndGo();
}
}
}
}
}
void NGIEngine::lift_startExitQueue() {
MessageQueue *mq = new MessageQueue(_liftExitMQ, 0, 0);
mq->chain(nullptr);
}
void NGIEngine::lift_hoverButton(ExCommand *cmd) {
if (_lastLiftButton) {
if (!(cmd->_param & 2) || _liftX != cmd->_x || _liftY != cmd->_y) {
_lastLiftButton->_statics = _lastLiftButton->getStaticsById(lift_getButtonIdN(_lastLiftButton->_statics->_staticsId));
_lastLiftButton = nullptr;
}
}
}
bool NGIEngine::lift_checkButton(const char *varName) {
GameVar *var = g_nmi->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons);
if (var)
return lift_getButtonIdP(var->getSubVarByName(varName)->_value.intValue) > 0;
return false;
}
void NGIEngine::lift_setButtonStatics(Scene *sc, int buttonId) {
for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) {
StaticANIObject *ani = sc->_staticANIObjectList1[i];
if (ani->_id == ANI_LIFTBUTTON) {
int id = lift_getButtonIdN(ani->_statics->_staticsId);
if (id == buttonId)
ani->_statics = ani->getStaticsById(id);
}
}
}
} // End of namespace NGI