/* 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 "common/stream.h" #include "gob/gob.h" #include "gob/map.h" #include "gob/global.h" #include "gob/goblin.h" #include "gob/inter.h" #include "gob/game.h" #include "gob/script.h" #include "gob/resources.h" #include "gob/mult.h" namespace Gob { Map_v2::Map_v2(GobEngine *vm) : Map_v1(vm) { _screenHeight = 200; } Map_v2::~Map_v2() { _passMap = 0; } void Map_v2::loadMapObjects(const char *avjFile) { uint8 wayPointsCount; uint16 var; int16 id; int16 mapWidth, mapHeight; int16 tmp; byte *variables; uint32 tmpPos; uint32 passPos; var = _vm->_game->_script->readVarIndex(); variables = _vm->_inter->_variables->getAddressOff8(var); id = _vm->_game->_script->readInt16(); if (((uint16) id) >= 65520) { switch ((uint16) id) { case 65530: for (int i = 0; i < _mapWidth * _mapHeight; i++) _passMap[i] -= READ_VARO_UINT8(var + i); break; case 65531: for (int i = 0; i < _mapWidth * _mapHeight; i++) _passMap[i] += READ_VARO_UINT8(var + i); break; case 65532: for (int i = 0; i < _mapWidth * _mapHeight; i++) WRITE_VARO_UINT8(var + i, 0x00); break; case 65533: { int index = READ_VARO_UINT16(var); // _vm->_mult->_objects[index].field_6E = 0; // _vm->_mult->_objects[index].field_6A = variables; warning("Map_v2::loadMapObjects(): ID == 65533 (%d)", index); break; } case 65534: _tilesWidth = READ_VARO_UINT8(var); _tilesHeight = READ_VARO_UINT8(var + 1); _mapWidth = READ_VARO_UINT8(var + 2); _mapHeight = READ_VARO_UINT8(var + 3); _mapUnknownBool = READ_VARO_UINT8(var + 4) ? true : false; if (_mapUnknownBool) warning("Map_v2::loadMapObjects(): _mapUnknownBool == true"); break; case 65535: _passMap = (int8 *)_vm->_inter->_variables->getAddressOff8(var); break; default: warning("Map_v2::loadMapObjects(): ID == %d", (uint16) id); break; } return; } Resource *resource = _vm->_game->_resources->getResource(id); if (!resource) return; Common::SeekableReadStream &mapData = *resource->stream(); _mapVersion = mapData.readByte(); if (_mapVersion == 4) { _screenWidth = 640; _screenHeight = 400; } else if (_mapVersion == 3) { _passWidth = 65; _screenWidth = 640; _screenHeight = 200; } else { _passWidth = 40; _screenWidth = 320; _screenHeight = 200; } _wayPointCount = mapData.readByte(); _tilesWidth = mapData.readSint16LE(); _tilesHeight = mapData.readSint16LE(); _bigTiles = !(_tilesHeight & 0xFF00); _tilesHeight &= 0xFF; if (_mapVersion == 4) { _screenWidth = mapData.readSint16LE(); _screenHeight = mapData.readSint16LE(); } _mapWidth = _screenWidth / _tilesWidth; _mapHeight = _screenHeight / _tilesHeight; passPos = mapData.pos(); mapData.skip(_mapWidth * _mapHeight); if (resource->getData()[0] == 1) wayPointsCount = _wayPointCount = 40; else wayPointsCount = _wayPointCount == 0 ? 1 : _wayPointCount; delete[] _wayPoints; _wayPoints = new WayPoint[wayPointsCount]; for (int i = 0; i < _wayPointCount; i++) { _wayPoints[i].x = mapData.readSByte(); _wayPoints[i].y = mapData.readSByte(); _wayPoints[i].notWalkable = mapData.readSByte(); } if (_mapVersion == 4) { _mapWidth = VAR(17); _passWidth = _mapWidth; } // In the original asm, this writes byte-wise into the variables-array tmpPos = mapData.pos(); mapData.seek(passPos); if ((variables != 0) && (variables != _vm->_inter->_variables->getAddressOff8(0))) { _passMap = (int8 *)variables; mapHeight = _screenHeight / _tilesHeight; mapWidth = _screenWidth / _tilesWidth; for (int i = 0; i < mapHeight; i++) { for (int j = 0; j < mapWidth; j++) setPass(j, i, mapData.readSByte()); _vm->_inter->_variables->getAddressOff8(var + i * _passWidth); } } mapData.seek(tmpPos); tmp = mapData.readSint16LE(); mapData.skip(tmp * 14); tmp = mapData.readSint16LE(); mapData.skip(tmp * 14 + 28); tmp = mapData.readSint16LE(); mapData.skip(tmp * 14); _vm->_goblin->_gobsCount = tmp; for (int i = 0; i < _vm->_goblin->_gobsCount; i++) loadGoblinStates(mapData, i); _vm->_goblin->_soundSlotsCount = _vm->_game->_script->readInt16(); for (int i = 0; i < _vm->_goblin->_soundSlotsCount; i++) _vm->_goblin->_soundSlots[i] = _vm->_inter->loadSound(1); delete resource; } void Map_v2::loadGoblinStates(Common::SeekableReadStream &data, int index) { Mult::Mult_GobState *statesPtr; Mult::Mult_GobState *gobState; int8 indices[102]; uint8 statesCount; uint8 dataCount; int16 state; uint32 tmpPos; memset(indices, -1, 101); _vm->_mult->_objects[index].goblinStates = new Mult::Mult_GobState*[101]; memset(_vm->_mult->_objects[index].goblinStates, 0, 101 * sizeof(Mult::Mult_GobState *)); data.read(indices, 100); tmpPos = data.pos(); statesCount = 0; for (int i = 0; i < 100; i++) { if (indices[i] != -1) { statesCount++; data.skip(4); dataCount = data.readByte(); statesCount += dataCount; data.skip(dataCount * 9); } } data.seek(tmpPos); statesPtr = new Mult::Mult_GobState[statesCount]; _vm->_mult->_objects[index].goblinStates[0] = statesPtr; for (int i = 0; i < 100; i++) { state = indices[i]; if (state != -1) { _vm->_mult->_objects[index].goblinStates[state] = statesPtr++; gobState = _vm->_mult->_objects[index].goblinStates[state]; gobState[0].animation = data.readSint16LE(); gobState[0].layer = data.readSint16LE(); dataCount = data.readByte(); gobState[0].dataCount = dataCount; for (uint8 j = 1; j <= dataCount; j++) { data.skip(1); gobState[j].sndItem = data.readSByte(); data.skip(1); gobState[j].sndFrame = data.readByte(); data.skip(1); gobState[j].freq = data.readSint16LE(); gobState[j].repCount = data.readSByte(); gobState[j].speaker = data.readByte(); statesPtr++; } } } } void Map_v2::findNearestToGob(Mult::Mult_Object *obj) { int16 wayPoint = findNearestWayPoint(obj->goblinX, obj->goblinY); if (wayPoint != -1) obj->nearestWayPoint = wayPoint; } void Map_v2::findNearestToDest(Mult::Mult_Object *obj) { int16 wayPoint = findNearestWayPoint(obj->destX, obj->destY); if (wayPoint != -1) obj->nearestDest = wayPoint; } void Map_v2::optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y) { if (!_wayPoints) return; if (obj->nearestWayPoint < obj->nearestDest) { for (int i = obj->nearestWayPoint; i <= obj->nearestDest; i++) { if (checkDirectPath(obj, x, y, _wayPoints[i].x, _wayPoints[i].y) == 1) obj->nearestWayPoint = i; } } else { for (int i = obj->nearestWayPoint; i >= obj->nearestDest; i--) { if (_wayPoints[i].notWalkable == 1) break; if (checkDirectPath(obj, x, y, _wayPoints[i].x, _wayPoints[i].y) == 1) obj->nearestWayPoint = i; } } } } // End of namespace Gob