scummvm/engines/gnap/character.cpp

735 lines
19 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 "gnap/gnap.h"
#include "gnap/character.h"
#include "gnap/gamesys.h"
namespace Gnap {
Character::Character(GnapEngine *vm) : _vm(vm) {
_pos = Common::Point(0, 0);
_idleFacing = kDirNone;
_actionStatus = 0;
_sequenceId = 0;
_sequenceDatNum = 0;
_id = 0;
_gridX = 0;
_gridY = 0;
}
Character::~Character() {}
/************************************************************************************************/
PlayerGnap::PlayerGnap(GnapEngine * vm) : Character(vm) {
_brainPulseNum = 0;
_brainPulseRndValue = 0;
}
int PlayerGnap::getSequenceId(int kind, int gridX, int gridY) {
int sequenceId = 0;
switch (kind) {
case gskPullOutDevice:
if (gridX > 0 && gridY > 0) {
if (_pos.y > gridY) {
if (_pos.x > gridX) {
sequenceId = 0x83F;
_idleFacing = kDirUpLeft;
} else {
sequenceId = 0x83D;
_idleFacing = kDirUpRight;
}
} else {
if (_pos.x > gridX) {
sequenceId = 0x83B;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x839;
_idleFacing = kDirBottomRight;
}
}
} else {
switch (_idleFacing) {
case kDirBottomRight:
sequenceId = 0x839;
break;
case kDirBottomLeft:
sequenceId = 0x83B;
break;
case kDirUpRight:
sequenceId = 0x83D;
break;
default:
sequenceId = 0x83F;
break;
}
}
break;
case gskPullOutDeviceNonWorking:
if (gridX > 0 && gridY > 0) {
if (_pos.y > gridY) {
if (_pos.x > gridX) {
sequenceId = 0x829;
_idleFacing = kDirUpLeft;
} else {
sequenceId = 0x828;
_idleFacing = kDirUpRight;
}
} else {
if (_pos.x > gridX) {
sequenceId = 0x827;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x826;
_idleFacing = kDirBottomRight;
}
}
} else {
switch (_idleFacing) {
case kDirBottomRight:
sequenceId = 0x826;
break;
case kDirBottomLeft:
sequenceId = 0x827;
break;
case kDirUpRight:
sequenceId = 0x828;
break;
default:
sequenceId = 0x829;
break;
}
}
break;
case gskScratchingHead:
if (gridX > 0 && gridY > 0) {
if (_pos.y > gridY) {
if (_pos.x > gridX) {
sequenceId = 0x834;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x885;
_idleFacing = kDirUpRight;
}
} else {
if (_pos.x > gridX) {
sequenceId = 0x834;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x833;
_idleFacing = kDirBottomRight;
}
}
} else {
switch (_idleFacing) {
case kDirBottomRight:
sequenceId = 0x833;
_idleFacing = kDirBottomRight;
break;
case kDirBottomLeft:
sequenceId = 0x834;
_idleFacing = kDirBottomLeft;
break;
case kDirUpRight:
sequenceId = 0x885;
_idleFacing = kDirUpRight;
break;
default:
sequenceId = 0x834;
_idleFacing = kDirBottomLeft;
break;
}
}
break;
case gskIdle:
if (gridX > 0 && gridY > 0) {
if (_pos.y > gridY) {
if (_pos.x > gridX) {
sequenceId = 0x7BC;
_idleFacing = kDirUpLeft;
} else {
sequenceId = 0x7BB;
_idleFacing = kDirUpRight;
}
} else {
if (_pos.x > gridX) {
sequenceId = 0x7BA;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x7B9;
_idleFacing = kDirBottomRight;
}
}
} else {
switch (_idleFacing) {
case kDirBottomRight:
sequenceId = 0x7B9;
break;
case kDirBottomLeft:
sequenceId = 0x7BA;
break;
case kDirUpRight:
sequenceId = 0x7BB;
break;
default:
sequenceId = 0x7BC;
break;
}
}
break;
case gskBrainPulsating:
_brainPulseNum = (_brainPulseNum + 1) & 1;
if (gridX > 0 && gridY > 0) {
if (_pos.y > gridY) {
if (_pos.x > gridX) {
sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812;
_idleFacing = kDirUpLeft;
} else {
sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE;
_idleFacing = kDirUpRight;
}
} else {
if (_pos.x > gridX) {
sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA;
_idleFacing = kDirBottomRight;
}
}
} else {
switch (_idleFacing) {
case kDirBottomRight:
sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA;
break;
case kDirBottomLeft:
sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6;
break;
case kDirUpRight:
sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE;
break;
default:
sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812;
break;
}
}
break;
case gskImpossible:
if (gridX > 0 && gridY > 0) {
if (_pos.y > gridY) {
if (_pos.x > gridX) {
sequenceId = 0x831;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x7A8;
_idleFacing = kDirBottomRight;
}
} else {
if (_pos.x > gridX) {
sequenceId = 0x831;
_idleFacing = kDirBottomLeft;
} else {
if (_pos.x % 2)
sequenceId = 0x7A8;
else
sequenceId = 0x89A;
_idleFacing = kDirBottomRight;
}
}
} else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
sequenceId = 0x831;
_idleFacing = kDirBottomLeft;
} else {
if (_vm->_currentSceneNum % 2)
sequenceId = 0x7A8;
else
sequenceId = 0x89A;
_idleFacing = kDirBottomRight;
}
break;
case gskDeflect:
if (gridX > 0 && gridY > 0) {
if (_pos.y > gridY) {
if (_pos.x > gridX) {
sequenceId = 0x830;
_idleFacing = kDirUpLeft;
} else {
sequenceId = 0x82F;
_idleFacing = kDirUpRight;
}
} else {
if (_pos.x > gridX) {
sequenceId = 0x82E;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x7A7;
_idleFacing = kDirBottomRight;
}
}
} else {
switch (_idleFacing) {
case kDirBottomRight:
sequenceId = 0x7A7;
break;
case kDirBottomLeft:
sequenceId = 0x82E;
break;
case kDirUpLeft:
sequenceId = 0x830;
break;
case kDirUpRight:
sequenceId = 0x82F;
break;
case kDirNone:
case kDirUnk4:
break;
}
}
break;
case gskUseDevice:
switch (_idleFacing) {
case kDirBottomRight:
sequenceId = 0x83A;
break;
case kDirBottomLeft:
sequenceId = 0x83C;
break;
case kDirUpLeft:
sequenceId = 0x840;
break;
case kDirUpRight:
sequenceId = 0x83E;
break;
case kDirNone:
case kDirUnk4:
break;
}
break;
case gskMoan1:
if (gridX > 0 && gridY > 0) {
if (_pos.y > gridY) {
if (_pos.x > gridX) {
sequenceId = 0x832;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x7AA;
_idleFacing = kDirBottomRight;
}
} else {
if (_pos.x > gridX) {
sequenceId = 0x832;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x7AA;
_idleFacing = kDirBottomRight;
}
}
} else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
sequenceId = 0x832;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x7AA;
_idleFacing = kDirBottomRight;
}
break;
case gskMoan2:
if (gridX > 0 && gridY > 0) {
if (_pos.y > gridY) {
if (_pos.x > gridX) {
sequenceId = 0x832;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x7AA;
_idleFacing = kDirBottomRight;
}
} else {
if (_pos.x > gridX) {
sequenceId = 0x832;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x7AA;
_idleFacing = kDirBottomRight;
}
}
} else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) {
sequenceId = 0x832;
_idleFacing = kDirBottomLeft;
} else {
sequenceId = 0x7AA;
_idleFacing = kDirBottomRight;
}
break;
}
return sequenceId | 0x10000;
}
void PlayerGnap::useJointOnPlatypus() {
_vm->setGrabCursorSprite(-1);
if (_vm->gnapPlatypusAction(1, 0, 0x107C1, 0)) {
_actionStatus = 100;
_vm->_gameSys->setAnimation(0, 0, 1);
_vm->_gameSys->setAnimation(0x10876, _vm->_plat->_id, 0);
_vm->_gameSys->insertSequence(0x10875, _id,
makeRid(_sequenceDatNum, _sequenceId), _id,
kSeqSyncWait, 0, 15 * (5 * _pos.x - 30), 48 * (_pos.y - 7));
_sequenceDatNum = 1;
_sequenceId = 0x875;
_vm->_gameSys->insertSequence(0x10876, _vm->_plat->_id,
_vm->_plat->_sequenceId | (_vm->_plat->_sequenceDatNum << 16), _vm->_plat->_id,
kSeqSyncWait, 0, 15 * (5 * _vm->_plat->_pos.x - 25), 48 * (_vm->_plat->_pos.y - 7));
_vm->_plat->_sequenceDatNum = 1;
_vm->_plat->_sequenceId = 0x876;
_vm->_plat->_idleFacing = kDirNone;
playSequence(0x107B5);
_vm->gnapWalkStep();
while (_vm->_gameSys->getAnimationStatus(0) != 2) {
_vm->updateMouseCursor();
_vm->gameUpdateTick();
}
_vm->_gameSys->setAnimation(0, 0, 0);
_actionStatus = -1;
} else {
playSequence(getSequenceId(gskScratchingHead, _vm->_plat->_pos.x, _vm->_plat->_pos.y) | 0x10000);
}
}
void PlayerGnap::kissPlatypus(int callback) {
if (_vm->gnapPlatypusAction(-1, 0, 0x107D1, callback)) {
_actionStatus = 100;
_vm->_gameSys->setAnimation(0, 0, 1);
_vm->_gameSys->setAnimation(0x10847, _id, 0);
_vm->_gameSys->insertSequence(0x10847, _id,
makeRid(_sequenceDatNum, _sequenceId), _id,
kSeqSyncWait, 0, 15 * (5 * _pos.x - 20) - (21 - _vm->_gridMinX), 48 * (_pos.y - 6) - (146 - _vm->_gridMinY));
_sequenceDatNum = 1;
_sequenceId = 0x847;
_vm->_gameSys->insertSequence(0x107CB, _vm->_plat->_id,
makeRid(_vm->_plat->_sequenceDatNum, _vm->_plat->_sequenceId), _vm->_plat->_id,
kSeqSyncWait, _vm->getSequenceTotalDuration(0x10847), 75 * _vm->_plat->_pos.x - _vm->_plat->_gridX, 48 * _vm->_plat->_pos.y - _vm->_plat->_gridY);
_vm->_plat->_sequenceDatNum = 1;
_vm->_plat->_sequenceId = 0x7CB;
_vm->_plat->_idleFacing = kDirNone;
playSequence(0x107B5);
while (_vm->_gameSys->getAnimationStatus(0) != 2) {
_vm->updateMouseCursor();
_vm->doCallback(callback);
_vm->gameUpdateTick();
}
_vm->_gameSys->setAnimation(0, 0, 0);
_actionStatus = -1;
} else {
playSequence(getSequenceId(gskScratchingHead, _vm->_plat->_pos.x, _vm->_plat->_pos.y) | 0x10000);
}
}
void PlayerGnap::useDeviceOnPlatypus() {
playSequence(makeRid(1, getSequenceId(gskPullOutDevice, _vm->_plat->_pos.x, _vm->_plat->_pos.y)));
if (_vm->_plat->_idleFacing != kDirNone) {
_vm->_gameSys->insertSequence(makeRid(1, 0x7D5), _vm->_plat->_id,
makeRid(_vm->_plat->_sequenceDatNum, _vm->_plat->_sequenceId), _vm->_plat->_id,
kSeqSyncWait, 0, 75 * _vm->_plat->_pos.x - _vm->_plat->_gridX, 48 * _vm->_plat->_pos.y - _vm->_plat->_gridY);
_vm->_plat->_sequenceId = 0x7D5;
_vm->_plat->_sequenceDatNum = 1;
} else {
_vm->_gameSys->insertSequence(makeRid(1, 0x7D4), _vm->_plat->_id,
makeRid(_vm->_plat->_sequenceDatNum, _vm->_plat->_sequenceId), _vm->_plat->_id,
kSeqSyncWait, 0, 75 * _vm->_plat->_pos.x - _vm->_plat->_gridX, 48 * _vm->_plat->_pos.y - _vm->_plat->_gridY);
_vm->_plat->_sequenceId = 0x7D4;
_vm->_plat->_sequenceDatNum = 1;
}
int newSequenceId = getSequenceId(gskUseDevice, 0, 0);
_vm->_gameSys->insertSequence(makeRid(1, newSequenceId), _id,
makeRid(_sequenceDatNum, _sequenceId), _id,
kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
_sequenceId = newSequenceId;
_sequenceDatNum = 1;
}
void PlayerGnap::initBrainPulseRndValue() {
_brainPulseRndValue = 2 * _vm->getRandom(10);
}
void PlayerGnap::playSequence(int sequenceId) {
_vm->_timers[2] = _vm->getRandom(30) + 20;
_vm->_timers[3] = 300;
_vm->gnapIdle();
_vm->_gameSys->insertSequence(sequenceId, _id,
makeRid(_sequenceDatNum, _sequenceId), _id,
kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
_sequenceId = ridToEntryIndex(sequenceId);
_sequenceDatNum = ridToDatIndex(sequenceId);
}
void PlayerGnap::updateIdleSequence() {
if (_actionStatus < 0) {
if (_vm->_timers[2] > 0) {
if (_vm->_timers[3] == 0) {
_vm->_timers[2] = 60;
_vm->_timers[3] = 300;
if (_idleFacing == kDirBottomRight) {
switch (_vm->getRandom(5)) {
case 0:
playSequence(0x107A6);
break;
case 1:
playSequence(0x107AA);
break;
case 2:
playSequence(0x10841);
break;
default:
playSequence(0x108A2);
break;
}
} else if (_idleFacing == kDirBottomLeft) {
if (_vm->getRandom(5) > 2)
playSequence(0x10832);
else
playSequence(0x10842);
}
}
} else {
_vm->_timers[2] = _vm->getRandom(30) + 20;
if (_idleFacing == kDirBottomRight) {
_vm->_gameSys->insertSequence(0x107BD, _id,
makeRid(_sequenceDatNum, _sequenceId), _id,
kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
_sequenceId = 0x7BD;
_sequenceDatNum = 1;
} else if (_idleFacing == kDirBottomLeft) {
_vm->_gameSys->insertSequence(0x107BE, _id,
makeRid(_sequenceDatNum, _sequenceId), _id,
kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
_sequenceId = 0x7BE;
_sequenceDatNum = 1;
}
}
} else {
_vm->_timers[2] = _vm->getRandom(30) + 20;
_vm->_timers[3] = 300;
}
}
void PlayerGnap::updateIdleSequence2() {
if (_actionStatus < 0) {
if (_vm->_timers[2] > 0) {
if (_vm->_timers[3] == 0) {
_vm->_timers[2] = 60;
_vm->_timers[3] = 300;
if (_idleFacing == kDirBottomRight) {
playSequence(0x107AA);
} else if (_idleFacing == kDirBottomLeft) {
playSequence(0x10832);
}
}
} else {
_vm->_timers[2] = _vm->getRandom(30) + 20;
if (_idleFacing == kDirBottomRight) {
_vm->_gameSys->insertSequence(0x107BD, _id,
makeRid(_sequenceDatNum, _sequenceId), _id,
kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
_sequenceId = 0x7BD;
_sequenceDatNum = 1;
} else if (_idleFacing == kDirBottomLeft) {
_vm->_gameSys->insertSequence(0x107BE, _id,
makeRid(_sequenceDatNum, _sequenceId), _id,
kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
_sequenceId = 0x7BE;
_sequenceDatNum = 1;
}
}
} else {
_vm->_timers[2] = _vm->getRandom(30) + 20;
_vm->_timers[3] = 300;
}
}
void PlayerGnap::initPos(int gridX, int gridY, Facing facing) {
_vm->_timers[2] = 30;
_vm->_timers[3] = 300;
_pos = Common::Point(gridX, gridY);
if (facing == kDirNone)
_idleFacing = kDirBottomRight;
else
_idleFacing = facing;
if (_idleFacing == kDirBottomLeft) {
_sequenceId = 0x7B8;
} else {
_sequenceId = 0x7B5;
_idleFacing = kDirBottomRight;
}
_id = 20 * _pos.y;
_sequenceDatNum = 1;
_vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y,
0, 0,
kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
}
int PlayerGnap::getWalkSequenceId(int deltaX, int deltaY) {
static const int walkSequenceIds[9] = {
0x7B2, 0x000, 0x7B4,
0x7AD, 0x000, 0x7AE,
0x7B1, 0x000, 0x7B3
};
// CHECKME This is a little weird
return walkSequenceIds[3 * deltaX + 3 + 1 + deltaY];
}
/************************************************************************************************/
PlayerPlat::PlayerPlat(GnapEngine * vm) : Character(vm) {}
int PlayerPlat::getSequenceId(int kind, int gridX, int gridY) {
// The original had 3 parameters, all always set to 0.
// The code to handle the other values has been removed.
int sequenceId = 0x7CB;
if (_idleFacing != kDirNone) {
sequenceId = 0x7CC;
_idleFacing = kDirUnk4;
}
return sequenceId | 0x10000;
}
void PlayerPlat::playSequence(int sequenceId) {
_vm->_gameSys->insertSequence(sequenceId, _id,
makeRid(_sequenceDatNum, _sequenceId), _id,
kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
_sequenceId = ridToEntryIndex(sequenceId);
_sequenceDatNum = ridToDatIndex(sequenceId);
}
void PlayerPlat::updateIdleSequence() {
if (_actionStatus < 0 && _vm->_gnap->_actionStatus < 0) {
if (_vm->_timers[0] > 0) {
if (_vm->_timers[1] == 0) {
_vm->_timers[1] = _vm->getRandom(20) + 30;
int rnd = _vm->getRandom(10);
if (_idleFacing != kDirNone) {
if (rnd != 0 || _sequenceId != 0x7CA) {
if (rnd != 1 || _sequenceId != 0x7CA)
playSequence(0x107CA);
else
playSequence(0x10845);
} else {
playSequence(0x107CC);
}
} else if (rnd != 0 || _sequenceId != 0x7C9) {
if (rnd != 1 || _sequenceId != 0x7C9) {
if (rnd != 2 || _sequenceId != 0x7C9)
playSequence(0x107C9);
else
playSequence(0x108A4);
} else {
playSequence(0x10844);
}
} else {
playSequence(0x107CB);
}
}
} else {
_vm->_timers[0] = _vm->getRandom(75) + 75;
_vm->platypusMakeRoom();
}
} else {
_vm->_timers[0] = 100;
_vm->_timers[1] = 35;
}
}
void PlayerPlat::updateIdleSequence2() {
if (_actionStatus < 0 && _vm->_gnap->_actionStatus < 0) {
if (_vm->_timers[0]) {
if (!_vm->_timers[1]) {
_vm->_timers[1] = _vm->getRandom(20) + 30;
if (_idleFacing != kDirNone) {
if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7CA)
playSequence(0x107CA);
else
playSequence(0x107CC);
} else {
if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7C9) {
playSequence(0x107C9);
} else {
playSequence(0x107CB);
}
}
}
} else {
_vm->_timers[0] = _vm->getRandom(75) + 75;
_vm->platypusMakeRoom();
}
} else {
_vm->_timers[0] = 100;
_vm->_timers[1] = 35;
}
}
void PlayerPlat::initPos(int gridX, int gridY, Facing facing) {
_vm->_timers[0] = 50;
_vm->_timers[1] = 20;
_pos = Common::Point(gridX, gridY);
if (facing == kDirNone)
_idleFacing = kDirNone;
else
_idleFacing = facing;
if (_idleFacing == kDirUnk4) {
_sequenceId = 0x7D1;
} else {
_sequenceId = 0x7C1;
_idleFacing = kDirNone;
}
_id = 20 * _pos.y;
_sequenceDatNum = 1;
_vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y,
0, 0,
kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY);
}
int PlayerPlat::getWalkSequenceId(int deltaX, int deltaY) {
static const int walkSequenceIds[9] = {
0x7C5, 0x000, 0x7C8,
0x7C4, 0x000, 0x7C7,
0x7C3, 0x000, 0x7C6
};
// CHECKME This is a little weird
return walkSequenceIds[3 * deltaX + 3 + 1 + deltaY];
}
} // End of namespace Gnap