/* 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. * * $Header$ * */ #include "gob/gob.h" #include "gob/goblin.h" #include "gob/inter.h" #include "gob/global.h" #include "gob/draw.h" #include "gob/video.h" #include "gob/anim.h" #include "gob/scenery.h" #include "gob/map.h" #include "gob/sound.h" #include "gob/game.h" #include "gob/dataio.h" #include "gob/cdrom.h" #include "gob/music.h" namespace Gob { Goblin::Goblin(GobEngine *vm) : _vm(vm) { _goesAtTarget = 0; _readyToAct = 0; _gobAction = 0; _itemIndInPocket = 5; _itemIdInPocket = 2; _itemByteFlag = 0; _destItemId = -1; _destActionItem = 0; _actDestItemDesc = 0; _forceNextState[0] = -1; _forceNextState[1] = -1; _forceNextState[2] = -1; _forceNextState[3] = -1; _forceNextState[4] = -1; _forceNextState[5] = -1; _forceNextState[6] = -1; _forceNextState[7] = 0; _forceNextState[8] = 0; _forceNextState[9] = 0; _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; _boreCounter = 0; _positionedGob = 5; _noPick = 0; _objList = 0; int i; for (i = 0; i < 4; i++) _goblins[i] = 0; _currentGoblin = 0; for (i = 0; i < 16; i++) _soundData[i] = 0; for (i = 0; i < 3; i++) { _gobPositions[i].x = 0; _gobPositions[i].y = 0; } _gobDestX = 0; _gobDestY = 0; _pressedMapX = 0; _pressedMapY = 0; _pathExistence = 0; _some0ValPtr = 0; _gobRetVarPtr = 0; _curGobVarPtr = 0; _curGobXPosVarPtr = 0; _curGobYPosVarPtr = 0; _itemInPocketVarPtr = 0; _curGobStateVarPtr = 0; _curGobFrameVarPtr = 0; _curGobMultStateVarPtr = 0; _curGobNextStateVarPtr = 0; _curGobScrXVarPtr = 0; _curGobScrYVarPtr = 0; _curGobLeftVarPtr = 0; _curGobTopVarPtr = 0; _curGobRightVarPtr = 0; _curGobBottomVarPtr = 0; _curGobDoAnimVarPtr = 0; _curGobOrderVarPtr = 0; _curGobNoTickVarPtr = 0; _curGobTypeVarPtr = 0; _curGobMaxTickVarPtr = 0; _curGobTickVarPtr = 0; _curGobActStartStateVarPtr = 0; _curGobLookDirVarPtr = 0; _curGobPickableVarPtr = 0; _curGobRelaxVarPtr = 0; _curGobMaxFrameVarPtr = 0; _destItemStateVarPtr = 0; _destItemFrameVarPtr = 0; _destItemMultStateVarPtr = 0; _destItemNextStateVarPtr = 0; _destItemScrXVarPtr = 0; _destItemScrYVarPtr = 0; _destItemLeftVarPtr = 0; _destItemTopVarPtr = 0; _destItemRightVarPtr = 0; _destItemBottomVarPtr = 0; _destItemDoAnimVarPtr = 0; _destItemOrderVarPtr = 0; _destItemNoTickVarPtr = 0; _destItemTypeVarPtr = 0; _destItemMaxTickVarPtr = 0; _destItemTickVarPtr = 0; _destItemActStartStVarPtr = 0; _destItemLookDirVarPtr = 0; _destItemPickableVarPtr = 0; _destItemRelaxVarPtr = 0; _destItemMaxFrameVarPtr = 0; _destItemType = 0; _destItemState = 0; for (i = 0; i < 20; i++) { _itemToObject[i] = 0; _objects[i] = 0; } _objCount = 0; _gobsCount = 0; } char Goblin::rotateState(int16 from, int16 to) { return _rotStates[from / 2][to / 2]; } int16 Goblin::peekGoblin(Gob_Object *_curGob) { Util::ListNode *ptr; Gob_Object *desc; int16 index; int16 i; ptr = _objList->pHead; index = 0; while (ptr != 0) { desc = (Gob_Object *) ptr->pData; if (desc != _curGob) { for (i = 0; i < 3; i++) { if (desc != _goblins[i]) continue; if (_vm->_global->_inter_mouseX < desc->right && _vm->_global->_inter_mouseX > desc->left && _vm->_global->_inter_mouseY < desc->bottom && _vm->_global->_inter_mouseY > desc->top) { index = i + 1; } } } ptr = ptr->pNext; } return index; } void Goblin::initList(void) { _objList = new Util::List; _objList->pHead = 0; _objList->pTail = 0; } void Goblin::sortByOrder(Util::List *list) { Util::ListNode *ptr; Util::ListNode *ptr2; ptr = list->pHead; while (ptr->pNext != 0) { for (ptr2 = ptr->pNext; ptr2 != 0; ptr2 = ptr2->pNext) { Gob_Object *objDesc = (Gob_Object *)ptr->pData; Gob_Object *objDesc2 = (Gob_Object *)ptr2->pData; if (objDesc->order <= objDesc2->order) { if (objDesc->order != objDesc2->order) continue; if (objDesc->bottom <= objDesc2->bottom) { if (objDesc->bottom != objDesc2->bottom) continue; if (objDesc != _goblins[_currentGoblin]) continue; } } SWAP(ptr->pData, ptr2->pData); } ptr = ptr->pNext; } } void Goblin::playSound(Snd::SoundDesc *snd, int16 repCount, int16 freq) { if (snd != 0) { _vm->_snd->stopSound(0); _vm->_snd->playSample(snd, repCount, freq); } } void Goblin::drawObjects(void) { Util::ListNode *ptr; Util::ListNode *ptr2; Gob_Object *objDesc; Gob_Object *gobDesc2; int16 layer; ptr = _objList->pHead; for (ptr = _objList->pHead; ptr != 0; ptr = ptr->pNext) { objDesc = (Gob_Object *) ptr->pData; if (objDesc->type == 3) objDesc->toRedraw = 1; else if (objDesc->type == 1) objDesc->toRedraw = 0; } for (ptr = _objList->pHead; ptr != 0; ptr = ptr->pNext) { objDesc = (Gob_Object *) ptr->pData; if (objDesc->toRedraw == 0) continue; _vm->_video->drawSprite(_vm->_anim->_animSurf, _vm->_draw->_backSurface, objDesc->left, objDesc->top, objDesc->right, objDesc->bottom, objDesc->left, objDesc->top, 0); _vm->_draw->invalidateRect(objDesc->left, objDesc->top, objDesc->right, objDesc->bottom); if (objDesc->type != 0) continue; layer = objDesc->stateMach[objDesc->state][objDesc->stateColumn]-> layer; _vm->_scenery->updateAnim(layer, objDesc->curFrame, objDesc->animation, 0, objDesc->xPos, objDesc->yPos, 0); if (_vm->_scenery->_toRedrawLeft == -12345) { objDesc->dirtyLeft = objDesc->left; objDesc->dirtyRight = objDesc->right; objDesc->dirtyTop = objDesc->top; objDesc->dirtyBottom = objDesc->bottom; } else { objDesc->dirtyLeft = MIN(objDesc->left, _vm->_scenery->_toRedrawLeft); objDesc->dirtyRight = MAX(objDesc->right, _vm->_scenery->_toRedrawRight); objDesc->dirtyTop = MIN(objDesc->top, _vm->_scenery->_toRedrawTop); objDesc->dirtyBottom = MAX(objDesc->bottom, _vm->_scenery->_toRedrawBottom); } objDesc->dirtyLeft = 0; objDesc->dirtyRight = 319; objDesc->dirtyTop = 0; objDesc->dirtyBottom = 199; } sortByOrder(_objList); for (ptr = _objList->pHead; ptr != 0; ptr = ptr->pNext) { objDesc = (Gob_Object *) ptr->pData; if (objDesc->toRedraw) { layer = objDesc->stateMach[objDesc->state][objDesc-> stateColumn]->layer; if (objDesc->type == 0) { if (objDesc->visible == 0) { _vm->_scenery->updateAnim(layer, objDesc->curFrame, objDesc->animation, 0, objDesc->xPos, objDesc->yPos, 0); } else { _vm->_scenery->updateAnim(layer, objDesc->curFrame, objDesc->animation, 2, objDesc->xPos, objDesc->yPos, 1); } if (_vm->_scenery->_toRedrawLeft == -12345) { objDesc->left = 0; objDesc->top = 0; objDesc->right = 0; objDesc->bottom = 0; } else { _vm->_draw->invalidateRect(_vm->_scenery->_toRedrawLeft, _vm->_scenery->_toRedrawTop, _vm->_scenery->_toRedrawRight, _vm->_scenery->_toRedrawBottom); objDesc->left = _vm->_scenery->_toRedrawLeft; objDesc->top = _vm->_scenery->_toRedrawTop; objDesc->right = _vm->_scenery->_toRedrawRight; objDesc->bottom = _vm->_scenery->_toRedrawBottom; _vm->_scenery->updateStatic(objDesc->order); } } else { objDesc->left = 0; objDesc->top = 0; objDesc->right = 0; objDesc->bottom = 0; objDesc->type = 1; } continue; } if (objDesc->type == 0 && objDesc->visible != 0) { for (ptr2 = _objList->pHead; ptr2 != 0; ptr2 = ptr2->pNext) { gobDesc2 = (Gob_Object *) ptr2->pData; if (gobDesc2->toRedraw == 0) continue; if (objDesc->right < gobDesc2->dirtyLeft) continue; if (gobDesc2->dirtyRight < objDesc->left) continue; if (objDesc->bottom < gobDesc2->dirtyTop) continue; if (gobDesc2->dirtyBottom < objDesc->top) continue; _vm->_scenery->_toRedrawLeft = gobDesc2->dirtyLeft; _vm->_scenery->_toRedrawRight = gobDesc2->dirtyRight; _vm->_scenery->_toRedrawTop = gobDesc2->dirtyTop; _vm->_scenery->_toRedrawBottom = gobDesc2->dirtyBottom; layer = objDesc->stateMach[objDesc-> state][objDesc->stateColumn]->layer; _vm->_scenery->updateAnim(layer, objDesc->curFrame, objDesc->animation, 4, objDesc->xPos, objDesc->yPos, 1); _vm->_scenery->updateStatic(objDesc->order); } } } for (ptr = _objList->pHead; ptr != 0; ptr = ptr->pNext) { objDesc = (Gob_Object *) ptr->pData; if (objDesc->toRedraw == 0 || objDesc->type == 1) continue; Gob_State *state = objDesc->stateMach[objDesc->state][objDesc->stateColumn]; int16 sndFrame; int16 sndItem; int16 freq; int16 repCount; if (state->sndFrame & 0xff00) { // There are two frames which trigger a sound effect, // so everything has to be encoded in one byte each. // Note that the frequency is multiplied by 100, not - // as I would have thought, 0x100. sndFrame = (state->sndFrame >> 8) & 0xff; sndItem = (state->sndItem >> 8) & 0xff; freq = 100 * ((state->freq >> 8) & 0xff); repCount = (state->repCount >> 8) & 0xff; if (objDesc->curFrame == sndFrame) { if (sndItem != 0xff) { playSound(_soundData[sndItem], repCount, freq); } } sndFrame = state->sndFrame & 0xff; sndItem = state->sndItem & 0xff; freq = 100 * (state->freq & 0xff); repCount = state->repCount & 0xff; if (objDesc->curFrame == sndFrame) { if (sndItem != 0xff) { playSound(_soundData[sndItem], repCount, freq); } } } else { // There is only one, so frequency etc. are used as is. sndFrame = state->sndFrame; sndItem = state->sndItem; freq = state->freq; repCount = state->repCount; if (objDesc->curFrame == sndFrame) { if (sndItem != -1) { playSound(_soundData[sndItem], repCount, freq); } } } } // _vm->_scenery->updateAnim(27, 0, 9, 2, 10, 10, 1); } void Goblin::animateObjects(void) { Util::ListNode *node; Gob_Object *objDesc; Scenery::AnimLayer *pLayer; int16 layer; for (node = _objList->pHead; node != 0; node = node->pNext) { objDesc = (Gob_Object *) node->pData; if (objDesc->doAnim != 1 || objDesc->type != 0) continue; if (objDesc->noTick != 0) continue; if (objDesc->tick < objDesc->maxTick) objDesc->tick++; if (objDesc->tick >= objDesc->maxTick) { objDesc->tick = 1; objDesc->curFrame++; layer = objDesc->stateMach[objDesc->state][0]->layer; pLayer = _vm->_scenery->_animations[objDesc->animation].layers[layer]; if (objDesc->curFrame < pLayer->framesCount) continue; objDesc->curFrame = 0; objDesc->xPos += pLayer->animDeltaX; objDesc->yPos += pLayer->animDeltaY; if (objDesc->nextState == -1 && objDesc->multState == -1 && objDesc->unk14 == 0) { objDesc->toRedraw = 0; objDesc->curFrame = pLayer->framesCount - 1; } if (objDesc->multState != -1) { if (objDesc->multState > 39) { objDesc->stateMach = _goblins[(int)(objDesc->multObjIndex)]->stateMach; objDesc->state = objDesc->multState - 40; } else { objDesc->stateMach = objDesc->realStateMach; objDesc->state = objDesc->multState; } objDesc->animation = objDesc->stateMach[objDesc->state][0]-> animation; objDesc->multState = -1; } else { if (objDesc->nextState == -1) continue; objDesc->stateMach = objDesc->realStateMach; objDesc->state = objDesc->nextState; objDesc->animation = objDesc->stateMach[objDesc->state][0]-> animation; objDesc->nextState = -1; } objDesc->toRedraw = 1; } } } void Goblin::placeObject(Gob_Object *objDesc, char animated) { 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); } } int16 Goblin::getObjMaxFrame(Gob_Object * objDesc) { int16 layer; layer = objDesc->stateMach[objDesc->state][0]->layer; return _vm->_scenery->_animations[objDesc->animation].layers[layer]->framesCount - 1; } int16 Goblin::objIntersected(Gob_Object *obj1, Gob_Object *obj2) { if (obj1->type == 1 || obj2->type == 1) return 0; if (obj1->right < obj2->left) return 0; if (obj1->left > obj2->right) return 0; if (obj1->bottom < obj2->top) return 0; if (obj1->top > obj2->bottom) return 0; return 1; } void Goblin::setMultStates(Gob_Object * gobDesc) { gobDesc->stateMach = _goblins[(int)gobDesc->multObjIndex]->stateMach; } int16 Goblin::nextLayer(Gob_Object *gobDesc) { if (gobDesc->nextState == 10) gobDesc->curLookDir = 0; if (gobDesc->nextState == 11) gobDesc->curLookDir = 4; if (gobDesc->nextState > 39) { setMultStates(gobDesc); } else { gobDesc->stateMach = gobDesc->realStateMach; } gobDesc->curFrame = 0; if (gobDesc->nextState > 39) gobDesc->state = gobDesc->nextState - 40; else gobDesc->state = gobDesc->nextState; gobDesc->animation = gobDesc->stateMach[gobDesc->state][0]->animation; return gobDesc->stateMach[gobDesc->state][0]->layer; } void Goblin::showBoredom(int16 gobIndex) { Gob_Object *gobDesc; int16 frame; int16 frameCount; int16 layer; int16 state; int16 boreFlag; gobDesc = _goblins[gobIndex]; layer = gobDesc->stateMach[gobDesc->state][0]->layer; frameCount = _vm->_scenery->_animations[gobDesc->animation].layers[layer]->framesCount; state = gobDesc->state; frame = gobDesc->curFrame; gobDesc->noTick = 0; gobDesc->toRedraw = 1; boreFlag = 1 << _vm->_util->getRandom(7); if (gobIndex != _currentGoblin && _vm->_util->getRandom(3) != 0) { if (state == 21) { if ((boreFlag & 16) || (boreFlag & 32)) { gobDesc->multState = 92 + gobIndex; } else if (boreFlag & 1) { gobDesc->multState = 86 + gobIndex; } else if (boreFlag & 2) { gobDesc->multState = 80 + gobIndex; } else if (boreFlag & 4) { gobDesc->multState = 89 + gobIndex; } else if (boreFlag & 8) { gobDesc->multState = 104 + gobIndex; } } gobDesc->nextState = 21; } else if (state >= 18 && state <= 21 && VAR(59) == 0) { if (state == 30 || state == 31) // ??? return; if (frame != frameCount) return; gobDesc->multState = 104 + gobIndex; } } // index - goblin to select+1 // index==0 - switch to next void Goblin::switchGoblin(int16 index) { int16 next; int16 tmp; debug(4, "switchGoblin"); if (VAR(59) != 0) return; if (_goblins[_currentGoblin]->state <= 39 && _goblins[_currentGoblin]->curFrame != 0) return; if (index != 0 && _goblins[index - 1]->type != 0) return; if (index == 0) next = (_currentGoblin + 1) % 3; else next = index - 1; if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3 || _vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 6) return; if (_goblins[(_currentGoblin + 1) % 3]->type != 0 && _goblins[(_currentGoblin + 2) % 3]->type != 0) return; _gobPositions[_currentGoblin].x = _vm->_map->_curGoblinX; _gobPositions[_currentGoblin].y = _vm->_map->_curGoblinY; _goblins[_currentGoblin]->doAnim = 1; _goblins[_currentGoblin]->nextState = 21; nextLayer(_goblins[_currentGoblin]); _currentGoblin = next; if (_goblins[_currentGoblin]->type != 0) _currentGoblin = (_currentGoblin + 1) % 3; _goblins[_currentGoblin]->doAnim = 0; if (_goblins[_currentGoblin]->curLookDir == 4) _goblins[_currentGoblin]->nextState = 18; else _goblins[_currentGoblin]->nextState = 19; _goblins[_currentGoblin]->toRedraw = 1; nextLayer(_goblins[_currentGoblin]); tmp = _gobPositions[_currentGoblin].x; _pressedMapX = tmp; _vm->_map->_destX = tmp; _gobDestX = tmp; _vm->_map->_curGoblinX = tmp; tmp = _gobPositions[_currentGoblin].y; _pressedMapY = tmp; _vm->_map->_destY = tmp; _gobDestY = tmp; _vm->_map->_curGoblinY = tmp; *_curGobVarPtr = _currentGoblin; _pathExistence = 0; _readyToAct = 0; } void Goblin::adjustDest(int16 posX, int16 posY) { int16 resDelta; int16 resDeltaDir; int16 resDeltaPix; int16 deltaPix; int16 i; if (_vm->_map->_passMap[_pressedMapY][_pressedMapX] == 0 && (_gobAction == 0 || _vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0)) { resDelta = -1; resDeltaDir = 0; resDeltaPix = 0; for (i = 1; i <= _pressedMapX && _vm->_map->_passMap[_pressedMapY][_pressedMapX - i] == 0; i++); if (i <= _pressedMapX) { resDeltaPix = (i - 1) * 12 + (posX % 12) + 1; resDelta = i; } for (i = 1; (i + _pressedMapX) < Map::kMapWidth && _vm->_map->_passMap[_pressedMapY][_pressedMapX + i] == 0; i++); if (_pressedMapX + i < Map::kMapWidth) { deltaPix = (i * 12) - (posX % 12); if (resDelta == -1 || deltaPix < resDeltaPix) { resDeltaPix = deltaPix; resDelta = i; resDeltaDir = 1; } } for (i = 1; (i + _pressedMapY) < Map::kMapHeight && _vm->_map->_passMap[_pressedMapY + i][_pressedMapX] == 0; i++); if (_pressedMapY + i < Map::kMapHeight) { deltaPix = (i * 6) - (posY % 6); if (resDelta == -1 || deltaPix < resDeltaPix) { resDeltaPix = deltaPix; resDelta = i; resDeltaDir = 2; } } for (i = 1; i <= _pressedMapY && _vm->_map->_passMap[_pressedMapY - i][_pressedMapX] == 0; i++); if (i <= _pressedMapY) { deltaPix = (i * 6) + (posY % 6); if (resDelta == -1 || deltaPix < resDeltaPix) { resDeltaPix = deltaPix; resDelta = i; resDeltaDir = 3; } } switch (resDeltaDir) { case 0: _pressedMapX -= resDelta; break; case 1: _pressedMapX += resDelta; break; case 2: _pressedMapY += resDelta; break; case 3: _pressedMapY -= resDelta; break; } } } void Goblin::adjustTarget(void) { if (_gobAction == 4 && _vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0) { if (_pressedMapY > 0 && _vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0) { _pressedMapY--; } else if (_pressedMapX < Map::kMapWidth - 1 && _vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0) { _pressedMapX++; } else if (_pressedMapX < Map::kMapWidth - 1 && _pressedMapY > 0 && _vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0) { _pressedMapY--; _pressedMapX++; } } } void Goblin::targetDummyItem(Gob_Object *gobDesc) { if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0 && _vm->_map->_passMap[_pressedMapY][_pressedMapX] == 1) { if (gobDesc->curLookDir == 0) { _vm->_map->_itemPoses[0].x = _pressedMapX; _vm->_map->_itemPoses[0].y = _pressedMapY; _vm->_map->_itemPoses[0].orient = -4; } else { _vm->_map->_itemPoses[0].x = _pressedMapX; _vm->_map->_itemPoses[0].y = _pressedMapY; _vm->_map->_itemPoses[0].orient = -1; } } } void Goblin::targetItem(void) { int16 tmpX; int16 tmpY; int16 items; int16 layer; int16 tmpPosX; int16 tmpPosY; Gob_Object *itemDesc; if (_gobAction == 3 || _gobAction == 4) { items = _vm->_map->_itemsMap[_pressedMapY][_pressedMapX]; if (_gobAction == 4 && (items & 0xff00) != 0 && _objects[_itemToObject[(items & 0xff00) >> 8]]-> pickable == 1) { _destItemId = (items & 0xff00) >> 8; _destActionItem = (items & 0xff00) >> 8; _itemByteFlag = 1; } else if ((items & 0xff) == 0) { _destItemId = (items & 0xff00) >> 8; _destActionItem = (items & 0xff00) >> 8; _itemByteFlag = 1; } else if (_gobAction == 3 && _currentGoblin == 2 && (items & 0xff00) != 0) { _destItemId = (items & 0xff00) >> 8; _destActionItem = (items & 0xff00) >> 8; _itemByteFlag = 1; } else { _destItemId = items & 0xff; _destActionItem = items & 0xff; _itemByteFlag = 0; } _pressedMapY = _vm->_map->_itemPoses[_destItemId].y; _vm->_map->_destY = _vm->_map->_itemPoses[_destItemId].y; _gobDestY = _vm->_map->_itemPoses[_destItemId].y; if (_gobAction == 3 || _destActionItem == 0) { _pressedMapX = _vm->_map->_itemPoses[_destItemId].x; _vm->_map->_destX = _vm->_map->_itemPoses[_destItemId].x; _gobDestX = _vm->_map->_itemPoses[_destItemId].x; } else if ((items & 0xff00) != 0) { if (_vm->_map->_itemPoses[_destItemId].orient == 4) { if ((_vm->_map->_itemsMap[_pressedMapY] [_pressedMapX - 1] & 0xff00) == (_vm->_map->_itemsMap[_pressedMapY] [_pressedMapX] & 0xff00)) { _pressedMapX--; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } else if (_vm->_map->_itemPoses[_destItemId].orient == 0) { if ((_vm->_map->_itemsMap[_pressedMapY] [_pressedMapX + 1] & 0xff00) == (_vm->_map->_itemsMap[_pressedMapY] [_pressedMapX] & 0xff00)) { _pressedMapX++; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] & 0xff00) == (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] & 0xff00)) { _pressedMapY++; _vm->_map->_destY = _pressedMapY; _gobDestY = _pressedMapY; } } else { if (_vm->_map->_itemPoses[_destItemId].orient == 4) { if ((_vm->_map->_itemsMap[_pressedMapY] [_pressedMapX - 1]) == (_vm->_map->_itemsMap[_pressedMapY] [_pressedMapX])) { _pressedMapX--; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } else if (_vm->_map->_itemPoses[_destItemId].orient == 0) { if ((_vm->_map->_itemsMap[_pressedMapY] [_pressedMapX + 1]) == (_vm->_map->_itemsMap[_pressedMapY] [_pressedMapX])) { _pressedMapX++; _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; } } if ((_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX]) == (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX])) { _pressedMapY++; _vm->_map->_destY = _pressedMapY; _gobDestY = _pressedMapY; } } if (_gobAction == 4 && _destActionItem != 0 && _itemToObject[_destActionItem] != -1 && _objects[_itemToObject[_destActionItem]]-> pickable == 1) { itemDesc = _objects[_itemToObject[_destActionItem]]; itemDesc->animation = itemDesc->stateMach[itemDesc->state][0]->animation; layer = itemDesc->stateMach[itemDesc->state][itemDesc-> stateColumn]->layer; _vm->_scenery->updateAnim(layer, 0, itemDesc->animation, 0, itemDesc->xPos, itemDesc->yPos, 0); tmpX = (_vm->_scenery->_toRedrawRight + _vm->_scenery->_toRedrawLeft) / 2; tmpY = _vm->_scenery->_toRedrawBottom; tmpPosY = tmpY / 6; if ((tmpY % 3) < 3 && tmpPosY > 0) tmpPosY--; tmpPosX = tmpX / 12; if ((tmpX % 12) < 6 && tmpPosX > 0) tmpPosX--; if (_vm->_map->_itemPoses[_destActionItem].orient == 0 || _vm->_map->_itemPoses[_destActionItem].orient == -1) { tmpPosX++; } if (_vm->_map->_passMap[tmpPosY][tmpPosX] == 1) { _pressedMapX = tmpPosX; _vm->_map->_destX = tmpPosX; _gobDestX = tmpPosX; _pressedMapY = tmpPosY; _vm->_map->_destY = tmpPosY; _gobDestY = tmpPosY; } } } } void Goblin::initiateMove(void) { _vm->_map->findNearestToDest(); _vm->_map->findNearestToGob(); _vm->_map->optimizePoints(); _pathExistence = _vm->_map->checkDirectPath(_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::moveFindItem(int16 posX, int16 posY) { int16 i; if (_gobAction == 3 || _gobAction == 4) { for (i = 0; i < 20; i++) { if (_objects[i] == 0) continue; if (_objects[i]->type != 0) continue; if (_objects[i]->left > posX) continue; if (_objects[i]->right < posX) continue; if (_objects[i]->top > posY) continue; if (_objects[i]->bottom < posY) continue; if (_objects[i]->right - _objects[i]->left < 40) posX = (_objects[i]->left + _objects[i]->right) / 2; if (_objects[i]->bottom - _objects[i]->top < 40) posY = (_objects[i]->top + _objects[i]->bottom) / 2; break; } _pressedMapX = posX / 12; _pressedMapY = posY / 6; if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX] == 0 && i < 20) { if (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX] != 0) { _pressedMapY++; } else if (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX + 1] != 0) { _pressedMapX++; _pressedMapY++; } else if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX + 1] != 0) { _pressedMapX++; } else if (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX + 1] != 0) { _pressedMapX++; _pressedMapY--; } else if (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX] != 0) { _pressedMapY--; } else if (_vm->_map->_itemsMap[_pressedMapY - 1][_pressedMapX - 1] != 0) { _pressedMapY--; _pressedMapX--; } else if (_vm->_map->_itemsMap[_pressedMapY][_pressedMapX - 1] != 0) { _pressedMapX--; } else if (_vm->_map->_itemsMap[_pressedMapY + 1][_pressedMapX - 1] != 0) { _pressedMapX--; _pressedMapY++; } } } else { _pressedMapX = posX / 12; _pressedMapY = posY / 6; } } void Goblin::moveCheckSelect(int16 framesCount, Gob_Object * gobDesc, int16 *pGobIndex, int16 *nextAct) { if (gobDesc->right > _vm->_global->_inter_mouseX && gobDesc->left < _vm->_global->_inter_mouseX && gobDesc->bottom > _vm->_global->_inter_mouseY && gobDesc->bottom - 10 < _vm->_global->_inter_mouseY && _gobAction == 0) { if (gobDesc->curLookDir & 4) *nextAct = 16; else *nextAct = 23; gobDesc->curFrame = framesCount - 1; _pathExistence = 0; } else { *pGobIndex = peekGoblin(gobDesc); if (*pGobIndex != 0) { _pathExistence = 0; } else if (_vm->_map->_curGoblinX == _pressedMapX && _vm->_map->_curGoblinY == _pressedMapY) { if (_gobAction != 0) _readyToAct = 1; _pathExistence = 0; } } } void Goblin::moveInitStep(int16 framesCount, int16 action, int16 cont, Gob_Object *gobDesc, int16 *pGobIndex, int16 *pNextAct) { int16 posX; int16 posY; if (cont != 0 && _goesAtTarget == 0 && _readyToAct == 0 && VAR(59) == 0 && gobDesc->type != 1 && gobDesc->state != 10 && gobDesc->state != 11) { if (gobDesc->state >= 40) { gobDesc->curFrame = framesCount - 1; } _gobAction = action; _forceNextState[0] = -1; _forceNextState[1] = -1; _forceNextState[2] = -1; if (action == 3) { posX = _vm->_global->_inter_mouseX + 6; posY = _vm->_global->_inter_mouseY + 7; } else if (action == 4) { posX = _vm->_global->_inter_mouseX + 7; posY = _vm->_global->_inter_mouseY + 12; } else { posX = _vm->_global->_inter_mouseX; posY = _vm->_global->_inter_mouseY; } moveFindItem(posX, posY); adjustDest(posX, posY); adjustTarget(); _vm->_map->_destX = _pressedMapX; _gobDestX = _pressedMapX; _vm->_map->_destY = _pressedMapY; _gobDestY = _pressedMapY; targetDummyItem(gobDesc); targetItem(); initiateMove(); moveCheckSelect(framesCount, gobDesc, pGobIndex, pNextAct); } else { if (_readyToAct != 0 && (_vm->_map->_curGoblinX != _pressedMapX || _vm->_map->_curGoblinY != _pressedMapY)) _readyToAct = 0; if (gobDesc->type == 1) { *pGobIndex = peekGoblin(gobDesc); } } } void Goblin::moveTreatRopeStairs(Gob_Object *gobDesc) { if (_currentGoblin != 1) return; if (gobDesc->nextState == 28 && _vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 6) { _forceNextState[0] = 28; _forceNextState[1] = -1; } if (gobDesc->nextState == 29 && _vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 6) { _forceNextState[0] = 29; _forceNextState[1] = -1; } if ((gobDesc->nextState == 28 || gobDesc->nextState == 29 || gobDesc->nextState == 20) && _vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 6) { if ((gobDesc->curLookDir == 0 || gobDesc->curLookDir == 4 || gobDesc->curLookDir == 2) && _vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 6) { _forceNextState[0] = 28; _forceNextState[1] = -1; } else if ((gobDesc->curLookDir == 0 || gobDesc->curLookDir == 4 || gobDesc->curLookDir == 6) && _vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 6) { _forceNextState[0] = 29; _forceNextState[1] = -1; } } if (gobDesc->nextState == 8 && _vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 3) { _forceNextState[0] = 8; _forceNextState[1] = -1; } if (gobDesc->nextState == 9 && _vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 3) { _forceNextState[0] = 9; _forceNextState[1] = -1; } if (gobDesc->nextState == 20 && _vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3) { if ((gobDesc->curLookDir == 0 || gobDesc->curLookDir == 4 || gobDesc->curLookDir == 2) && _vm->_map->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 3) { _forceNextState[0] = 8; _forceNextState[1] = -1; } else if ((gobDesc->curLookDir == 0 || gobDesc->curLookDir == 4 || gobDesc->curLookDir == 6) && _vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 3) { _forceNextState[0] = 9; _forceNextState[1] = -1; } } } void Goblin::movePathFind(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(_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(); _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(); _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(_vm->_map->_curGoblinX, _vm->_map->_curGoblinY, _gobDestX, _gobDestY) == 3 && _vm->_map->_passMap[_pressedMapY][_pressedMapX] != 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->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX] == 6 && _currentGoblin != 1) { _pathExistence = 0; break; } if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3) { gobDesc->nextState = 8; break; } if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 6 && _currentGoblin == 1) { gobDesc->nextState = 28; break; } gobDesc->nextState = rotateState(gobDesc->curLookDir, 2); break; case Map::kDirS: if (_vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX] == 6 && _currentGoblin != 1) { _pathExistence = 0; break; } if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3) { gobDesc->nextState = 9; break; } if (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 6 && _currentGoblin == 1) { gobDesc->nextState = 29; break; } gobDesc->nextState = rotateState(gobDesc->curLookDir, 6); break; case Map::kDirSE: if (_vm->_map->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX + 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->_passMap[_vm->_map->_curGoblinY + 1][_vm->_map->_curGoblinX - 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->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX - 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->_passMap[_vm->_map->_curGoblinY - 1][_vm->_map->_curGoblinX + 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->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 3 || (_vm->_map->_passMap[_vm->_map->_curGoblinY][_vm->_map->_curGoblinX] == 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::moveAdvance(Gob_Object *gobDesc, int16 nextAct, int16 framesCount) { int16 i; int16 newX; int16 newY; int16 flag; movePathFind(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; } int16 Goblin::doMove(Gob_Object *gobDesc, int16 cont, int16 action) { int16 framesCount; int16 nextAct; int16 gobIndex; int16 layer; nextAct = 0; gobIndex = 0; layer = gobDesc->stateMach[gobDesc->state][0]->layer; framesCount = _vm->_scenery->_animations[gobDesc->animation].layers[layer]->framesCount; if (VAR(59) == 0 && gobDesc->state != 30 && gobDesc->state != 31) { gobDesc->order = (gobDesc->bottom) / 24 + 3; } if (_positionedGob != _currentGoblin) { _vm->_map->_curGoblinX = _gobPositions[_currentGoblin].x; _vm->_map->_curGoblinY = _gobPositions[_currentGoblin].y; } _positionedGob = _currentGoblin; gobDesc->animation = gobDesc->stateMach[gobDesc->state][gobDesc->stateColumn]-> animation; _gobStateLayer = gobDesc->stateMach[gobDesc->state][gobDesc->stateColumn]->layer; moveInitStep(framesCount, action, cont, gobDesc, &gobIndex, &nextAct); moveTreatRopeStairs(gobDesc); moveAdvance(gobDesc, nextAct, framesCount); return gobIndex; } void Goblin::freeObjects(void) { int16 i; int16 state; int16 col; for (i = 0; i < 16; i++) { if (_soundData[i] == 0) continue; _vm->_snd->freeSoundData(_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::zeroObjects(void) { int16 i; for (i = 0; i < 4; i++) _goblins[i] = 0; for (i = 0; i < 20; i++) _objects[i] = 0; for (i = 0; i < 16; i++) _soundData[i] = 0; } void Goblin::freeAllObjects(void) { _vm->_util->deleteList(_objList); freeObjects(); } void Goblin::loadObjects(char *source) { int16 i; zeroObjects(); for (i = 0; i < 20; i++) _itemToObject[i] = 100; freeObjects(); initList(); strcpy(_vm->_map->_sourceFile, source); _vm->_map->_sourceFile[strlen(_vm->_map->_sourceFile) - 4] = 0; _vm->_map->loadMapObjects(source); for (i = 0; i < _gobsCount; i++) placeObject(_goblins[i], 0); for (i = 0; i < _objCount; i++) { placeObject(_objects[i], 1); } initVarPointers(); _actDestItemDesc = 0; } void Goblin::saveGobDataToVars(int16 xPos, int16 yPos, int16 someVal) { Gob_Object *obj; *_some0ValPtr = someVal; *_curGobXPosVarPtr = xPos; *_curGobYPosVarPtr = yPos; *_itemInPocketVarPtr = _itemIndInPocket; obj = _goblins[_currentGoblin]; *_curGobStateVarPtr = obj->state; *_curGobFrameVarPtr = obj->curFrame; *_curGobMultStateVarPtr = obj->multState; *_curGobNextStateVarPtr = obj->nextState; *_curGobScrXVarPtr = obj->xPos; *_curGobScrYVarPtr = obj->yPos; *_curGobLeftVarPtr = obj->left; *_curGobTopVarPtr = obj->top; *_curGobRightVarPtr = obj->right; *_curGobBottomVarPtr = obj->bottom; *_curGobDoAnimVarPtr = obj->doAnim; *_curGobOrderVarPtr = obj->order; *_curGobNoTickVarPtr = obj->noTick; *_curGobTypeVarPtr = obj->type; *_curGobMaxTickVarPtr = obj->maxTick; *_curGobTickVarPtr = obj->tick; *_curGobActStartStateVarPtr = obj->actionStartState; *_curGobLookDirVarPtr = obj->curLookDir; *_curGobPickableVarPtr = obj->pickable; *_curGobRelaxVarPtr = obj->relaxTime; *_curGobMaxFrameVarPtr = getObjMaxFrame(obj); if (_actDestItemDesc == 0) return; obj = _actDestItemDesc; *_destItemStateVarPtr = obj->state; *_destItemFrameVarPtr = obj->curFrame; *_destItemMultStateVarPtr = obj->multState; *_destItemNextStateVarPtr = obj->nextState; *_destItemScrXVarPtr = obj->xPos; *_destItemScrYVarPtr = obj->yPos; *_destItemLeftVarPtr = obj->left; *_destItemTopVarPtr = obj->top; *_destItemRightVarPtr = obj->right; *_destItemBottomVarPtr = obj->bottom; *_destItemDoAnimVarPtr = obj->doAnim; *_destItemOrderVarPtr = obj->order; *_destItemNoTickVarPtr = obj->noTick; *_destItemTypeVarPtr = obj->type; *_destItemMaxTickVarPtr = obj->maxTick; *_destItemTickVarPtr = obj->tick; *_destItemActStartStVarPtr = obj->actionStartState; *_destItemLookDirVarPtr = obj->curLookDir; *_destItemPickableVarPtr = obj->pickable; *_destItemRelaxVarPtr = obj->relaxTime; *_destItemMaxFrameVarPtr = getObjMaxFrame(obj); _destItemState = obj->state; _destItemType = obj->type; } void Goblin::initVarPointers(void) { _gobRetVarPtr = (int32 *)VAR_ADDRESS(59); _curGobStateVarPtr = (int32 *)VAR_ADDRESS(60); _curGobFrameVarPtr = (int32 *)VAR_ADDRESS(61); _curGobMultStateVarPtr = (int32 *)VAR_ADDRESS(62); _curGobNextStateVarPtr = (int32 *)VAR_ADDRESS(63); _curGobScrXVarPtr = (int32 *)VAR_ADDRESS(64); _curGobScrYVarPtr = (int32 *)VAR_ADDRESS(65); _curGobLeftVarPtr = (int32 *)VAR_ADDRESS(66); _curGobTopVarPtr = (int32 *)VAR_ADDRESS(67); _curGobRightVarPtr = (int32 *)VAR_ADDRESS(68); _curGobBottomVarPtr = (int32 *)VAR_ADDRESS(69); _curGobDoAnimVarPtr = (int32 *)VAR_ADDRESS(70); _curGobOrderVarPtr = (int32 *)VAR_ADDRESS(71); _curGobNoTickVarPtr = (int32 *)VAR_ADDRESS(72); _curGobTypeVarPtr = (int32 *)VAR_ADDRESS(73); _curGobMaxTickVarPtr = (int32 *)VAR_ADDRESS(74); _curGobTickVarPtr = (int32 *)VAR_ADDRESS(75); _curGobActStartStateVarPtr = (int32 *)VAR_ADDRESS(76); _curGobLookDirVarPtr = (int32 *)VAR_ADDRESS(77); _curGobPickableVarPtr = (int32 *)VAR_ADDRESS(80); _curGobRelaxVarPtr = (int32 *)VAR_ADDRESS(81); _destItemStateVarPtr = (int32 *)VAR_ADDRESS(82); _destItemFrameVarPtr = (int32 *)VAR_ADDRESS(83); _destItemMultStateVarPtr = (int32 *)VAR_ADDRESS(84); _destItemNextStateVarPtr = (int32 *)VAR_ADDRESS(85); _destItemScrXVarPtr = (int32 *)VAR_ADDRESS(86); _destItemScrYVarPtr = (int32 *)VAR_ADDRESS(87); _destItemLeftVarPtr = (int32 *)VAR_ADDRESS(88); _destItemTopVarPtr = (int32 *)VAR_ADDRESS(89); _destItemRightVarPtr = (int32 *)VAR_ADDRESS(90); _destItemBottomVarPtr = (int32 *)VAR_ADDRESS(91); _destItemDoAnimVarPtr = (int32 *)VAR_ADDRESS(92); _destItemOrderVarPtr = (int32 *)VAR_ADDRESS(93); _destItemNoTickVarPtr = (int32 *)VAR_ADDRESS(94); _destItemTypeVarPtr = (int32 *)VAR_ADDRESS(95); _destItemMaxTickVarPtr = (int32 *)VAR_ADDRESS(96); _destItemTickVarPtr = (int32 *)VAR_ADDRESS(97); _destItemActStartStVarPtr = (int32 *)VAR_ADDRESS(98); _destItemLookDirVarPtr = (int32 *)VAR_ADDRESS(99); _destItemPickableVarPtr = (int32 *)VAR_ADDRESS(102); _destItemRelaxVarPtr = (int32 *)VAR_ADDRESS(103); _destItemMaxFrameVarPtr = (int32 *)VAR_ADDRESS(105); _curGobVarPtr = (int32 *)VAR_ADDRESS(106); _some0ValPtr = (int32 *)VAR_ADDRESS(107); _curGobXPosVarPtr = (int32 *)VAR_ADDRESS(108); _curGobYPosVarPtr = (int32 *)VAR_ADDRESS(109); _curGobMaxFrameVarPtr = (int32 *)VAR_ADDRESS(110); _itemInPocketVarPtr = (int32 *)VAR_ADDRESS(114); *_itemInPocketVarPtr = -2; } void Goblin::loadGobDataFromVars(void) { Gob_Object *obj; _itemIndInPocket = *_itemInPocketVarPtr; obj = _goblins[_currentGoblin]; obj->state = *_curGobStateVarPtr; obj->curFrame = *_curGobFrameVarPtr; obj->multState = *_curGobMultStateVarPtr; obj->nextState = *_curGobNextStateVarPtr; obj->xPos = *_curGobScrXVarPtr; obj->yPos = *_curGobScrYVarPtr; obj->left = *_curGobLeftVarPtr; obj->top = *_curGobTopVarPtr; obj->right = *_curGobRightVarPtr; obj->bottom = *_curGobBottomVarPtr; obj->doAnim = *_curGobDoAnimVarPtr; obj->order = *_curGobOrderVarPtr; obj->noTick = *_curGobNoTickVarPtr; obj->type = *_curGobTypeVarPtr; obj->maxTick = *_curGobMaxTickVarPtr; obj->tick = *_curGobTickVarPtr; obj->actionStartState = *_curGobActStartStateVarPtr; obj->curLookDir = *_curGobLookDirVarPtr; obj->pickable = *_curGobPickableVarPtr; obj->relaxTime = *_curGobRelaxVarPtr; if (_actDestItemDesc == 0) return; obj = _actDestItemDesc; obj->state = *_destItemStateVarPtr; obj->curFrame = *_destItemFrameVarPtr; obj->multState = *_destItemMultStateVarPtr; obj->nextState = *_destItemNextStateVarPtr; obj->xPos = *_destItemScrXVarPtr; obj->yPos = *_destItemScrYVarPtr; obj->left = *_destItemLeftVarPtr; obj->top = *_destItemTopVarPtr; obj->right = *_destItemRightVarPtr; obj->bottom = *_destItemBottomVarPtr; obj->doAnim = *_destItemDoAnimVarPtr; obj->order = *_destItemOrderVarPtr; obj->noTick = *_destItemNoTickVarPtr; obj->type = *_destItemTypeVarPtr; obj->maxTick = *_destItemMaxTickVarPtr; obj->tick = *_destItemTickVarPtr; obj->actionStartState = *_destItemActStartStVarPtr; obj->curLookDir = *_destItemLookDirVarPtr; obj->pickable = *_destItemPickableVarPtr; obj->relaxTime = *_destItemRelaxVarPtr; if (obj->type != _destItemType) obj->toRedraw = 1; if (obj->state != _destItemState && obj->type == 0) obj->toRedraw = 1; } void Goblin::pickItem(int16 indexToPocket, int16 idToPocket) { int16 x; int16 y; if (_objects[indexToPocket]->pickable != 1) return; _objects[indexToPocket]->type = 3; _itemIndInPocket = indexToPocket; _itemIdInPocket = idToPocket; for (y = 0; y < Map::kMapHeight; y++) { for (x = 0; x < Map::kMapWidth; x++) { if (_itemByteFlag == 1) { if (((_vm->_map->_itemsMap[y][x] & 0xff00) >> 8) == idToPocket) _vm->_map->_itemsMap[y][x] &= 0xff; } else { if ((_vm->_map->_itemsMap[y][x] & 0xff) == idToPocket) _vm->_map->_itemsMap[y][x] &= 0xff00; } } } if (idToPocket >= 0 && idToPocket < 20) { _vm->_map->_itemPoses[_itemIdInPocket].x = 0; _vm->_map->_itemPoses[_itemIdInPocket].y = 0; _vm->_map->_itemPoses[_itemIdInPocket].orient = 0; } } void Goblin::placeItem(int16 indexInPocket, int16 idInPocket) { Gob_Object *itemDesc; int16 lookDir; int16 xPos; int16 yPos; int16 layer; itemDesc = _objects[indexInPocket]; lookDir = _goblins[0]->curLookDir & 4; xPos = _gobPositions[0].x; yPos = _gobPositions[0].y; _itemIndInPocket = -1; _itemIdInPocket = 0; itemDesc->pickable = 1; itemDesc->type = 0; itemDesc->toRedraw = 1; itemDesc->curFrame = 0; itemDesc->order = _goblins[0]->order; itemDesc->animation = itemDesc->stateMach[itemDesc->state][0]->animation; layer = itemDesc->stateMach[itemDesc->state][itemDesc->stateColumn]->layer; _vm->_scenery->updateAnim(layer, 0, itemDesc->animation, 0, itemDesc->xPos, itemDesc->yPos, 0); itemDesc->yPos += (_gobPositions[0].y * 6) + 5 - _vm->_scenery->_toRedrawBottom; if (lookDir == 4) { itemDesc->xPos += (_gobPositions[0].x * 12 + 14) - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2; } else { itemDesc->xPos += (_gobPositions[0].x * 12) - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2; } _vm->_map->placeItem(xPos, yPos, idInPocket); if (yPos > 0) { _vm->_map->placeItem(xPos, yPos - 1, idInPocket); } if (lookDir == 4) { if (xPos < Map::kMapWidth - 1) { _vm->_map->placeItem(xPos + 1, yPos, idInPocket); if (yPos > 0) { _vm->_map->placeItem(xPos + 1, yPos - 1, idInPocket); } } } else { if (xPos > 0) { _vm->_map->placeItem(xPos - 1, yPos, idInPocket); if (yPos > 0) { _vm->_map->placeItem(xPos - 1, yPos - 1, idInPocket); } } } if (idInPocket >= 0 && idInPocket < 20) { _vm->_map->_itemPoses[idInPocket].x = _gobPositions[0].x; _vm->_map->_itemPoses[idInPocket].y = _gobPositions[0].y; _vm->_map->_itemPoses[idInPocket].orient = lookDir; if (_vm->_map->_itemPoses[idInPocket].orient == 0) { // _vm->_map->_itemPoses[idInPocket].x++; if (_vm->_map->_passMap[(int)_vm->_map->_itemPoses[idInPocket].y][_vm->_map->_itemPoses[idInPocket].x + 1] == 1) _vm->_map->_itemPoses[idInPocket].x++; } else { if (_vm->_map->_passMap[(int)_vm->_map->_itemPoses[idInPocket].y][_vm->_map->_itemPoses[idInPocket].x - 1] == 1) _vm->_map->_itemPoses[idInPocket].x--; } } } void Goblin::swapItems(int16 indexToPick, int16 idToPick) { int16 layer; Gob_Object *pickObj; Gob_Object *placeObj; int16 idToPlace; int16 x; int16 y; pickObj = _objects[indexToPick]; placeObj = _objects[_itemIndInPocket]; idToPlace = _itemIdInPocket; pickObj->type = 3; _itemIndInPocket = indexToPick; _itemIdInPocket = idToPick; if (_itemByteFlag == 0) { for (y = 0; y < Map::kMapHeight; y++) { for (x = 0; x < Map::kMapWidth; x++) { if ((_vm->_map->_itemsMap[y][x] & 0xff) == idToPick) _vm->_map->_itemsMap[y][x] = (_vm->_map->_itemsMap[y][x] & 0xff00) + idToPlace; } } } else { for (y = 0; y < Map::kMapHeight; y++) { for (x = 0; x < Map::kMapWidth; x++) { if (((_vm->_map->_itemsMap[y][x] & 0xff00) >> 8) == idToPick) _vm->_map->_itemsMap[y][x] = (_vm->_map->_itemsMap[y][x] & 0xff) + (idToPlace << 8); } } } if (idToPick >= 0 && idToPick < 20) { _vm->_map->_itemPoses[idToPlace].x = _vm->_map->_itemPoses[_itemIdInPocket].x; _vm->_map->_itemPoses[idToPlace].y = _vm->_map->_itemPoses[_itemIdInPocket].y; _vm->_map->_itemPoses[idToPlace].orient = _vm->_map->_itemPoses[_itemIdInPocket].orient; _vm->_map->_itemPoses[_itemIdInPocket].x = 0; _vm->_map->_itemPoses[_itemIdInPocket].y = 0; _vm->_map->_itemPoses[_itemIdInPocket].orient = 0; } _itemIndInPocket = -1; _itemIdInPocket = 0; placeObj->type = 0; placeObj->nextState = -1; placeObj->multState = -1; placeObj->unk14 = 0; placeObj->toRedraw = 1; placeObj->curFrame = 0; placeObj->order = _goblins[0]->order; placeObj->animation = placeObj->stateMach[placeObj->state][0]->animation; layer = placeObj->stateMach[placeObj->state][placeObj->stateColumn]->layer; _vm->_scenery->updateAnim(layer, 0, placeObj->animation, 0, placeObj->xPos, placeObj->yPos, 0); placeObj->yPos += (_gobPositions[0].y * 6) + 5 - _vm->_scenery->_toRedrawBottom; if (_vm->_map->_itemPoses[idToPlace].orient == 4) { placeObj->xPos += (_gobPositions[0].x * 12 + 14) - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2; } else { placeObj->xPos += (_gobPositions[0].x * 12) - (_vm->_scenery->_toRedrawLeft + _vm->_scenery->_toRedrawRight) / 2; } } void Goblin::treatItemPick(int16 itemId) { int16 itemIndex; Gob_Object *gobDesc; gobDesc = _goblins[_currentGoblin]; if (gobDesc->curFrame != 9) return; if (gobDesc->stateMach != gobDesc->realStateMach) return; _readyToAct = 0; _goesAtTarget = 0; itemIndex = _itemToObject[itemId]; if (itemId != 0 && itemIndex != -1 && _objects[itemIndex]->pickable != 1) itemIndex = -1; if (_itemIndInPocket != -1 && _itemIndInPocket == itemIndex) itemIndex = -1; if (_itemIndInPocket != -1 && itemIndex != -1 && _objects[itemIndex]->pickable == 1) { swapItems(itemIndex, itemId); _itemIndInPocket = itemIndex; _itemIdInPocket = itemId; return; } if (_itemIndInPocket != -1 && itemIndex == -1) { placeItem(_itemIndInPocket, _itemIdInPocket); return; } if (_itemIndInPocket == -1 && itemIndex != -1) { pickItem(itemIndex, itemId); return; } } int16 Goblin::treatItem(int16 action) { int16 state; state = _goblins[_currentGoblin]->state; if ((state == 10 || state == 11) && _goblins[_currentGoblin]->curFrame == 0) { _readyToAct = 0; } if (action == 3 && _currentGoblin == 0 && (state == 10 || state == 11) && _goblins[0]->curFrame == 0) { saveGobDataToVars(_gobPositions[_currentGoblin].x, _gobPositions[_currentGoblin].y, 0); _goesAtTarget = 1; return -1; } if (_noPick == 0 && _currentGoblin == 0 && (state == 10 || state == 11)) { treatItemPick(_destActionItem); saveGobDataToVars(_gobPositions[_currentGoblin].x, _gobPositions[_currentGoblin].y, 0); return 0; } if (_goesAtTarget == 0) { saveGobDataToVars(_gobPositions[_currentGoblin].x, _gobPositions[_currentGoblin].y, 0); return 0; } else { if (_itemToObject[_destActionItem] != 100 && _destActionItem != 0) { if (_itemToObject[_destActionItem] == -1) { _actDestItemDesc = 0; } else { _actDestItemDesc = _objects[_itemToObject [_destActionItem]]; } } _goesAtTarget = 0; saveGobDataToVars(_gobPositions[_currentGoblin].x, _gobPositions[_currentGoblin].y, 0); return _destActionItem; } } } // End of namespace Gob