scummvm/engines/gob/goblin_v1.cpp

713 lines
17 KiB
C++
Raw Normal View History

/* ScummVM - Scumm Interpreter
* Copyright (C) 2004 Ivan Dubrov
* Copyright (C) 2004-2006 The ScummVM project
*
* 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.
*
* $URL$
* $Id$
*
*/
#include "common/stdafx.h"
#include "common/endian.h"
#include "gob/gob.h"
#include "gob/goblin.h"
#include "gob/scenery.h"
#include "gob/map.h"
namespace Gob {
Goblin_v1::Goblin_v1(GobEngine *vm) : Goblin(vm) {
_rotStates[0][0] = 0; _rotStates[0][1] = 22; _rotStates[0][2] = 23; _rotStates[0][3] = 24;
_rotStates[1][0] = 13; _rotStates[1][1] = 2; _rotStates[1][2] = 12; _rotStates[1][3] = 14;
_rotStates[2][0] = 16; _rotStates[2][1] = 15; _rotStates[2][2] = 4; _rotStates[2][3] = 17;
_rotStates[3][0] = 27; _rotStates[3][1] = 25; _rotStates[3][2] = 26; _rotStates[3][3] = 6;
}
void Goblin_v1::freeObjects(void) {
int16 i;
int16 state;
int16 col;
for (i = 0; i < 16; i++) {
if (_soundData[i] == 0)
continue;
_vm->_snd->freeSoundDesc(_soundData[i]);
_soundData[i] = 0;
}
for (i = 0; i < 4; i++) {
if (_goblins[i] == 0)
continue;
_goblins[i]->stateMach = _goblins[i]->realStateMach;
for (state = 0; state < 40; state++) {
for (col = 0; col < 6; col++) {
delete _goblins[i]->stateMach[state][col];
_goblins[i]->stateMach[state][col] = 0;
}
}
if (i == 3) {
for (state = 40; state < 70; state++) {
delete _goblins[3]->stateMach[state][0];
_goblins[3]->stateMach[state][0] = 0;
}
}
delete[] _goblins[i]->stateMach;
delete _goblins[i];
_goblins[i] = 0;
}
for (i = 0; i < 20; i++) {
if (_objects[i] == 0)
continue;
_objects[i]->stateMach = _objects[i]->realStateMach;
for (state = 0; state < 40; state++) {
for (col = 0; col < 6; col++) {
delete _objects[i]->stateMach[state][col];
_objects[i]->stateMach[state][col] = 0;
}
}
delete[] _objects[i]->stateMach;
delete _objects[i];
_objects[i] = 0;
}
}
void Goblin_v1::placeObject(Gob_Object *objDesc, char animated,
int16 index, int16 x, int16 y, int16 state) {
int16 layer;
if (objDesc->stateMach[objDesc->state][0] != 0) {
objDesc->animation =
objDesc->stateMach[objDesc->state][0]->animation;
objDesc->noTick = 0;
objDesc->toRedraw = 1;
objDesc->doAnim = animated;
objDesc->maxTick = 1;
objDesc->tick = 1;
objDesc->curFrame = 0;
objDesc->type = 0;
objDesc->actionStartState = 0;
objDesc->nextState = -1;
objDesc->multState = -1;
objDesc->stateColumn = 0;
objDesc->curLookDir = 0;
objDesc->visible = 1;
objDesc->pickable = 0;
objDesc->unk14 = 0;
objDesc->relaxTime = _vm->_util->getRandom(30);
layer = objDesc->stateMach[objDesc->state][0]->layer;
_vm->_scenery->updateAnim(layer, 0, objDesc->animation, 0,
objDesc->xPos, objDesc->yPos, 0);
objDesc->order = _vm->_scenery->_toRedrawBottom / 24 + 3;
objDesc->left = objDesc->xPos;
objDesc->right = objDesc->xPos;
objDesc->dirtyLeft = objDesc->xPos;
objDesc->dirtyRight = objDesc->xPos;
objDesc->top = objDesc->yPos;
objDesc->bottom = objDesc->yPos;
objDesc->dirtyTop = objDesc->yPos;
objDesc->dirtyBottom = objDesc->yPos;
_vm->_util->listInsertBack(_objList, objDesc);
}
}
void Goblin_v1::initiateMove(Mult::Mult_Object *obj) {
_vm->_map->findNearestToDest(0);
_vm->_map->findNearestToGob(0);
_vm->_map->optimizePoints(0, 0, 0);
_pathExistence = _vm->_map->checkDirectPath(0, _vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
_pressedMapX, _pressedMapY);
if (_pathExistence == 3) {
if (_vm->_map->checkLongPath(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
_pressedMapX, _pressedMapY,
_vm->_map->_nearestWayPoint, _vm->_map->_nearestDest) == 0) {
_pathExistence = 0;
} else {
_vm->_map->_destX = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].x;
_vm->_map->_destY = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].y;
}
}
}
void Goblin_v1::movePathFind(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16 nextAct) {
if (_pathExistence == 1) {
_vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
_vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y;
if (_vm->_map->_curGoblinX == _pressedMapX &&
_vm->_map->_curGoblinY == _pressedMapY && _gobAction != 0) {
_readyToAct = 1;
_pathExistence = 0;
}
nextAct = _vm->_map->getDirection(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
_vm->_map->_destX, _vm->_map->_destY);
if (nextAct == 0)
_pathExistence = 0;
} else if (_pathExistence == 3) {
_vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
_vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y;
if (_vm->_map->_curGoblinX == _gobDestX && _vm->_map->_curGoblinY == _gobDestY) {
_pathExistence = 1;
_vm->_map->_destX = _pressedMapX;
_vm->_map->_destY = _pressedMapY;
} else {
if (_vm->_map->checkDirectPath(0, _vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
_gobDestX, _gobDestY) == 1) {
_vm->_map->_destX = _gobDestX;
_vm->_map->_destY = _gobDestY;
} else if (_vm->_map->_curGoblinX == _vm->_map->_destX && _vm->_map->_curGoblinY == _vm->_map->_destY) {
if (_vm->_map->_nearestWayPoint > _vm->_map->_nearestDest) {
_vm->_map->optimizePoints(0, 0, 0);
_vm->_map->_destX =
_vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].
x;
_vm->_map->_destY =
_vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].
y;
if (_vm->_map->_nearestWayPoint > _vm->_map->_nearestDest)
_vm->_map->_nearestWayPoint--;
} else if (_vm->_map->_nearestWayPoint < _vm->_map->_nearestDest) {
_vm->_map->optimizePoints(0, 0, 0);
_vm->_map->_destX =
_vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].
x;
_vm->_map->_destY =
_vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].
y;
if (_vm->_map->_nearestWayPoint < _vm->_map->_nearestDest)
_vm->_map->_nearestWayPoint++;
} else {
if (_vm->_map->checkDirectPath(0, _vm->_map->_curGoblinX,
_vm->_map->_curGoblinY, _gobDestX,
_gobDestY) == 3 && _vm->_map->getPass(_pressedMapX, _pressedMapY) != 0) {
_vm->_map->_destX = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].x;
_vm->_map->_destY = _vm->_map->_wayPoints[_vm->_map->_nearestWayPoint].y;
} else {
_pathExistence = 1;
_vm->_map->_destX = _pressedMapX;
_vm->_map->_destY = _pressedMapY;
}
}
}
nextAct =
_vm->_map->getDirection(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY,
_vm->_map->_destX, _vm->_map->_destY);
}
}
if (_readyToAct != 0 && (_gobAction == 3 || _gobAction == 4))
nextAct = 0x4dc8;
switch (nextAct) {
case Map::kDirW:
gobDesc->nextState = rotateState(gobDesc->curLookDir, 0);
break;
case Map::kDirE:
gobDesc->nextState = rotateState(gobDesc->curLookDir, 4);
break;
case 16:
gobDesc->nextState = 16;
break;
case 23:
gobDesc->nextState = 23;
break;
case Map::kDirN:
if (_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY - 1) == 6 &&
_currentGoblin != 1) {
_pathExistence = 0;
break;
}
if (_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY) == 3) {
gobDesc->nextState = 8;
break;
}
if (_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY) == 6 &&
_currentGoblin == 1) {
gobDesc->nextState = 28;
break;
}
gobDesc->nextState = rotateState(gobDesc->curLookDir, 2);
break;
case Map::kDirS:
if (_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY + 1) == 6 &&
_currentGoblin != 1) {
_pathExistence = 0;
break;
}
if (_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY) == 3) {
gobDesc->nextState = 9;
break;
}
if (_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY) == 6 &&
_currentGoblin == 1) {
gobDesc->nextState = 29;
break;
}
gobDesc->nextState = rotateState(gobDesc->curLookDir, 6);
break;
case Map::kDirSE:
if (_vm->_map->getPass(_vm->_map->_curGoblinX + 1, _vm->_map->_curGoblinY + 1) == 6 &&
_currentGoblin != 1) {
_pathExistence = 0;
break;
}
gobDesc->nextState = 5;
if (gobDesc->curLookDir == 4)
break;
gobDesc->nextState = rotateState(gobDesc->curLookDir, 4);
break;
case Map::kDirSW:
if (_vm->_map->getPass(_vm->_map->_curGoblinX - 1, _vm->_map->_curGoblinY + 1) == 6 &&
_currentGoblin != 1) {
_pathExistence = 0;
break;
}
gobDesc->nextState = 7;
if (gobDesc->curLookDir == 0)
break;
gobDesc->nextState = rotateState(gobDesc->curLookDir, 0);
break;
case Map::kDirNW:
if (_vm->_map->getPass(_vm->_map->_curGoblinX - 1, _vm->_map->_curGoblinY - 1) == 6 &&
_currentGoblin != 1) {
_pathExistence = 0;
break;
}
gobDesc->nextState = 1;
if (gobDesc->curLookDir == 0)
break;
gobDesc->nextState = rotateState(gobDesc->curLookDir, 0);
break;
case Map::kDirNE:
if (_vm->_map->getPass(_vm->_map->_curGoblinX + 1, _vm->_map->_curGoblinY - 1) == 6 &&
_currentGoblin != 1) {
_pathExistence = 0;
break;
}
gobDesc->nextState = 3;
if (gobDesc->curLookDir == 4)
break;
gobDesc->nextState = rotateState(gobDesc->curLookDir, 4);
break;
case 0x4dc8:
if (_currentGoblin == 0 && _gobAction == 3
&& _itemIndInPocket == -1) {
_destItemId = -1;
_readyToAct = 0;
break;
}
if (_currentGoblin == 0 && _gobAction == 4 &&
_itemIndInPocket == -1 && _destActionItem == 0) {
gobDesc->multState = 104;
_destItemId = -1;
_readyToAct = 0;
break;
}
if (_currentGoblin == 0 && _gobAction == 4 &&
_itemIndInPocket == -1 && _destActionItem != 0 &&
_itemToObject[_destActionItem] != -1 &&
_objects[_itemToObject[_destActionItem]]->
pickable == 0) {
gobDesc->multState = 104;
_destItemId = -1;
_readyToAct = 0;
break;
}
switch (_vm->_map->_itemPoses[_destActionItem].orient) {
case 0:
case -4:
gobDesc->nextState = 10;
gobDesc->curLookDir = 0;
_destItemId = -1;
break;
case -1:
case 4:
gobDesc->nextState = 11;
gobDesc->curLookDir = 4;
_destItemId = -1;
break;
}
break;
default:
if (_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY) == 3 ||
(_vm->_map->getPass(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY) == 6
&& _currentGoblin == 1)) {
gobDesc->nextState = 20;
break;
}
switch (gobDesc->curLookDir) {
case 2:
case 4:
gobDesc->nextState = 18;
break;
case 6:
case 0:
gobDesc->nextState = 19;
break;
}
break;
}
return;
}
void Goblin_v1::moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc,
int16 nextAct, int16 framesCount) {
int16 i;
int16 newX;
int16 newY;
int16 flag;
movePathFind(0, gobDesc, nextAct);
gobDesc->curFrame++;
if (gobDesc->curFrame == 1)
gobDesc->actionStartState = gobDesc->state;
if (_goesAtTarget == 0
&& gobDesc->stateMach == gobDesc->realStateMach) {
switch (gobDesc->state) {
case 0:
case 1:
case 7:
case 13:
case 16:
case 27:
gobDesc->curLookDir = 0;
break;
case 3:
case 4:
case 5:
case 12:
case 23:
case 26:
gobDesc->curLookDir = 4;
break;
case 28:
if (_currentGoblin != 1)
break;
gobDesc->curLookDir = 2;
break;
case 2:
case 8:
case 15:
case 22:
case 25:
gobDesc->curLookDir = 2;
break;
case 29:
if (_currentGoblin != 1)
break;
gobDesc->curLookDir = 6;
break;
case 6:
case 9:
case 14:
case 17:
case 24:
gobDesc->curLookDir = 6;
break;
}
}
if (gobDesc->state >= 0 && gobDesc->state < 10 &&
gobDesc->stateMach == gobDesc->realStateMach &&
(gobDesc->curFrame == 3 || gobDesc->curFrame == 6)) {
_vm->_snd->speakerOn(10 * _vm->_util->getRandom(3) + 50, 5);
}
if (_currentGoblin == 0
&& gobDesc->stateMach == gobDesc->realStateMach
&& (gobDesc->state == 10 || gobDesc->state == 11)
&& gobDesc->curFrame == 9) {
_vm->_snd->stopSound(0);
if (_itemIndInPocket != -1) {
_vm->_snd->playSample(_soundData[14], 1, 9000);
}
if (_itemIndInPocket == -1) {
_vm->_snd->playSample(_soundData[14], 1, 5000);
}
}
if (_boreCounter++ == 120) {
_boreCounter = 0;
for (i = 0; i < 3; i++)
showBoredom(i);
}
if (gobDesc->multState != -1 && gobDesc->curFrame == framesCount &&
gobDesc->state != gobDesc->multState) {
gobDesc->nextState = gobDesc->multState;
gobDesc->multState = -1;
newX =
_vm->_scenery->_animations[gobDesc->animation].
layers[_gobStateLayer].animDeltaX + gobDesc->xPos;
newY =
_vm->_scenery->_animations[gobDesc->animation].
layers[_gobStateLayer].animDeltaY + gobDesc->yPos;
_gobStateLayer = nextLayer(gobDesc);
gobDesc->xPos = newX;
gobDesc->yPos = newY;
} else {
if (gobDesc->curFrame == 3 &&
gobDesc->stateMach == gobDesc->realStateMach &&
(gobDesc->state < 10 ||
(_currentGoblin == 1 && (gobDesc->state == 28
|| gobDesc->state == 29))
)) {
flag = 0;
if (_forceNextState[0] != -1) {
gobDesc->nextState = _forceNextState[0];
for (i = 0; i < 9; i++)
_forceNextState[i] =
_forceNextState[i + 1];
}
_vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
_vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y;
if (gobDesc->nextState != gobDesc->state) {
_gobStateLayer = nextLayer(gobDesc);
flag = 1;
}
switch (gobDesc->state) {
case 0:
_gobPositions[_currentGoblin].x--;
break;
case 2:
case 8:
_gobPositions[_currentGoblin].y--;
break;
case 4:
_gobPositions[_currentGoblin].x++;
break;
case 6:
case 9:
_gobPositions[_currentGoblin].y++;
break;
case 1:
_gobPositions[_currentGoblin].x--;
_gobPositions[_currentGoblin].y--;
break;
case 3:
_gobPositions[_currentGoblin].x++;
_gobPositions[_currentGoblin].y--;
break;
case 5:
_gobPositions[_currentGoblin].x++;
_gobPositions[_currentGoblin].y++;
break;
case 7:
_gobPositions[_currentGoblin].x--;
_gobPositions[_currentGoblin].y++;
break;
case 38:
_gobPositions[_currentGoblin].y++;
break;
}
if (_currentGoblin == 1) {
if (gobDesc->state == 28)
_gobPositions[1].y--;
if (gobDesc->state == 29)
_gobPositions[1].y++;
}
if (flag != 0) {
_vm->_scenery->updateAnim(_gobStateLayer, 0,
gobDesc->animation, 0, gobDesc->xPos,
gobDesc->yPos, 0);
gobDesc->yPos =
(_vm->_map->_curGoblinY + 1) * 6 -
(_vm->_scenery->_toRedrawBottom - _vm->_scenery->_animTop);
gobDesc->xPos =
_vm->_map->_curGoblinX * 12 - (_vm->_scenery->_toRedrawLeft -
_vm->_scenery->_animLeft);
}
if ((gobDesc->state == 10 || gobDesc->state == 11)
&& _currentGoblin != 0)
_goesAtTarget = 1;
}
if (gobDesc->curFrame != framesCount)
return;
if (_forceNextState[0] != -1) {
gobDesc->nextState = _forceNextState[0];
for (i = 0; i < 10; i++)
_forceNextState[i] =
_forceNextState[i + 1];
}
_vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x;
_vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y;
_gobStateLayer = nextLayer(gobDesc);
if (gobDesc->stateMach == gobDesc->realStateMach) {
switch (gobDesc->nextState) {
case 0:
_gobPositions[_currentGoblin].x--;
break;
case 2:
case 8:
_gobPositions[_currentGoblin].y--;
break;
case 4:
_gobPositions[_currentGoblin].x++;
break;
case 6:
case 9:
_gobPositions[_currentGoblin].y++;
break;
case 1:
_gobPositions[_currentGoblin].x--;
_gobPositions[_currentGoblin].y--;
break;
case 3:
_gobPositions[_currentGoblin].x++;
_gobPositions[_currentGoblin].y--;
break;
case 5:
_gobPositions[_currentGoblin].x++;
_gobPositions[_currentGoblin].y++;
break;
case 7:
_gobPositions[_currentGoblin].x--;
_gobPositions[_currentGoblin].y++;
break;
case 38:
_gobPositions[_currentGoblin].y++;
break;
}
if (_currentGoblin == 1) {
if (gobDesc->nextState == 28)
_gobPositions[1].y--;
if (gobDesc->nextState == 29)
_gobPositions[1].y++;
}
}
_vm->_scenery->updateAnim(_gobStateLayer, 0, gobDesc->animation, 0,
gobDesc->xPos, gobDesc->yPos, 0);
gobDesc->yPos =
(_vm->_map->_curGoblinY + 1) * 6 - (_vm->_scenery->_toRedrawBottom -
_vm->_scenery->_animTop);
gobDesc->xPos =
_vm->_map->_curGoblinX * 12 - (_vm->_scenery->_toRedrawLeft - _vm->_scenery->_animLeft);
if ((gobDesc->state == 10 || gobDesc->state == 11)
&& _currentGoblin != 0)
_goesAtTarget = 1;
}
return;
}
} // End of namespace Gob