scummvm/engines/trecision/anim.cpp
2021-07-08 21:57:48 +01:00

380 lines
10 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "trecision/anim.h"
#include "trecision/dialog.h"
#include "trecision/logic.h"
#include "trecision/pathfinding3d.h"
#include "trecision/scheduler.h"
#include "trecision/text.h"
#include "trecision/trecision.h"
#include "trecision/video.h"
namespace Trecision {
#define ATF_WAITTEXT 1
AnimTypeManager::AnimTypeManager(TrecisionEngine *vm) : _vm(vm) {
for (int i = 0; i < 3; ++i) {
_animType[i]._curFrame = 1;
_animType[i]._lastFrame = 0;
_animType[i]._object = 0;
_animType[i]._status = 0;
_animType[i]._curAnim = nullptr;
}
_oneSpeakDialogCount = 0;
}
AnimTypeManager::~AnimTypeManager() {
}
void AnimTypeManager::executeAtFrameDoit(ATFHandle *h, int doit, uint16 objectId) {
SAnim *anim = &_vm->_animMgr->_animTab[_vm->_room[_vm->_curRoom]._bkgAnim];
switch (doit) {
case fCLROBJSTATUS:
_vm->setObjectVisible(objectId, false);
break;
case fSETOBJSTATUS:
_vm->setObjectVisible(objectId, true);
break;
case fONETIME:
_vm->setObjectAnim(objectId, 0);
break;
case fCREPACCIO:
if (_vm->_room[kRoom2E].hasExtra())
_vm->_obj[oCRACK2E]._position = 7;
else
_vm->_obj[oCRACK2E]._position = 6;
break;
case fSERPVIA:
_vm->_scheduler->doEvent(_vm->_snake52._class, _vm->_snake52._event, _vm->_snake52._priority, _vm->_snake52._u16Param1, _vm->_snake52._u16Param2, _vm->_snake52._u8Param, _vm->_snake52._u32Param);
break;
case fPIRANHA:
_vm->setObjectAnim(oLUCCHETTO53, 0);
_vm->setObjectAnim(oGRATAC53, 0);
_vm->setObjectAnim(oGRATAA53, 0);
_vm->_obj[oLUCCHETTO53]._action = 1240;
_vm->_obj[oGRATAC53]._action = 1243;
_vm->_obj[oGRATAA53]._action = 1246;
_vm->_obj[oLAGO53]._examine = 1237;
break;
case fMOREAU:
_vm->setObjectAnim(oWINDOWB58, 0);
_vm->_obj[oWINDOWB58]._action = 1358;
break;
case fDOOR58:
_vm->_scheduler->leftClick(468, 180 + TOP);
break;
case fHELLEN:
_vm->_scheduler->leftClick(336, 263 + TOP);
break;
case fVALVEON34:
if (!(_vm->_dialogMgr->isDialogFinished(616)) && // if the fmv is not done
(_vm->isObjectVisible(oTUBOA34)) && // if there's a cut pipe
!(_vm->isObjectVisible(oTUBOFT34))) // if there's not tube outside
_vm->_animMgr->smkToggleTrackAudio(0, 2, true);
break;
case fVALVEOFF34:
_vm->_animMgr->smkToggleTrackAudio(0, 2, false);
break;
case fCHARACTEROFF:
_vm->_flagShowCharacter = false;
break;
case fCHARACTERON:
_vm->_flagShowCharacter = true;
break;
case fCHARACTERFOREGROUND:
_vm->_pathFind->setForcedActorPos(BOX_FOREGROUND);
break;
case fCHARACTERBACKGROUND:
_vm->_pathFind->setForcedActorPos(BOX_BACKGROUND);
break;
case fCHARACTERNORM:
_vm->_pathFind->setForcedActorPos(BOX_NORMAL);
break;
case fSETEXTRA:
_vm->_obj[objectId].setFlagExtra(true);
break;
case fCLREXTRA:
_vm->_obj[objectId].setFlagExtra(false);
break;
case fANIMOFF1:
anim->toggleAnimArea(1, false);
if (_vm->_curRoom == kRoom11 ||
_vm->_curRoom == kRoom1D ||
_vm->_curRoom == kRoom14 ||
_vm->_curRoom == kRoom22 ||
_vm->_curRoom == kRoom48 ||
_vm->_curRoom == kRoom4P)
_vm->_animMgr->smkToggleTrackAudio(0, 1, false);
break;
case fANIMOFF2:
anim->toggleAnimArea(2, false);
if (_vm->_curRoom == kRoom2E)
_vm->_animMgr->smkToggleTrackAudio(0, 2, false);
break;
case fANIMOFF3:
anim->toggleAnimArea(3, false);
break;
case fANIMOFF4:
anim->toggleAnimArea(4, false);
if (_vm->_curRoom == kRoom28)
_vm->_animMgr->smkToggleTrackAudio(0, 1, false);
break;
case fANIMON1:
anim->toggleAnimArea(1, true);
if (_vm->_curRoom == kRoom14 || _vm->_curRoom == kRoom1D || _vm->_curRoom == kRoom22 || _vm->_curRoom == kRoom48 || _vm->_curRoom == kRoom4P) {
_vm->_animMgr->smkToggleTrackAudio(0, 1, true);
}
break;
case fANIMON2:
anim->toggleAnimArea(2, true);
if (_vm->_curRoom == kRoom2E)
_vm->_animMgr->smkToggleTrackAudio(0, 2, true);
break;
case fANIMON3:
anim->toggleAnimArea(3, true);
break;
case fANIMON4:
anim->toggleAnimArea(4, true);
break;
case fENDDEMO:
_vm->demoOver();
_vm->quitGame();
break;
case fSTOP2TXT:
h->_status |= ATF_WAITTEXT;
// Sets a flag that is always cleared when you finish speaking
// if the flag is cleared the anim no longer plays
// (to be done in the smacker player)
// also the counters in next() stops
break;
default:
break;
}
}
void AnimTypeManager::processAtFrame(ATFHandle *h, int type, int atf) {
const uint16 index = h->_curAnim->_atFrame[atf]._index;
switch (type) {
case ATFTEXT:
_vm->_textMgr->characterSayInAction(index);
break;
case ATFTEXTACT:
_vm->_textMgr->characterSayInAction(_vm->_obj[h->_object]._action);
break;
case ATFTEXTEX:
_vm->_textMgr->characterSayInAction(_vm->_obj[h->_object]._examine);
break;
case ATFCLR:
_vm->setObjectVisible(index, false);
break;
case ATFCLRI:
_vm->removeIcon(index);
break;
case ATFCEX:
_vm->_obj[h->_object]._examine = index;
break;
case ATFCACT:
_vm->_obj[h->_object]._action = index;
break;
case ATFSET:
_vm->setObjectVisible(index, true);
break;
case ATFSETI:
_vm->addIcon(index);
break;
case ATFDO:
executeAtFrameDoit(h, index, h->_object);
break;
case ATFROOM:
_vm->changeRoom(index);
break;
case ATFSETPOS:
_vm->_pathFind->setPosition(index);
break;
case ATFDIALOG:
_vm->_dialogMgr->playDialog(index);
break;
case ATFCOBJANIM:
_vm->_obj[h->_object]._anim = index;
break;
case ATFCOBJBOX:
_vm->_obj[h->_object]._nbox = index;
break;
case ATFCOBJPOS:
_vm->_obj[h->_object]._position = index;
break;
case ATFSETFORE:
_vm->_obj[index]._nbox = BOX_FOREGROUND;
break;
case ATFSETBACK:
_vm->_obj[index]._nbox = BOX_BACKGROUND;
break;
case ATFSWITCH:
_vm->setObjectVisible(index, !_vm->isObjectVisible(index));
break;
case ATFSETROOMT:
_vm->_logicMgr->setupAltRoom(index, true);
break;
case ATFSETROOMF:
_vm->_logicMgr->setupAltRoom(index, false);
break;
case ATFREADBOX:
switch (index) {
case 1: {
const Common::String filename = Common::String::format("%s.3d", _vm->_room[_vm->_curRoom]._baseName);
_vm->read3D(filename);
_vm->_room[_vm->_curRoom].setExtra(false);
}
break;
case 2: {
const Common::String filename = Common::String::format("%s2.3d", _vm->_room[_vm->_curRoom]._baseName);
_vm->read3D(filename);
_vm->_room[_vm->_curRoom].setExtra(true);
if (_vm->_curRoom == kRoom37)
_vm->_animMgr->smkToggleTrackAudio(0, 1, true);
} break;
default:
break;
}
break;
case ATFONESPEAK:
switch (index) {
case 1: // Storekeeper's wife
if (_vm->_room[kRoom1D].hasExtra())
break;
// Quotes spoken by the storekeeper's wife while she is in the cellar
_vm->_textMgr->someoneSay(307 + _oneSpeakDialogCount, oDONNA1D);
if (_oneSpeakDialogCount < 6)
++_oneSpeakDialogCount;
break;
case 2: // Storekeeper
// Quote when you enter the liquor store: "Ah, it's you again... look round
// if you want, but don't disturb me, I've got a lot to do"
_vm->_textMgr->someoneSay(1788, ocNEGOZIANTE1A);
break;
default:
break;
}
break;
case ATFEND:
_vm->demoOver();
_vm->quitGame();
break;
default:
break;
}
}
void AnimTypeManager::init(uint16 an, uint16 obj) {
SAnim *anim = &_vm->_animMgr->_animTab[an];
ATFHandle *handle = &_animType[kAnimTypeCharacter];
if (anim->_flag & SMKANIM_BKG)
handle = &_animType[kAnimTypeBackground];
if (anim->_flag & SMKANIM_ICON)
handle = &_animType[kAnimTypeIcon];
handle->_curAnim = anim;
handle->_object = obj ? obj : _vm->_curObj;
handle->_curFrame = 0;
handle->_lastFrame = -1;
handle->_status = 0;
}
void AnimTypeManager::next() {
for (int i = 0; i < 3; ++i) {
if (!(_animType[i]._status & ATF_WAITTEXT) || !_vm->_flagCharacterSpeak)
++_animType[i]._curFrame;
}
}
void AnimTypeManager::end(int type) {
ATFHandle *h = &_animType[type];
SAnim *anim = h->_curAnim;
h->_curFrame = 0;
// if this ATFrame has already been handled
if (h->_curFrame == h->_lastFrame)
return;
h->_lastFrame = h->_curFrame;
for (int32 i = 0; i < MAXATFRAME; ++i) {
// if it's time to run this AtFrame
if (anim->_atFrame[i]._numFrame == 0 && anim->_atFrame[i]._type) {
const uint8 area = anim->_atFrame[i]._area;
if ( area == 0 ||
(area == 1 && anim->isAnimAreaShown(1)) ||
(area == 2 && anim->isAnimAreaShown(2)) ||
(area == 3 && anim->isAnimAreaShown(3)) ||
(area == 4 && anim->isAnimAreaShown(4)))
processAtFrame(h, anim->_atFrame[i]._type, i);
}
}
h->_curAnim = nullptr;
}
void AnimTypeManager::handler(int type) {
ATFHandle *h = &_animType[type];
SAnim *anim = h->_curAnim;
if (anim == nullptr)
return;
if (h->_curFrame == 0)
++h->_curFrame;
// if this ATFrame has already been applied
if (h->_curFrame <= h->_lastFrame)
return;
for (int32 i = 0; i < MAXATFRAME; ++i) {
// if it's time to run this AtFrame
if (anim->_atFrame[i]._numFrame > h->_lastFrame &&
anim->_atFrame[i]._numFrame <= h->_curFrame &&
anim->_atFrame[i]._numFrame != 0) {
const uint8 child = anim->_atFrame[i]._area;
if ( child == 0 ||
(child == 1 && anim->isAnimAreaShown(1)) ||
(child == 2 && anim->isAnimAreaShown(2)) ||
(child == 3 && anim->isAnimAreaShown(3)) ||
(child == 4 && anim->isAnimAreaShown(4)))
processAtFrame(h, anim->_atFrame[i]._type, i);
}
}
// set _lastFrame
h->_lastFrame = h->_curFrame;
}
} // End of namespace Trecision