SCI: adding virtual lists for qfg-import rooms
now lists import files of all possible games, adds game title before that, removes game prefixes for all files svn-id: r52441
This commit is contained in:
parent
8ba02169f8
commit
ff7476d9f1
8 changed files with 131 additions and 80 deletions
|
@ -101,13 +101,9 @@ enum {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
reg_t file_open(EngineState *s, const char *filename, int mode) {
|
reg_t file_open(EngineState *s, const char *filename, int mode, bool unwrapFilename) {
|
||||||
// QfG3 character import prepends /\ to the filenames.
|
|
||||||
if (filename[0] == '/' && filename[1] == '\\')
|
|
||||||
filename += 2;
|
|
||||||
|
|
||||||
Common::String englishName = g_sci->getSciLanguageString(filename, K_LANG_ENGLISH);
|
Common::String englishName = g_sci->getSciLanguageString(filename, K_LANG_ENGLISH);
|
||||||
const Common::String wrappedName = g_sci->wrapFilename(englishName);
|
Common::String wrappedName = unwrapFilename ? g_sci->wrapFilename(englishName) : englishName;
|
||||||
Common::SeekableReadStream *inFile = 0;
|
Common::SeekableReadStream *inFile = 0;
|
||||||
Common::WriteStream *outFile = 0;
|
Common::WriteStream *outFile = 0;
|
||||||
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
|
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
|
||||||
|
@ -183,7 +179,7 @@ reg_t kFOpen(EngineState *s, int argc, reg_t *argv) {
|
||||||
int mode = argv[1].toUint16();
|
int mode = argv[1].toUint16();
|
||||||
|
|
||||||
debugC(2, kDebugLevelFile, "kFOpen(%s,0x%x)", name.c_str(), mode);
|
debugC(2, kDebugLevelFile, "kFOpen(%s,0x%x)", name.c_str(), mode);
|
||||||
return file_open(s, name.c_str(), mode);
|
return file_open(s, name.c_str(), mode, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FileHandle *getFileFromHandle(EngineState *s, uint handle) {
|
static FileHandle *getFileFromHandle(EngineState *s, uint handle) {
|
||||||
|
@ -739,45 +735,6 @@ reg_t kValidPath(EngineState *s, int argc, reg_t *argv) {
|
||||||
return make_reg(0, 1);
|
return make_reg(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t DirSeeker::firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan) {
|
|
||||||
// Verify that we are given a valid buffer
|
|
||||||
if (!buffer.segment) {
|
|
||||||
error("DirSeeker::firstFile('%s') invoked with invalid buffer", mask.c_str());
|
|
||||||
return NULL_REG;
|
|
||||||
}
|
|
||||||
_outbuffer = buffer;
|
|
||||||
|
|
||||||
// Prefix the mask
|
|
||||||
const Common::String wrappedMask = g_sci->wrapFilename(mask);
|
|
||||||
|
|
||||||
// Obtain a list of all savefiles matching the given mask
|
|
||||||
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
|
|
||||||
_savefiles = saveFileMan->listSavefiles(wrappedMask);
|
|
||||||
|
|
||||||
// Reset the list iterator and write the first match to the output buffer,
|
|
||||||
// if any.
|
|
||||||
_iter = _savefiles.begin();
|
|
||||||
return nextFile(segMan);
|
|
||||||
}
|
|
||||||
|
|
||||||
reg_t DirSeeker::nextFile(SegManager *segMan) {
|
|
||||||
if (_iter == _savefiles.end()) {
|
|
||||||
return NULL_REG;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Common::String wrappedString = *_iter;
|
|
||||||
|
|
||||||
// Strip the prefix
|
|
||||||
Common::String string = g_sci->unwrapFilename(wrappedString);
|
|
||||||
if (string.size() > 12)
|
|
||||||
string = Common::String(string.c_str(), 12);
|
|
||||||
segMan->strcpy(_outbuffer, string.c_str());
|
|
||||||
|
|
||||||
// Return the result and advance the list iterator :)
|
|
||||||
++_iter;
|
|
||||||
return _outbuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
reg_t kFileIO(EngineState *s, int argc, reg_t *argv) {
|
reg_t kFileIO(EngineState *s, int argc, reg_t *argv) {
|
||||||
if (!s)
|
if (!s)
|
||||||
return make_reg(0, getSciVersion());
|
return make_reg(0, getSciVersion());
|
||||||
|
@ -790,6 +747,7 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
|
||||||
// SCI32 can call K_FILEIO_OPEN with only one argument. It seems to
|
// SCI32 can call K_FILEIO_OPEN with only one argument. It seems to
|
||||||
// just be checking if it exists.
|
// just be checking if it exists.
|
||||||
int mode = (argc < 2) ? (int)_K_FILE_MODE_OPEN_OR_FAIL : argv[1].toUint16();
|
int mode = (argc < 2) ? (int)_K_FILE_MODE_OPEN_OR_FAIL : argv[1].toUint16();
|
||||||
|
bool unwrapFilename = true;
|
||||||
|
|
||||||
// SQ4 floppy prepends /\ to the filenames
|
// SQ4 floppy prepends /\ to the filenames
|
||||||
if (name.hasPrefix("/\\")) {
|
if (name.hasPrefix("/\\")) {
|
||||||
|
@ -813,6 +771,12 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
|
||||||
}
|
}
|
||||||
debugC(2, kDebugLevelFile, "kFileIO(open): %s, 0x%x", name.c_str(), mode);
|
debugC(2, kDebugLevelFile, "kFileIO(open): %s, 0x%x", name.c_str(), mode);
|
||||||
|
|
||||||
|
// QFG import rooms get a virtual filelisting instead of an actual one
|
||||||
|
if (g_sci->inQfGImportRoom()) {
|
||||||
|
// we need to find out what the user actually selected, "savedHeroes" is already destroyed
|
||||||
|
// when we get here. That's why we need to remember selection via kDrawControl
|
||||||
|
name = s->_dirseeker.getVirtualFilename(s->_chosenQfGImportItem);
|
||||||
|
unwrapFilename = false;
|
||||||
// Since we're not wrapping/unwrapping save files for QFG import screens,
|
// Since we're not wrapping/unwrapping save files for QFG import screens,
|
||||||
// the name of the save file will almost certainly be over 12 characters in
|
// the name of the save file will almost certainly be over 12 characters in
|
||||||
// length. Compensate for that fact here, by cutting off the last character
|
// length. Compensate for that fact here, by cutting off the last character
|
||||||
|
@ -835,7 +799,7 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return file_open(s, name.c_str(), mode);
|
return file_open(s, name.c_str(), mode, unwrapFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
|
reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
@ -962,24 +926,104 @@ reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) {
|
||||||
return SIGNAL_REG;
|
return SIGNAL_REG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DirSeeker::addAsVirtualFiles(Common::String title, Common::String fileMask) {
|
||||||
|
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
|
||||||
|
Common::StringArray foundFiles = saveFileMan->listSavefiles(fileMask);
|
||||||
|
if (!foundFiles.empty()) {
|
||||||
|
_files.push_back(title);
|
||||||
|
_virtualFiles.push_back("");
|
||||||
|
Common::StringArray::iterator it;
|
||||||
|
Common::StringArray::iterator it_end = foundFiles.end();
|
||||||
|
for (it = foundFiles.begin(); it != it_end; it++) {
|
||||||
|
Common::String regularFilename = *it;
|
||||||
|
Common::String wrappedFilename = Common::String(regularFilename.c_str() + fileMask.size() - 1);
|
||||||
|
// We need to remove the prefix for display purposes
|
||||||
|
_files.push_back(wrappedFilename);
|
||||||
|
// but remember the actual name as well
|
||||||
|
_virtualFiles.push_back(regularFilename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String DirSeeker::getVirtualFilename(uint fileNumber) {
|
||||||
|
if (fileNumber >= _virtualFiles.size())
|
||||||
|
error("invalid virtual filename access");
|
||||||
|
return _virtualFiles[fileNumber];
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_t DirSeeker::firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan) {
|
||||||
|
// Verify that we are given a valid buffer
|
||||||
|
if (!buffer.segment) {
|
||||||
|
error("DirSeeker::firstFile('%s') invoked with invalid buffer", mask.c_str());
|
||||||
|
return NULL_REG;
|
||||||
|
}
|
||||||
|
_outbuffer = buffer;
|
||||||
|
_files.clear();
|
||||||
|
_virtualFiles.clear();
|
||||||
|
|
||||||
|
int QfGImport = g_sci->inQfGImportRoom();
|
||||||
|
if (QfGImport) {
|
||||||
|
_files.clear();
|
||||||
|
addAsVirtualFiles("-QfG1-", "qfg1-*");
|
||||||
|
addAsVirtualFiles("-QfG1VGA-", "qfg1vga-*");
|
||||||
|
if (QfGImport > 2)
|
||||||
|
addAsVirtualFiles("-QfG2-", "qfg2-*");
|
||||||
|
if (QfGImport > 3)
|
||||||
|
addAsVirtualFiles("-QfG3-", "qfg3-*");
|
||||||
|
|
||||||
|
if (QfGImport == 3) {
|
||||||
|
// QfG3 sorts the filelisting itself, we can't let that happen otherwise our
|
||||||
|
// virtual list would go out-of-sync
|
||||||
|
SegManager *segMan = g_sci->getEngineState()->_segMan;
|
||||||
|
reg_t savedHeros = segMan->findObjectByName("savedHeros");
|
||||||
|
if (!savedHeros.isNull())
|
||||||
|
writeSelectorValue(segMan, savedHeros, SELECTOR(sort), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Prefix the mask
|
||||||
|
const Common::String wrappedMask = g_sci->wrapFilename(mask);
|
||||||
|
|
||||||
|
// Obtain a list of all files matching the given mask
|
||||||
|
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
|
||||||
|
_files = saveFileMan->listSavefiles(wrappedMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the list iterator and write the first match to the output buffer,
|
||||||
|
// if any.
|
||||||
|
_iter = _files.begin();
|
||||||
|
return nextFile(segMan);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_t DirSeeker::nextFile(SegManager *segMan) {
|
||||||
|
if (_iter == _files.end()) {
|
||||||
|
return NULL_REG;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::String string;
|
||||||
|
|
||||||
|
if (_virtualFiles.empty()) {
|
||||||
|
// Strip the prefix, if we don't got a virtual filelisting
|
||||||
|
const Common::String wrappedString = *_iter;
|
||||||
|
string = g_sci->unwrapFilename(wrappedString);
|
||||||
|
} else {
|
||||||
|
string = *_iter;
|
||||||
|
}
|
||||||
|
if (string.size() > 12)
|
||||||
|
string = Common::String(string.c_str(), 12);
|
||||||
|
segMan->strcpy(_outbuffer, string.c_str());
|
||||||
|
|
||||||
|
// Return the result and advance the list iterator :)
|
||||||
|
++_iter;
|
||||||
|
return _outbuffer;
|
||||||
|
}
|
||||||
|
|
||||||
reg_t kFileIOFindFirst(EngineState *s, int argc, reg_t *argv) {
|
reg_t kFileIOFindFirst(EngineState *s, int argc, reg_t *argv) {
|
||||||
Common::String mask = s->_segMan->getString(argv[0]);
|
Common::String mask = s->_segMan->getString(argv[0]);
|
||||||
reg_t buf = argv[1];
|
reg_t buf = argv[1];
|
||||||
int attr = argv[2].toUint16(); // We won't use this, Win32 might, though...
|
int attr = argv[2].toUint16(); // We won't use this, Win32 might, though...
|
||||||
debugC(2, kDebugLevelFile, "kFileIO(findFirst): %s, 0x%x", mask.c_str(), attr);
|
debugC(2, kDebugLevelFile, "kFileIO(findFirst): %s, 0x%x", mask.c_str(), attr);
|
||||||
|
|
||||||
// Change the file mask in QFG character import screens. The game
|
|
||||||
// is looking for *.*, but that may well include other files as well,
|
|
||||||
// thus limit the file mask to only include exported characters.
|
|
||||||
if (g_sci->isQFGImportScreen())
|
|
||||||
mask = "qfg*.sav";
|
|
||||||
|
|
||||||
// QfG3 uses "/\*.*" for the character import, QfG4 uses "/\*"
|
|
||||||
if (mask.hasPrefix("/\\")) {
|
|
||||||
mask.deleteChar(0);
|
|
||||||
mask.deleteChar(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We remove ".*". mask will get prefixed, so we will return all additional files for that gameid
|
// We remove ".*". mask will get prefixed, so we will return all additional files for that gameid
|
||||||
if (mask == "*.*")
|
if (mask == "*.*")
|
||||||
mask = "*";
|
mask = "*";
|
||||||
|
|
|
@ -944,6 +944,7 @@ reg_t kDrawControl(EngineState *s, int argc, reg_t *argv) {
|
||||||
"for Quest for Glory 2. Example: 'qfg2-thief.sav'.");
|
"for Quest for Glory 2. Example: 'qfg2-thief.sav'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s->_chosenQfGImportItem = readSelectorValue(s->_segMan, controlObject, SELECTOR(mark));
|
||||||
}
|
}
|
||||||
|
|
||||||
_k_GenericDrawControl(s, controlObject, false);
|
_k_GenericDrawControl(s, controlObject, false);
|
||||||
|
|
|
@ -86,7 +86,8 @@ void Kernel::mapSelectors() {
|
||||||
// window
|
// window
|
||||||
FIND_SELECTOR(cursor);
|
FIND_SELECTOR(cursor);
|
||||||
FIND_SELECTOR(max);
|
FIND_SELECTOR(max);
|
||||||
// mark
|
FIND_SELECTOR(mark);
|
||||||
|
FIND_SELECTOR(sort);
|
||||||
// who
|
// who
|
||||||
FIND_SELECTOR(message);
|
FIND_SELECTOR(message);
|
||||||
// edit
|
// edit
|
||||||
|
|
|
@ -58,7 +58,9 @@ struct SelectorCache {
|
||||||
Selector state, font, type;///< Used by controls
|
Selector state, font, type;///< Used by controls
|
||||||
// window
|
// window
|
||||||
Selector cursor, max; ///< Used by EditControl
|
Selector cursor, max; ///< Used by EditControl
|
||||||
// mark, who
|
Selector mark; //< Used by list controls
|
||||||
|
Selector sort; //< Used by list controls (script internal, is needed by us for QfG3 import room)
|
||||||
|
// who
|
||||||
Selector message; ///< Used by GetEvent
|
Selector message; ///< Used by GetEvent
|
||||||
// edit
|
// edit
|
||||||
Selector play; ///< Play function (first function to be called)
|
Selector play; ///< Play function (first function to be called)
|
||||||
|
|
|
@ -110,6 +110,8 @@ void EngineState::reset(bool isRestoring) {
|
||||||
_lastSaveVirtualId = SAVEGAMEID_OFFICIALRANGE_START;
|
_lastSaveVirtualId = SAVEGAMEID_OFFICIALRANGE_START;
|
||||||
_lastSaveNewId = 0;
|
_lastSaveNewId = 0;
|
||||||
|
|
||||||
|
_chosenQfGImportItem = 0;
|
||||||
|
|
||||||
scriptStepCounter = 0;
|
scriptStepCounter = 0;
|
||||||
scriptGCInterval = GC_INTERVAL;
|
scriptGCInterval = GC_INTERVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,17 +59,23 @@ enum AbortGameState {
|
||||||
class DirSeeker {
|
class DirSeeker {
|
||||||
protected:
|
protected:
|
||||||
reg_t _outbuffer;
|
reg_t _outbuffer;
|
||||||
Common::StringArray _savefiles;
|
Common::StringArray _files;
|
||||||
|
Common::StringArray _virtualFiles;
|
||||||
Common::StringArray::const_iterator _iter;
|
Common::StringArray::const_iterator _iter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DirSeeker() {
|
DirSeeker() {
|
||||||
_outbuffer = NULL_REG;
|
_outbuffer = NULL_REG;
|
||||||
_iter = _savefiles.begin();
|
_iter = _files.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan);
|
reg_t firstFile(const Common::String &mask, reg_t buffer, SegManager *segMan);
|
||||||
reg_t nextFile(SegManager *segMan);
|
reg_t nextFile(SegManager *segMan);
|
||||||
|
|
||||||
|
Common::String getVirtualFilename(uint fileNumber);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addAsVirtualFiles(Common::String title, Common::String fileMask);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -139,6 +145,8 @@ public:
|
||||||
int16 _lastSaveVirtualId; // last virtual id fed to kSaveGame, if no kGetSaveFiles was called inbetween
|
int16 _lastSaveVirtualId; // last virtual id fed to kSaveGame, if no kGetSaveFiles was called inbetween
|
||||||
int16 _lastSaveNewId; // last newly created filename-id by kSaveGame
|
int16 _lastSaveNewId; // last newly created filename-id by kSaveGame
|
||||||
|
|
||||||
|
uint _chosenQfGImportItem; // Remembers the item selected in QfG import rooms
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* VM Information */
|
/* VM Information */
|
||||||
|
|
||||||
|
|
|
@ -641,34 +641,27 @@ Common::String SciEngine::getFilePrefix() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::String SciEngine::wrapFilename(const Common::String &name) const {
|
Common::String SciEngine::wrapFilename(const Common::String &name) const {
|
||||||
// Do not wrap the game prefix when reading files in QFG import screens.
|
return getFilePrefix() + "-" + name;
|
||||||
// That way, we can read exported characters from all QFG games, as
|
|
||||||
// intended.
|
|
||||||
return !isQFGImportScreen() ? getFilePrefix() + "-" + name : name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::String SciEngine::unwrapFilename(const Common::String &name) const {
|
Common::String SciEngine::unwrapFilename(const Common::String &name) const {
|
||||||
Common::String prefix = getFilePrefix() + "-";
|
Common::String prefix = getFilePrefix() + "-";
|
||||||
// Do not unwrap the file name when reading files in QFG import screens.
|
if (name.hasPrefix(prefix.c_str()))
|
||||||
// We don't wrap the game ID prefix in these screens in order to read
|
|
||||||
// save states from all QFG games.
|
|
||||||
if (name.hasPrefix(prefix.c_str()) && !isQFGImportScreen())
|
|
||||||
return Common::String(name.c_str() + prefix.size());
|
return Common::String(name.c_str() + prefix.size());
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SciEngine::isQFGImportScreen() const {
|
int SciEngine::inQfGImportRoom() const {
|
||||||
if (_gameId == GID_QFG2 && _gamestate->currentRoomNumber() == 805) {
|
if (_gameId == GID_QFG2 && _gamestate->currentRoomNumber() == 805) {
|
||||||
// QFG2 character import screen
|
// QFG2 character import screen
|
||||||
return true;
|
return 2;
|
||||||
} else if (_gameId == GID_QFG3 && _gamestate->currentRoomNumber() == 54) {
|
} else if (_gameId == GID_QFG3 && _gamestate->currentRoomNumber() == 54) {
|
||||||
// QFG3 character import screen
|
// QFG3 character import screen
|
||||||
return true;
|
return 3;
|
||||||
} else if (_gameId == GID_QFG4 && _gamestate->currentRoomNumber() == 54) {
|
} else if (_gameId == GID_QFG4 && _gamestate->currentRoomNumber() == 54) {
|
||||||
return true;
|
return 4;
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SciEngine::pauseEngineIntern(bool pause) {
|
void SciEngine::pauseEngineIntern(bool pause) {
|
||||||
|
|
|
@ -251,10 +251,10 @@ public:
|
||||||
Common::String unwrapFilename(const Common::String &name) const;
|
Common::String unwrapFilename(const Common::String &name) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if we are in a QFG import screen, where special handling
|
* Checks if we are in a QfG import screen, where special handling
|
||||||
* of save states is performed.
|
* of file-listings is performed.
|
||||||
*/
|
*/
|
||||||
bool isQFGImportScreen() const;
|
int inQfGImportRoom() const;
|
||||||
|
|
||||||
void sleep(uint32 msecs);
|
void sleep(uint32 msecs);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue