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:
Martin Kiewitz 2010-08-29 15:13:25 +00:00
parent 8ba02169f8
commit ff7476d9f1
8 changed files with 131 additions and 80 deletions

View file

@ -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 = "*";

View file

@ -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);

View file

@ -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

View file

@ -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)

View file

@ -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;
} }

View file

@ -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 */

View file

@ -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) {

View file

@ -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);