394 lines
12 KiB
C++
394 lines
12 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "tot/tot.h"
|
|
#include "tot/util.h"
|
|
|
|
namespace Tot {
|
|
|
|
void TotEngine::readBitmap(int32 bitmapPosition, byte *buf, uint bitmapSize, uint error) {
|
|
Common::File bitmapFile;
|
|
if (!bitmapFile.open("BITMAPS.DAT")) {
|
|
showError(error);
|
|
}
|
|
bitmapFile.seek(bitmapPosition);
|
|
bitmapFile.read(buf, bitmapSize);
|
|
|
|
bitmapFile.close();
|
|
}
|
|
|
|
void TotEngine::loadCharAnimation() {
|
|
Common::File characterFile;
|
|
_cpCounter = _cpCounter2;
|
|
if (!characterFile.open("PERSONAJ.SPT"))
|
|
showError(265);
|
|
|
|
_mainCharFrameSize = characterFile.readUint16LE();
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
for (int j = 0; j < kWalkFrameCount; j++) {
|
|
if (g_engine->_mainCharAnimation.bitmap[i][j])
|
|
free(g_engine->_mainCharAnimation.bitmap[i][j]);
|
|
_mainCharAnimation.bitmap[i][j] = (byte *)malloc(_mainCharFrameSize);
|
|
characterFile.read(_mainCharAnimation.bitmap[i][j], _mainCharFrameSize);
|
|
}
|
|
for (int i = 0; i < 4; i++)
|
|
for (int j = kWalkFrameCount; j < (kWalkFrameCount + 10 * 3); j++) {
|
|
if (g_engine->_mainCharAnimation.bitmap[i][j])
|
|
free(g_engine->_mainCharAnimation.bitmap[i][j]);
|
|
_mainCharAnimation.bitmap[i][j] = (byte *)malloc(_mainCharFrameSize);
|
|
characterFile.read(_mainCharAnimation.bitmap[i][j], _mainCharFrameSize);
|
|
}
|
|
characterFile.close();
|
|
}
|
|
|
|
void TotEngine::readTextFile() {
|
|
if (!_verbFile.open("CONVERSA.TXT")) {
|
|
showError(313);
|
|
}
|
|
}
|
|
|
|
TextEntry TotEngine::readTextRegister(uint numRegister) {
|
|
_verbFile.seek(numRegister * kVerbRegSize);
|
|
return readTextRegister();
|
|
}
|
|
|
|
TextEntry TotEngine::readTextRegister() {
|
|
TextEntry regmht;
|
|
// Since the text is encrypted it's safer to save the size as reported by
|
|
// the pascal string, because the encrypter character might be the termination
|
|
// character
|
|
byte size = _verbFile.readByte();
|
|
_verbFile.seek(-1, SEEK_CUR);
|
|
regmht.text = _verbFile.readPascalString(false);
|
|
_verbFile.skip(255 - size);
|
|
regmht.continued = _verbFile.readByte();
|
|
regmht.response = _verbFile.readUint16LE();
|
|
regmht.pointer = _verbFile.readSint32LE();
|
|
return regmht;
|
|
}
|
|
|
|
void TotEngine::readConversationFile() {
|
|
Common::File conversationFile;
|
|
if (!conversationFile.open(Common::Path(Common::String("CONVERSA.TRE")))) {
|
|
showError(314);
|
|
}
|
|
int64 fileSize = conversationFile.size();
|
|
byte *buf = (byte *)malloc(fileSize);
|
|
conversationFile.read(buf, fileSize);
|
|
|
|
_conversationData = new Common::MemorySeekableReadWriteStream(buf, fileSize, DisposeAfterUse::YES);
|
|
conversationFile.close();
|
|
}
|
|
|
|
void saveDoorMetadata(DoorRegistry doors, Common::SeekableWriteStream *out) {
|
|
out->writeUint16LE(doors.nextScene);
|
|
out->writeUint16LE(doors.exitPosX);
|
|
out->writeUint16LE(doors.exitPosY);
|
|
out->writeByte(doors.openclosed);
|
|
out->writeByte(doors.doorcode);
|
|
}
|
|
|
|
void savePoint(Common::Point point, Common::SeekableWriteStream *out) {
|
|
out->writeUint16LE(point.x);
|
|
out->writeUint16LE(point.y);
|
|
}
|
|
|
|
void saveBitmapRegister(RoomBitmapRegister bitmap, Common::SeekableWriteStream *out) {
|
|
out->writeSint32LE(bitmap.bitmapPointer);
|
|
out->writeUint16LE(bitmap.bitmapSize);
|
|
out->writeUint16LE(bitmap.coordx);
|
|
out->writeUint16LE(bitmap.coordy);
|
|
out->writeUint16LE(bitmap.depth);
|
|
}
|
|
|
|
void saveRoomObjectList(RoomObjectListEntry objectList, Common::SeekableWriteStream *out) {
|
|
|
|
out->writeUint16LE(objectList.fileIndex);
|
|
out->writeByte(objectList.objectName.size());
|
|
int paddingSize = 20 - objectList.objectName.size();
|
|
if (paddingSize < 20) {
|
|
out->writeString(objectList.objectName);
|
|
}
|
|
if (paddingSize > 0) {
|
|
char *padding = (char *)calloc(paddingSize, 1);
|
|
out->write(padding, paddingSize);
|
|
|
|
free(padding);
|
|
}
|
|
}
|
|
|
|
void saveRoom(RoomFileRegister *room, Common::SeekableWriteStream *out) {
|
|
out->writeUint16LE(room->code);
|
|
out->writeUint32LE(room->roomImagePointer);
|
|
out->writeUint16LE(room->roomImageSize);
|
|
out->write(room->walkAreasGrid, 40 * 28);
|
|
out->write(room->mouseGrid, 40 * 28);
|
|
|
|
// read puntos
|
|
for (int i = 0; i < 9; i++) {
|
|
for (int j = 0; j < 30; j++) {
|
|
for (int k = 0; k < 5; k++) {
|
|
savePoint(room->trajectories[i][j][k], out);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
saveDoorMetadata(room->doors[i], out);
|
|
}
|
|
for (int i = 0; i < 15; i++) {
|
|
saveBitmapRegister(room->screenLayers[i], out);
|
|
}
|
|
for (int i = 0; i < 51; i++) {
|
|
saveRoomObjectList(*room->screenObjectIndex[i], out);
|
|
}
|
|
out->writeByte(room->animationFlag);
|
|
|
|
out->writeByte(room->animationName.size());
|
|
out->writeString(room->animationName);
|
|
int paddingSize = 8 - room->animationName.size();
|
|
if (paddingSize > 0) {
|
|
char *padding = (char *)calloc(paddingSize, 1);
|
|
// 8 max char name
|
|
out->write(padding, paddingSize);
|
|
|
|
free(padding);
|
|
}
|
|
out->writeByte(room->paletteAnimationFlag);
|
|
out->writeUint16LE(room->palettePointer);
|
|
for (int i = 0; i < 300; i++) {
|
|
savePoint(room->secondaryAnimTrajectory[i], out);
|
|
}
|
|
out->write(room->secondaryAnimDirections, 600);
|
|
out->writeUint16LE(room->secondaryTrajectoryLength);
|
|
}
|
|
|
|
void TotEngine::saveRoomData(RoomFileRegister *room, Common::SeekableWriteStream *out) {
|
|
_rooms->seek(room->code * kRoomRegSize, SEEK_SET);
|
|
saveRoom(room, out);
|
|
}
|
|
|
|
void TotEngine::readObject(Common::SeekableReadStream *stream, uint itemPos, ScreenObject *thisRegObj) {
|
|
stream->seek(itemPos * kItemRegSize);
|
|
thisRegObj->code = stream->readUint16LE();
|
|
thisRegObj->height = stream->readByte();
|
|
|
|
thisRegObj->name = stream->readPascalString();
|
|
|
|
stream->skip(kObjectNameLength - thisRegObj->name.size());
|
|
|
|
thisRegObj->lookAtTextRef = stream->readUint16LE();
|
|
thisRegObj->beforeUseTextRef = stream->readUint16LE();
|
|
thisRegObj->afterUseTextRef = stream->readUint16LE();
|
|
thisRegObj->pickTextRef = stream->readUint16LE();
|
|
thisRegObj->useTextRef = stream->readUint16LE();
|
|
thisRegObj->speaking = stream->readByte();
|
|
thisRegObj->openable = stream->readByte();
|
|
thisRegObj->closeable = stream->readByte();
|
|
|
|
stream->read(thisRegObj->used, 8);
|
|
|
|
thisRegObj->pickupable = stream->readByte();
|
|
thisRegObj->useWith = stream->readUint16LE();
|
|
thisRegObj->replaceWith = stream->readUint16LE();
|
|
thisRegObj->depth = stream->readByte();
|
|
thisRegObj->bitmapPointer = stream->readUint32LE();
|
|
thisRegObj->bitmapSize = stream->readUint16LE();
|
|
thisRegObj->rotatingObjectAnimation = stream->readUint32LE();
|
|
thisRegObj->rotatingObjectPalette = stream->readUint16LE();
|
|
thisRegObj->dropOverlayX = stream->readUint16LE();
|
|
thisRegObj->dropOverlayY = stream->readUint16LE();
|
|
thisRegObj->dropOverlay = stream->readUint32LE();
|
|
thisRegObj->dropOverlaySize = stream->readUint16LE();
|
|
thisRegObj->objectIconBitmap = stream->readUint16LE();
|
|
thisRegObj->xgrid1 = stream->readByte();
|
|
thisRegObj->ygrid1 = stream->readByte();
|
|
thisRegObj->xgrid2 = stream->readByte();
|
|
thisRegObj->ygrid2 = stream->readByte();
|
|
stream->read(thisRegObj->walkAreasPatch, 100);
|
|
stream->read(thisRegObj->mouseGridPatch, 100);
|
|
}
|
|
|
|
void TotEngine::readObject(uint itemPosition) {
|
|
if(_curObject != nullptr) {
|
|
delete _curObject;
|
|
_curObject = nullptr;
|
|
}
|
|
_curObject = new ScreenObject();
|
|
|
|
readObject(_sceneObjectsData, itemPosition, _curObject);
|
|
}
|
|
|
|
void TotEngine::updateObject(uint itemPosition) {
|
|
_curObject->used[0] = 9;
|
|
_sceneObjectsData->seek(itemPosition);
|
|
saveObject(_curObject, _sceneObjectsData);
|
|
}
|
|
|
|
/**
|
|
* Object files contain a single register per object, with a set of 8 flags, to mark them as used in each save.
|
|
*/
|
|
void TotEngine::initializeObjectFile() {
|
|
Common::File objFile;
|
|
if (!objFile.open(Common::Path("OBJETOS.DAT"))) {
|
|
showError(261);
|
|
}
|
|
delete (_sceneObjectsData);
|
|
byte *objectData = (byte *)malloc(objFile.size());
|
|
objFile.read(objectData, objFile.size());
|
|
_sceneObjectsData = new Common::MemorySeekableReadWriteStream(objectData, objFile.size(), DisposeAfterUse::NO);
|
|
objFile.close();
|
|
}
|
|
|
|
void TotEngine::saveObjectsData(ScreenObject *object, Common::SeekableWriteStream *out) {
|
|
out->writeUint16LE(object->code);
|
|
out->writeByte(object->height);
|
|
|
|
out->writeByte(object->name.size());
|
|
out->writeString(object->name);
|
|
int paddingSize = kObjectNameLength - object->name.size();
|
|
if (paddingSize > 0) {
|
|
char *padding = (char *)calloc(paddingSize, 1);
|
|
// 8 max char name
|
|
out->write(padding, paddingSize);
|
|
free(padding);
|
|
}
|
|
|
|
out->writeUint16LE(object->lookAtTextRef);
|
|
out->writeUint16LE(object->beforeUseTextRef);
|
|
out->writeUint16LE(object->afterUseTextRef);
|
|
out->writeUint16LE(object->pickTextRef);
|
|
out->writeUint16LE(object->useTextRef);
|
|
|
|
out->writeByte(object->speaking);
|
|
out->writeByte(object->openable);
|
|
out->writeByte(object->closeable);
|
|
|
|
out->write(object->used, 8);
|
|
|
|
out->writeByte(object->pickupable);
|
|
|
|
out->writeUint16LE(object->useWith);
|
|
out->writeUint16LE(object->replaceWith);
|
|
out->writeByte(object->depth);
|
|
out->writeUint32LE(object->bitmapPointer);
|
|
out->writeUint16LE(object->bitmapSize);
|
|
out->writeUint16LE(object->rotatingObjectAnimation);
|
|
out->writeUint16LE(object->rotatingObjectPalette);
|
|
out->writeUint16LE(object->dropOverlayX);
|
|
out->writeUint16LE(object->dropOverlayY);
|
|
out->writeUint32LE(object->dropOverlay);
|
|
out->writeUint16LE(object->dropOverlaySize);
|
|
out->writeUint16LE(object->objectIconBitmap);
|
|
|
|
out->writeByte(object->xgrid1);
|
|
out->writeByte(object->ygrid1);
|
|
out->writeByte(object->xgrid2);
|
|
out->writeByte(object->ygrid2);
|
|
|
|
out->write(object->walkAreasPatch, 100);
|
|
out->write(object->mouseGridPatch, 100);
|
|
}
|
|
|
|
void TotEngine::saveObject(ScreenObject *object, Common::SeekableWriteStream *out) {
|
|
_sceneObjectsData->seek(object->code * kItemRegSize, SEEK_SET);
|
|
saveObjectsData(object, out);
|
|
}
|
|
|
|
DoorRegistry readDoorMetadata(Common::SeekableReadStream *in) {
|
|
DoorRegistry doorMetadata;
|
|
doorMetadata.nextScene = in->readUint16LE();
|
|
doorMetadata.exitPosX = in->readUint16LE();
|
|
doorMetadata.exitPosY = in->readUint16LE();
|
|
doorMetadata.openclosed = in->readByte();
|
|
doorMetadata.doorcode = in->readByte();
|
|
|
|
return doorMetadata;
|
|
}
|
|
|
|
Common::Point readPoint(Common::SeekableReadStream *in) {
|
|
Common::Point point;
|
|
point.x = in->readUint16LE();
|
|
point.y = in->readUint16LE();
|
|
return point;
|
|
}
|
|
|
|
RoomBitmapRegister readAuxBitmaps(Common::SeekableReadStream *in) {
|
|
RoomBitmapRegister bitmapMetadata = RoomBitmapRegister();
|
|
bitmapMetadata.bitmapPointer = in->readSint32LE();
|
|
bitmapMetadata.bitmapSize = in->readUint16LE();
|
|
bitmapMetadata.coordx = in->readUint16LE();
|
|
bitmapMetadata.coordy = in->readUint16LE();
|
|
bitmapMetadata.depth = in->readUint16LE();
|
|
return bitmapMetadata;
|
|
}
|
|
|
|
RoomObjectListEntry *readRoomObjects(Common::SeekableReadStream *in) {
|
|
RoomObjectListEntry *objectMetadata = new RoomObjectListEntry();
|
|
objectMetadata->fileIndex = in->readUint16LE();
|
|
objectMetadata->objectName = in->readPascalString();
|
|
|
|
in->skip(20 - objectMetadata->objectName.size());
|
|
|
|
return objectMetadata;
|
|
}
|
|
|
|
RoomFileRegister *TotEngine::readScreenDataFile(Common::SeekableReadStream *in) {
|
|
RoomFileRegister *screenData = new RoomFileRegister();
|
|
screenData->code = in->readUint16LE();
|
|
screenData->roomImagePointer = in->readUint32LE();
|
|
screenData->roomImageSize = in->readUint16LE();
|
|
in->read(screenData->walkAreasGrid, 40 * 28);
|
|
in->read(screenData->mouseGrid, 40 * 28);
|
|
for (int i = 0; i < 9; i++) {
|
|
for (int j = 0; j < 30; j++) {
|
|
for (int k = 0; k < 5; k++) {
|
|
screenData->trajectories[i][j][k] = readPoint(in);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
screenData->doors[i] = readDoorMetadata(in);
|
|
}
|
|
for (int i = 0; i < 15; i++) {
|
|
screenData->screenLayers[i] = readAuxBitmaps(in);
|
|
}
|
|
for (int i = 0; i < 51; i++) {
|
|
screenData->screenObjectIndex[i] = readRoomObjects(in);
|
|
}
|
|
|
|
screenData->animationFlag = in->readByte();
|
|
screenData->animationName = in->readPascalString();
|
|
in->skip(8 - screenData->animationName.size());
|
|
screenData->paletteAnimationFlag = in->readByte();
|
|
screenData->palettePointer = in->readUint16LE();
|
|
for (int i = 0; i < 300; i++) {
|
|
screenData->secondaryAnimTrajectory[i] = readPoint(in);
|
|
}
|
|
in->read(screenData->secondaryAnimDirections, 600);
|
|
screenData->secondaryTrajectoryLength = in->readUint16LE();
|
|
return screenData;
|
|
}
|
|
|
|
} // End of namespace Tot
|