Initial commit
This commit is contained in:
614
engines/hugo/file.cpp
Normal file
614
engines/hugo/file.cpp
Normal file
@@ -0,0 +1,614 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on original Hugo Trilogy source code
|
||||
*
|
||||
* Copyright (c) 1989-1995 David P. Gray
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/system.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/thumbnail.h"
|
||||
|
||||
#include "gui/saveload.h"
|
||||
|
||||
#include "image/pcx.h"
|
||||
|
||||
#include "hugo/hugo.h"
|
||||
#include "hugo/file.h"
|
||||
#include "hugo/schedule.h"
|
||||
#include "hugo/display.h"
|
||||
#include "hugo/util.h"
|
||||
#include "hugo/object.h"
|
||||
#include "hugo/text.h"
|
||||
#include "hugo/mouse.h"
|
||||
|
||||
namespace Hugo {
|
||||
|
||||
namespace {
|
||||
static const char s_bootCypher[] = "Copyright 1992, David P Gray, Gray Design Associates";
|
||||
static const int s_bootCypherLen = sizeof(s_bootCypher) - 1;
|
||||
}
|
||||
|
||||
|
||||
FileManager::FileManager(HugoEngine *vm) : _vm(vm) {
|
||||
_hasReadHeader = false;
|
||||
_firstUIFFl = true;
|
||||
|
||||
_UIFHeader->_size = 0;
|
||||
_UIFHeader->_offset = 0;
|
||||
_soundHdr->_size = 0;
|
||||
_soundHdr->_offset = 0;
|
||||
}
|
||||
|
||||
FileManager::~FileManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Name scenery and objects picture databases
|
||||
*/
|
||||
const char *FileManager::getBootFilename() const {
|
||||
return "HUGO.BSF";
|
||||
}
|
||||
|
||||
const char *FileManager::getObjectFilename() const {
|
||||
return "objects.dat";
|
||||
}
|
||||
|
||||
const char *FileManager::getSceneryFilename() const {
|
||||
return "scenery.dat";
|
||||
}
|
||||
|
||||
const char *FileManager::getSoundFilename() const {
|
||||
return "sounds.dat";
|
||||
}
|
||||
|
||||
const char *FileManager::getStringFilename() const {
|
||||
return "strings.dat";
|
||||
}
|
||||
|
||||
const char *FileManager::getUifFilename() const {
|
||||
return "uif.dat";
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a pcx file of length len. Use supplied seqPtr and image_p or
|
||||
* allocate space if NULL. Name used for errors. Returns address of seqPtr
|
||||
* Set first TRUE to initialize b_index (i.e. not reading a sequential image in file).
|
||||
*/
|
||||
Seq *FileManager::readPCX(Common::SeekableReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name) {
|
||||
debugC(1, kDebugFile, "readPCX(..., %s)", name);
|
||||
|
||||
// Allocate memory for Seq if 0
|
||||
if (seqPtr == nullptr) {
|
||||
if ((seqPtr = (Seq *)malloc(sizeof(Seq))) == nullptr)
|
||||
error("Insufficient memory to run game.");
|
||||
}
|
||||
|
||||
Image::PCXDecoder pcx;
|
||||
if (!pcx.loadStream(f))
|
||||
error("Error while reading PCX image");
|
||||
|
||||
const Graphics::Surface *pcxSurface = pcx.getSurface();
|
||||
if (pcxSurface->format.bytesPerPixel != 1)
|
||||
error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
|
||||
|
||||
// Find size of image data in 8-bit DIB format
|
||||
// Note save of x2 - marks end of valid data before garbage
|
||||
seqPtr->_lines = pcxSurface->h;
|
||||
seqPtr->_x2 = seqPtr->_bytesPerLine8 = pcxSurface->w;
|
||||
// Size of the image
|
||||
uint16 size = pcxSurface->w * pcxSurface->h;
|
||||
|
||||
// Allocate memory for image data if NULL
|
||||
if (imagePtr == nullptr)
|
||||
imagePtr = (byte *)malloc((size_t) size);
|
||||
|
||||
assert(imagePtr);
|
||||
|
||||
seqPtr->_imagePtr = imagePtr;
|
||||
for (uint16 y = 0; y < pcxSurface->h; y++)
|
||||
memcpy(imagePtr + y * pcxSurface->w, pcxSurface->getBasePtr(0, y), pcxSurface->w);
|
||||
|
||||
return seqPtr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read object file of PCC images into object supplied
|
||||
*/
|
||||
void FileManager::readImage(const int objNum, Object *objPtr) {
|
||||
debugC(1, kDebugFile, "readImage(%d, Object *objPtr)", objNum);
|
||||
|
||||
/**
|
||||
* Structure of object file lookup entry
|
||||
*/
|
||||
struct objBlock_t {
|
||||
uint32 objOffset;
|
||||
uint32 objLength;
|
||||
};
|
||||
|
||||
if (!objPtr->_seqNumb) // This object has no images
|
||||
return;
|
||||
|
||||
if (_vm->isPacked()) {
|
||||
_objectsArchive.seek((uint32)objNum * sizeof(objBlock_t), SEEK_SET);
|
||||
|
||||
objBlock_t objBlock; // Info on file within database
|
||||
objBlock.objOffset = _objectsArchive.readUint32LE();
|
||||
objBlock.objLength = _objectsArchive.readUint32LE();
|
||||
|
||||
_objectsArchive.seek(objBlock.objOffset, SEEK_SET);
|
||||
} else {
|
||||
Common::Path buf;
|
||||
buf = _vm->_picDir.appendComponent(Common::String(_vm->_text->getNoun(objPtr->_nounIndex, 0)) + ".PIX");
|
||||
if (!_objectsArchive.open(buf)) {
|
||||
buf = Common::String(_vm->_text->getNoun(objPtr->_nounIndex, 0)) + ".PIX";
|
||||
if (!_objectsArchive.open(buf))
|
||||
error("File not found: %s", buf.toString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
bool firstImgFl = true; // Initializes pcx read function
|
||||
Seq *seqPtr = nullptr; // Ptr to sequence structure
|
||||
|
||||
// Now read the images into an images list
|
||||
for (int j = 0; j < objPtr->_seqNumb; j++) { // for each sequence
|
||||
for (int k = 0; k < objPtr->_seqList[j]._imageNbr; k++) { // each image
|
||||
if (k == 0) { // First image
|
||||
// Read this image - allocate both seq and image memory
|
||||
seqPtr = readPCX(_objectsArchive, nullptr, nullptr, firstImgFl, _vm->_text->getNoun(objPtr->_nounIndex, 0));
|
||||
objPtr->_seqList[j]._seqPtr = seqPtr;
|
||||
firstImgFl = false;
|
||||
} else { // Subsequent image
|
||||
// Read this image - allocate both seq and image memory
|
||||
seqPtr->_nextSeqPtr = readPCX(_objectsArchive, nullptr, nullptr, firstImgFl, _vm->_text->getNoun(objPtr->_nounIndex, 0));
|
||||
seqPtr = seqPtr->_nextSeqPtr;
|
||||
}
|
||||
|
||||
// Compute the bounding box - x1, x2, y1, y2
|
||||
// Note use of x2 - marks end of valid data in row
|
||||
uint16 x2 = seqPtr->_x2;
|
||||
seqPtr->_x1 = seqPtr->_x2;
|
||||
seqPtr->_x2 = 0;
|
||||
seqPtr->_y1 = seqPtr->_lines;
|
||||
seqPtr->_y2 = 0;
|
||||
|
||||
ImagePtr dibPtr = seqPtr->_imagePtr;
|
||||
for (int y = 0; y < seqPtr->_lines; y++, dibPtr += seqPtr->_bytesPerLine8 - x2) {
|
||||
for (int x = 0; x < x2; x++) {
|
||||
if (*dibPtr++) { // Some data found
|
||||
if (x < seqPtr->_x1)
|
||||
seqPtr->_x1 = x;
|
||||
if (x > seqPtr->_x2)
|
||||
seqPtr->_x2 = x;
|
||||
if (y < seqPtr->_y1)
|
||||
seqPtr->_y1 = y;
|
||||
if (y > seqPtr->_y2)
|
||||
seqPtr->_y2 = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(seqPtr);
|
||||
seqPtr->_nextSeqPtr = objPtr->_seqList[j]._seqPtr; // loop linked list to head
|
||||
}
|
||||
|
||||
// Set the current image sequence to first or last
|
||||
switch (objPtr->_cycling) {
|
||||
case kCycleInvisible: // (May become visible later)
|
||||
case kCycleAlmostInvisible:
|
||||
case kCycleNotCycling:
|
||||
case kCycleForward:
|
||||
objPtr->_currImagePtr = objPtr->_seqList[0]._seqPtr;
|
||||
break;
|
||||
case kCycleBackward:
|
||||
objPtr->_currImagePtr = seqPtr;
|
||||
break;
|
||||
default:
|
||||
warning("Unexpected cycling: %d", objPtr->_cycling);
|
||||
}
|
||||
|
||||
if (!_vm->isPacked())
|
||||
_objectsArchive.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read sound (or music) file data. Call with SILENCE to free-up
|
||||
* any allocated memory. Also returns size of data
|
||||
*/
|
||||
SoundPtr FileManager::getSound(const int16 sound, uint16 *size) {
|
||||
debugC(1, kDebugFile, "getSound(%d)", sound);
|
||||
|
||||
// No more to do if SILENCE (called for cleanup purposes)
|
||||
if (sound == _vm->_soundSilence)
|
||||
return nullptr;
|
||||
|
||||
// Open sounds file
|
||||
Common::File fp; // Handle to SOUND_FILE
|
||||
if (!fp.open(getSoundFilename())) {
|
||||
warning("Hugo Error: File not found %s", getSoundFilename());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!_hasReadHeader) {
|
||||
for (int i = 0; i < kMaxSounds; i++) {
|
||||
_soundHdr[i]._size = fp.readUint16LE();
|
||||
_soundHdr[i]._offset = fp.readUint32LE();
|
||||
}
|
||||
if (fp.err())
|
||||
error("Wrong sound file format");
|
||||
_hasReadHeader = true;
|
||||
}
|
||||
|
||||
*size = _soundHdr[sound]._size;
|
||||
if (*size == 0)
|
||||
error("Wrong sound file format or missing sound %d", sound);
|
||||
|
||||
// Allocate memory for sound or music, if possible
|
||||
SoundPtr soundPtr = (byte *)malloc(_soundHdr[sound]._size); // Ptr to sound data
|
||||
assert(soundPtr);
|
||||
|
||||
// Seek to data and read it
|
||||
fp.seek(_soundHdr[sound]._offset, SEEK_SET);
|
||||
if (fp.read(soundPtr, _soundHdr[sound]._size) != _soundHdr[sound]._size)
|
||||
error("Wrong sound file format");
|
||||
|
||||
fp.close();
|
||||
|
||||
return soundPtr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save game to supplied slot
|
||||
*/
|
||||
bool FileManager::saveGame(const int16 slot, const Common::String &descrip) {
|
||||
debugC(1, kDebugFile, "saveGame(%d, %s)", slot, descrip.c_str());
|
||||
|
||||
int16 savegameId;
|
||||
Common::String savegameDescription;
|
||||
|
||||
if (slot == -1) {
|
||||
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
|
||||
savegameId = dialog->runModalWithCurrentTarget();
|
||||
savegameDescription = dialog->getResultString();
|
||||
delete dialog;
|
||||
} else {
|
||||
savegameId = slot;
|
||||
if (!descrip.empty()) {
|
||||
savegameDescription = descrip;
|
||||
} else {
|
||||
savegameDescription = Common::String::format("Quick save #%d", slot);
|
||||
}
|
||||
}
|
||||
|
||||
if (savegameId < 0) // dialog aborted
|
||||
return false;
|
||||
|
||||
Common::String savegameFile = _vm->getSaveStateName(savegameId);
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::OutSaveFile *out = saveMan->openForSaving(savegameFile);
|
||||
|
||||
if (!out) {
|
||||
warning("Can't create file '%s', game not saved", savegameFile.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write version. We can't restore from obsolete versions
|
||||
out->writeByte(kSavegameVersion);
|
||||
|
||||
if (savegameDescription == "") {
|
||||
savegameDescription = "Untitled savegame";
|
||||
}
|
||||
|
||||
out->writeSint16BE(savegameDescription.size() + 1);
|
||||
out->write(savegameDescription.c_str(), savegameDescription.size() + 1);
|
||||
|
||||
Graphics::saveThumbnail(*out);
|
||||
|
||||
TimeDate curTime;
|
||||
_vm->_system->getTimeAndDate(curTime);
|
||||
|
||||
uint32 saveDate = (curTime.tm_mday & 0xFF) << 24 | ((curTime.tm_mon + 1) & 0xFF) << 16 | ((curTime.tm_year + 1900) & 0xFFFF);
|
||||
uint16 saveTime = (curTime.tm_hour & 0xFF) << 8 | ((curTime.tm_min) & 0xFF);
|
||||
|
||||
out->writeUint32BE(saveDate);
|
||||
out->writeUint16BE(saveTime);
|
||||
|
||||
_vm->_object->saveObjects(out);
|
||||
|
||||
const Status &gameStatus = _vm->getGameStatus();
|
||||
|
||||
// Save whether hero image is swapped
|
||||
out->writeByte(_vm->_heroImage);
|
||||
|
||||
// Save score
|
||||
out->writeSint16BE(_vm->getScore());
|
||||
|
||||
// Save story mode
|
||||
out->writeByte((gameStatus._storyModeFl) ? 1 : 0);
|
||||
|
||||
// Save jumpexit mode
|
||||
out->writeByte((_vm->_mouse->getJumpExitFl()) ? 1 : 0);
|
||||
|
||||
// Save gameover status
|
||||
out->writeByte((gameStatus._gameOverFl) ? 1 : 0);
|
||||
|
||||
// Save screen states
|
||||
for (int i = 0; i < _vm->_numStates; i++)
|
||||
out->writeByte(_vm->_screenStates[i]);
|
||||
|
||||
_vm->_scheduler->saveSchedulerData(out);
|
||||
// Save palette table
|
||||
_vm->_screen->savePal(out);
|
||||
|
||||
// Save maze status
|
||||
out->writeByte((_vm->_maze._enabledFl) ? 1 : 0);
|
||||
out->writeByte(_vm->_maze._size);
|
||||
out->writeSint16BE(_vm->_maze._x1);
|
||||
out->writeSint16BE(_vm->_maze._y1);
|
||||
out->writeSint16BE(_vm->_maze._x2);
|
||||
out->writeSint16BE(_vm->_maze._y2);
|
||||
out->writeSint16BE(_vm->_maze._x3);
|
||||
out->writeSint16BE(_vm->_maze._x4);
|
||||
out->writeByte(_vm->_maze._firstScreenIndex);
|
||||
|
||||
out->writeByte((byte)_vm->getGameStatus()._viewState);
|
||||
|
||||
out->finalize();
|
||||
|
||||
delete out;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore game from supplied slot number
|
||||
*/
|
||||
bool FileManager::restoreGame(const int16 slot) {
|
||||
debugC(1, kDebugFile, "restoreGame(%d)", slot);
|
||||
|
||||
int16 savegameId;
|
||||
|
||||
if (slot == -1) {
|
||||
GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
|
||||
savegameId = dialog->runModalWithCurrentTarget();
|
||||
delete dialog;
|
||||
} else {
|
||||
savegameId = slot;
|
||||
}
|
||||
|
||||
if (savegameId < 0) // dialog aborted
|
||||
return false;
|
||||
|
||||
Common::String savegameFile = _vm->getSaveStateName(savegameId);
|
||||
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
|
||||
Common::InSaveFile *in = saveMan->openForLoading(savegameFile);
|
||||
|
||||
if (!in)
|
||||
return false;
|
||||
|
||||
// Initialize new-game status
|
||||
_vm->initStatus();
|
||||
|
||||
// Check version, can't restore from different versions
|
||||
int saveVersion = in->readByte();
|
||||
if (saveVersion != kSavegameVersion) {
|
||||
warning("Savegame of incompatible version");
|
||||
delete in;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip over description
|
||||
int32 saveGameNameSize = in->readSint16BE();
|
||||
in->skip(saveGameNameSize);
|
||||
|
||||
Graphics::skipThumbnail(*in);
|
||||
|
||||
in->skip(6); // Skip date & time
|
||||
|
||||
// If hero image is currently swapped, swap it back before restore
|
||||
if (_vm->_heroImage != kHeroIndex)
|
||||
_vm->_object->swapImages(kHeroIndex, _vm->_heroImage, true);
|
||||
|
||||
_vm->_object->restoreObjects(in);
|
||||
|
||||
_vm->_heroImage = in->readByte();
|
||||
|
||||
// Restore ptrs to currently loaded objects
|
||||
_vm->_object->restoreAllSeq();
|
||||
|
||||
// If hero swapped in saved game, swap it
|
||||
byte heroImg = _vm->_heroImage;
|
||||
if (heroImg != kHeroIndex)
|
||||
_vm->_object->swapImages(kHeroIndex, _vm->_heroImage, true);
|
||||
_vm->_heroImage = heroImg;
|
||||
|
||||
Status &gameStatus = _vm->getGameStatus();
|
||||
|
||||
int score = in->readSint16BE();
|
||||
_vm->setScore(score);
|
||||
#ifdef USE_TTS
|
||||
_vm->_previousScore = -1;
|
||||
#endif
|
||||
|
||||
gameStatus._storyModeFl = (in->readByte() == 1);
|
||||
_vm->_mouse->setJumpExitFl(in->readByte() == 1);
|
||||
gameStatus._gameOverFl = (in->readByte() == 1);
|
||||
for (int i = 0; i < _vm->_numStates; i++)
|
||||
_vm->_screenStates[i] = in->readByte();
|
||||
|
||||
_vm->_scheduler->restoreSchedulerData(in);
|
||||
|
||||
// Restore palette and change it if necessary
|
||||
_vm->_screen->restorePal(in);
|
||||
|
||||
// Restore maze status
|
||||
_vm->_maze._enabledFl = (in->readByte() == 1);
|
||||
_vm->_maze._size = in->readByte();
|
||||
_vm->_maze._x1 = in->readSint16BE();
|
||||
_vm->_maze._y1 = in->readSint16BE();
|
||||
_vm->_maze._x2 = in->readSint16BE();
|
||||
_vm->_maze._y2 = in->readSint16BE();
|
||||
_vm->_maze._x3 = in->readSint16BE();
|
||||
_vm->_maze._x4 = in->readSint16BE();
|
||||
_vm->_maze._firstScreenIndex = in->readByte();
|
||||
|
||||
_vm->_scheduler->restoreScreen(*_vm->_screenPtr);
|
||||
if ((_vm->getGameStatus()._viewState = (Vstate) in->readByte()) != kViewPlay)
|
||||
_vm->_screen->hideCursor();
|
||||
|
||||
|
||||
delete in;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads boot file for program environment. Fatal error if not there or
|
||||
* file checksum is bad. De-crypts structure while checking checksum
|
||||
*/
|
||||
void FileManager::readBootFile() {
|
||||
debugC(1, kDebugFile, "readBootFile()");
|
||||
|
||||
Common::File ofp;
|
||||
if (!ofp.open(getBootFilename())) {
|
||||
if (_vm->_gameVariant == kGameVariantH1Dos) {
|
||||
//TODO initialize properly _boot structure
|
||||
warning("readBootFile - Skipping as H1 Dos may be a freeware");
|
||||
memset(_vm->_boot._distrib, '\0', sizeof(_vm->_boot._distrib));
|
||||
_vm->_boot._registered = kRegFreeware;
|
||||
return;
|
||||
} else if (_vm->getPlatform() == Common::kPlatformDOS) {
|
||||
warning("readBootFile - Skipping as H2 and H3 Dos may be shareware");
|
||||
memset(_vm->_boot._distrib, '\0', sizeof(_vm->_boot._distrib));
|
||||
_vm->_boot._registered = kRegShareware;
|
||||
return;
|
||||
} else {
|
||||
_vm->notifyBox(Common::String::format("Missing startup file '%s'", getBootFilename()));
|
||||
_vm->getGameStatus()._doQuitFl = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ofp.size() < (int32)sizeof(_vm->_boot)) {
|
||||
_vm->notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename()));
|
||||
_vm->getGameStatus()._doQuitFl = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_vm->_boot._checksum = ofp.readByte();
|
||||
_vm->_boot._registered = ofp.readByte();
|
||||
ofp.read(_vm->_boot._pbswitch, sizeof(_vm->_boot._pbswitch));
|
||||
ofp.read(_vm->_boot._distrib, sizeof(_vm->_boot._distrib));
|
||||
_vm->_boot._exitLen = ofp.readUint16LE();
|
||||
ofp.close();
|
||||
|
||||
byte *p = (byte *)&_vm->_boot;
|
||||
|
||||
byte checksum = 0;
|
||||
for (uint32 i = 0; i < sizeof(_vm->_boot); i++) {
|
||||
checksum ^= p[i];
|
||||
p[i] ^= s_bootCypher[i % s_bootCypherLen];
|
||||
}
|
||||
|
||||
if (checksum) {
|
||||
_vm->notifyBox(Common::String::format("Corrupted startup file '%s'", getBootFilename()));
|
||||
_vm->getGameStatus()._doQuitFl = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns address of uif_hdr[id], reading it in if first call
|
||||
* This file contains, between others, the bitmaps of the fonts used in the application
|
||||
* UIF means User interface database (Windows Only)
|
||||
*/
|
||||
UifHdr *FileManager::getUIFHeader(const Uif id) {
|
||||
debugC(1, kDebugFile, "getUIFHeader(%d)", id);
|
||||
|
||||
// Initialize offset lookup if not read yet
|
||||
if (_firstUIFFl) {
|
||||
_firstUIFFl = false;
|
||||
// Open unbuffered to do far read
|
||||
Common::File ip; // Image data file
|
||||
if (!ip.open(getUifFilename()))
|
||||
error("File not found: %s", getUifFilename());
|
||||
|
||||
if (ip.size() < (int32)sizeof(_UIFHeader))
|
||||
error("Wrong UIF file format");
|
||||
|
||||
for (int i = 0; i < kMaxUifs; ++i) {
|
||||
_UIFHeader[i]._size = ip.readUint16LE();
|
||||
_UIFHeader[i]._offset = ip.readUint32LE();
|
||||
}
|
||||
|
||||
ip.close();
|
||||
}
|
||||
return &_UIFHeader[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Read uif item into supplied buffer.
|
||||
*/
|
||||
void FileManager::readUIFItem(const int16 id, byte *buf) {
|
||||
debugC(1, kDebugFile, "readUIFItem(%d, ...)", id);
|
||||
|
||||
// Open uif file to read data
|
||||
Common::File ip; // UIF_FILE handle
|
||||
if (!ip.open(getUifFilename()))
|
||||
error("File not found: %s", getUifFilename());
|
||||
|
||||
// Seek to data
|
||||
UifHdr *_UIFHeaderPtr = getUIFHeader((Uif)id);
|
||||
ip.seek(_UIFHeaderPtr->_offset, SEEK_SET);
|
||||
|
||||
// We support pcx images and straight data
|
||||
Seq *dummySeq; // Dummy Seq for image data
|
||||
switch (id) {
|
||||
case UIF_IMAGES: // Read uif images file
|
||||
dummySeq = readPCX(ip, nullptr, buf, true, getUifFilename());
|
||||
free(dummySeq);
|
||||
break;
|
||||
default: // Read file data into supplied array
|
||||
if (ip.read(buf, _UIFHeaderPtr->_size) != _UIFHeaderPtr->_size)
|
||||
error("Wrong UIF file format");
|
||||
break;
|
||||
}
|
||||
|
||||
ip.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the uif image file (inventory icons)
|
||||
*/
|
||||
void FileManager::readUIFImages() {
|
||||
debugC(1, kDebugFile, "readUIFImages()");
|
||||
|
||||
readUIFItem(UIF_IMAGES, _vm->_screen->getGUIBuffer()); // Read all uif images
|
||||
}
|
||||
|
||||
} // End of namespace Hugo
|
||||
Reference in New Issue
Block a user