Beispiel #1
0
GroovieEngine::GroovieEngine(OSystem *syst, const GroovieGameDescription *gd) :
	Engine(syst), _gameDescription(gd), _debugger(NULL), _script(NULL),
	_resMan(NULL), _grvCursorMan(NULL), _videoPlayer(NULL), _musicPlayer(NULL),
	_graphicsMan(NULL), _macResFork(NULL), _waitingForInput(false), _font(NULL) {

	// Adding the default directories
	const Common::FSNode gameDataDir(ConfMan.get("path"));
	SearchMan.addSubDirectoryMatching(gameDataDir, "groovie");
	SearchMan.addSubDirectoryMatching(gameDataDir, "media");
	SearchMan.addSubDirectoryMatching(gameDataDir, "system");
	SearchMan.addSubDirectoryMatching(gameDataDir, "MIDI");

	_modeSpeed = kGroovieSpeedNormal;
	if (ConfMan.hasKey("t7g_speed")) {
		Common::String speed = ConfMan.get("t7g_speed");
		if (speed.equals("im_an_ios"))
			_modeSpeed = kGroovieSpeediOS;
		else if (speed.equals("tweaked"))
			_modeSpeed = kGroovieSpeedTweaked;
	}

	// Initialize the custom debug levels
	DebugMan.addDebugChannel(kGroovieDebugAll, "All", "Debug everything");
	DebugMan.addDebugChannel(kGroovieDebugVideo, "Video", "Debug video and audio playback");
	DebugMan.addDebugChannel(kGroovieDebugResource, "Resource", "Debug resouce management");
	DebugMan.addDebugChannel(kGroovieDebugScript, "Script", "Debug the scripts");
	DebugMan.addDebugChannel(kGroovieDebugUnknown, "Unknown", "Report values of unknown data in files");
	DebugMan.addDebugChannel(kGroovieDebugHotspots, "Hotspots", "Show the hotspots");
	DebugMan.addDebugChannel(kGroovieDebugCursor, "Cursor", "Debug cursor decompression / switching");
	DebugMan.addDebugChannel(kGroovieDebugMIDI, "MIDI", "Debug MIDI / XMIDI files");
	DebugMan.addDebugChannel(kGroovieDebugScriptvars, "Scriptvars", "Print out any change to script variables");
	DebugMan.addDebugChannel(kGroovieDebugCell, "Cell", "Debug the cell game (in the microscope)");
	DebugMan.addDebugChannel(kGroovieDebugFast, "Fast", "Play videos quickly, with no sound (unstable)");
}
Beispiel #2
0
bool Script::loadScript(Common::String filename) {
	Common::SeekableReadStream *scriptfile = 0;

	if (_vm->_macResFork) {
		// Try to open the script file from the resource fork
		scriptfile = _vm->_macResFork->getResource(filename);
	} else {
		// Try to open the script file
		scriptfile = SearchMan.createReadStreamForMember(filename);
	}

	if (!scriptfile)
		return false;

	// Save the script filename
	_scriptFile = filename;

	// Load the code
	_codeSize = scriptfile->size();
	_code = new byte[_codeSize];
	if (!_code)
		return false;
	scriptfile->read(_code, _codeSize);
	delete scriptfile;

	// Patch the loaded code for known script bugs
	if (filename.equals("dr.grv")) {
		// WORKAROUND for the cake puzzle glitch (bug #2458322): Lowering the
		// piece on the first column and second row updates the wrong script
		// variable
		assert(_codeSize == 5546);
		_code[0x03C2] = 0x38;
	} else if (filename.equals("maze.grv")) {
		// GRAPHICS ENHANCEMENT - Leave a skeleton in the maze.
		// Replaces one normal T intersection with the unused(?)
		// skeleton T intersection graphics.
		assert(_codeSize == 3652);

		// Terminating T branch
		_code[0x0769] = 0x46;
		_code[0x0774] = 0x3E;
		_code[0x077A] = 0x42;

		// T with branch on right
		_code[0x08E2] = 0x43;
		_code[0x08D7] = 0x44;
		_code[0x08E8] = 0x45;

		// T with branch on left
		_code[0x0795] = 0x41;
		_code[0x078A] = 0x40;
		_code[0x079B] = 0x3F;
	}

	// Initialize the script
	_currentInstruction = 0;

	return true;
}
Beispiel #3
0
GameSupportLevel GameDescriptor::getSupportLevel() {
    GameSupportLevel gsl = kStableGame;
    if (contains("gsl")) {
        Common::String gslString = getVal("gsl");
        if (gslString.equals("unstable"))
            gsl = kUnstableGame;
        else if (gslString.equals("testing"))
            gsl = kTestingGame;
    }
    return gsl;
}
Beispiel #4
0
bool SaveStateDescriptor::getBool(const Common::String &key) const {
	if (contains(key)) {
		Common::String value = getVal(key);
		if (value.equalsIgnoreCase("true") ||
			value.equalsIgnoreCase("yes") ||
			value.equals("1"))
			return true;
		if (value.equalsIgnoreCase("false") ||
			value.equalsIgnoreCase("no") ||
			value.equals("0"))
			return false;
		error("SaveStateDescriptor: %s '%s' has unknown value '%s' for boolean '%s'",
				save_slot().c_str(), description().c_str(), value.c_str(), key.c_str());
	}
	return false;
}
Beispiel #5
0
bool parseBool(const Common::String &val, bool &valAsBool) {
	if (val.equalsIgnoreCase("true") ||
		val.equalsIgnoreCase("yes") ||
		val.equals("1")) {
		valAsBool = true;
		return true;
	}
	if (val.equalsIgnoreCase("false") ||
		val.equalsIgnoreCase("no") ||
		val.equals("0")) {
		valAsBool = false;
		return true;
	}

	return false;
}
Beispiel #6
0
void CursorManager::changeCursor(const Common::String &cursorName, bool pushed) {
	if (_currentCursor.equals(cursorName) && _cursorIsPushed == pushed)
		return;

	if (_cursorIsPushed != pushed)
		_cursorIsPushed = pushed;

	if (cursorName == "idle" && !pushed) {
		CursorMan.replaceCursor(_idleCursor.getSurface(), _idleCursor.getWidth(), _idleCursor.getHeight(), _idleCursor.getHotspotX(), _idleCursor.getHotspotY(), _idleCursor.getKeyColor(), false, _pixelFormat);
		return;
	}

	for (int i = 0; i < NUM_CURSORS; ++i) {
		if (_engine->getGameId() == GID_NEMESIS) {
			if (cursorName.equals(_cursorNames[i])) {
				_currentCursor = cursorName;

				// ZNem uses a/b at the end of the file to signify not pushed/pushed respectively
				Common::String pushedFlag = pushed ? "b" : "a";
				Common::String name = Common::String::format("%s%s.zcr", _zNemCursorFileNames[i], pushedFlag.c_str());

				changeCursor(ZorkCursor(name));
				return;
			}
		} else if (_engine->getGameId() == GID_GRANDINQUISITOR) {
			if (cursorName.equals(_cursorNames[i])) {
				_currentCursor = cursorName;

				if (!pushed) {
					changeCursor(ZorkCursor(_zgiCursorFileNames[i]));
				} else {
					// ZGI flips not pushed/pushed between a/c and b/d
					// It flips the 4th character of the name
					char buffer[25];
					strcpy(buffer, _zgiCursorFileNames[i]);
					buffer[3] += 2;
					changeCursor(ZorkCursor(buffer));
				}
				return;
			}
		}
	}

	// If we get here, something went wrong
	warning("No cursor found for identifier %s", cursorName.c_str());
}
Beispiel #7
0
int CursorManager::getCursorId(const Common::String &name) {
	for (int i = 0; i < NUM_CURSORS; i++) {
		if (name.equals(_cursorNames[i])) {
			return i;
		}
	}

	return CursorIndex_Idle;
}
Beispiel #8
0
const Maemo::Model OSystem_SDL_Maemo::detectModel() {
	Common::String deviceHwId = Common::String(getenv("SCUMMVM_MAEMO_DEVICE"));
	const Model *model;
	for (model = models; model->hwId; model++) {
		if (deviceHwId.equals(model->hwId))
			return *model;
	}
	return *model;
}
Beispiel #9
0
MidiDriver::DeviceHandle MidiDriver::getDeviceHandle(const Common::String &identifier) {
	const MusicPlugin::List p = MusicMan.getPlugins();

	if (p.begin() == p.end())
		error("MidiDriver::getDeviceHandle: Music plugins must be loaded prior to calling this method");

	for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); m++) {
		MusicDevices i = (**m)->getDevices();
		for (MusicDevices::iterator d = i.begin(); d != i.end(); d++) {
			// The music driver id isn't unique, but it will match
			// driver's first device. This is useful when selecting
			// the driver from the command line.
			if (identifier.equals(d->getMusicDriverId()) || identifier.equals(d->getCompleteId()) || identifier.equals(d->getCompleteName())) {
				return d->getHandle();
			}
		}
	}

	return 0;
}
Beispiel #10
0
CMapPtr ResourceLoader::getColormap(const Common::String &fname) {
	Common::String filename = fname;
	filename.toLowercase();
	for (Common::List<CMap *>::const_iterator i = _colormaps.begin(); i != _colormaps.end(); ++i) {
		CMap *c = *i;
		if (filename.equals(c->_fname)) {
			return c;
		}
	}

	return loadColormap(fname);
}
Beispiel #11
0
bool SaveGametests::readAndVerifyData(const char *fileName, const char *expected) {
	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
	Common::InSaveFile *loadFile = saveFileMan->openForLoading(fileName);

	if (!loadFile) {
		Testsuite::logDetailedPrintf("Can't open save File to load\n");
		return false;
	}

	Common::String lineToRead = loadFile->readLine();
	delete loadFile;

	if (lineToRead.equals(expected)) {
		return true;
	}

	return false;
}
Beispiel #12
0
/**
 * This test does the following:
 * 1) acquires the game-data path
 * 2) In the game-root it navigates to "directory" and opens the file "file"
 *
 * The code accesses the appropriate file using the fileSystem API, creates a read stream of it and
 * compares the message contained in it, with what it expects.
 *
 */
bool FStests::readDataFromFile(Common::FSDirectory *directory, const char *file) {

	Common::SeekableReadStream *readStream = directory->createReadStreamForMember(file);

	if (!readStream) {
		Testsuite::logDetailedPrintf("Can't open game file for reading\n");
		return false;
	}

	Common::String msg = readStream->readLine();
	delete readStream;

	Testsuite::logDetailedPrintf("Message Extracted from %s/%s : %s\n", directory->getFSNode().getName().c_str(), file, msg.c_str());

	Common::String expectedMsg = "It works!";

	if (!msg.equals(expectedMsg)) {
		Testsuite::logDetailedPrintf("Can't read Correct data from file\n");
		return false;
	}

	return true;
}
Beispiel #13
0
/**
 * This test creates a file testbed.out, writes a sample data and confirms if
 * it is same by reading the file again.
 */
TestExitStatus FStests::testWriteFile() {
	const Common::String &path = ConfMan.get("path");
	Common::FSNode gameRoot(path);
	if (!gameRoot.exists()) {
		Testsuite::logPrintf("Couldn't open the game data directory %s", path.c_str());
		 return kTestFailed;
	}

	Common::FSNode fileToWrite = gameRoot.getChild("testbed.out");

	Common::WriteStream *ws = fileToWrite.createWriteStream();

	if (!ws) {
		Testsuite::logDetailedPrintf("Can't open writable file in game data dir\n");
		 return kTestFailed;
	}

	ws->writeString("ScummVM Rocks!");
	ws->flush();
	delete ws;

	Common::SeekableReadStream *rs = fileToWrite.createReadStream();
	if (!rs) {
		Testsuite::logDetailedPrintf("Can't open recently written file testbed.out in game data dir\n");
		 return kTestFailed;
	}
	Common::String readFromFile = rs->readLine();
	delete rs;

	if (readFromFile.equals("ScummVM Rocks!")) {
		// All good
		Testsuite::logDetailedPrintf("Data written and read correctly\n");
		 return kTestPassed;
	}

	 return kTestFailed;
}
Beispiel #14
0
void Console::printUsage(const Common::String &command) {
	// TODO: This is horrible and would probably benefit from a map or something.
	if (command.equals(BREAK_CMD)) {
		debugPrintf("Usage: %s <file path> <line> to break at line <line> of file <file path>\n", command.c_str());
	} else if (command.equals(REMOVE_BREAKPOINT_CMD)) {
		debugPrintf("Usage: %s <id> to remove breakpoint #id\n", command.c_str());
	} else if (command.equals(ENABLE_BREAKPOINT_CMD)) {
		debugPrintf("Usage: %s <id> to enable breakpoint #id\n", command.c_str());
	} else if (command.equals(DISABLE_BREAKPOINT_CMD)) {
		debugPrintf("Usage: %s <id> to disable breakpoint #id\n", command.c_str());
	} else if (command.equals(REMOVE_WATCH_CMD)) {
		debugPrintf("Usage: %s <id> to remove watchpoint #id\n", command.c_str());
	} else if (command.equals(ENABLE_WATCH_CMD)) {
		debugPrintf("Usage: %s <id> to enable watchpoint #id\n", command.c_str());
	} else if (command.equals(DISABLE_WATCH_CMD)) {
		debugPrintf("Usage: %s <id> to disable watchpoint #id\n", command.c_str());
	} else if (command.equals(INFO_CMD)) {
		debugPrintf("Usage: %s [watch|breakpoints]\n", command.c_str());
	} else if (command.equals(WATCH_CMD)) {
		debugPrintf("Usage: %s <file path> <name> to watch for <name> in file <file path>\n", command.c_str());
	} else if (command.equals(STEP_CMD)) {
		debugPrintf("Usage: %s to step\n", command.c_str());
	} else if (command.equals(CONTINUE_CMD)) {
		debugPrintf("Usage: %s to continue\n", command.c_str());
	} else if (command.equals(FINISH_CMD)) {
		debugPrintf("Usage: %s to finish\n", command.c_str());
	} else if (command.equals(PRINT_CMD)) {
		debugPrintf("Usage: %s <name> to print value of <name>\n", command.c_str());
	} else if (command.equals(SET_CMD)) {
		debugPrintf("Usage: %s <name> = <value> to set <name> to <value>\n", command.c_str());
	} else {
		debugPrintf("No help about this command, sorry.");
	}
}
Beispiel #15
0
void Lingo::func_goto(Datum &frame, Datum &movie) {
	_vm->_playbackPaused = false;

	if (!_vm->getCurrentScore())
		return;

	if (movie.type != VOID) {
		movie.toString();

		Common::String movieFilename = convertPath(*movie.u.s);
		Common::String cleanedFilename;

		bool fileExists = false;

		if (_vm->getPlatform() == Common::kPlatformMacintosh) {
			Common::MacResManager resMan;

			for (const byte *p = (const byte *)movieFilename.c_str(); *p; p++)
				if (*p >= 0x20 && *p <= 0x7f)
					cleanedFilename += (char) *p;

			if (resMan.open(movieFilename)) {
				fileExists = true;
				cleanedFilename = movieFilename;
			} else if (!movieFilename.equals(cleanedFilename) && resMan.open(cleanedFilename)) {
				fileExists = true;
			}
		} else {
			Common::File file;
			cleanedFilename = movieFilename + ".MMM";

			if (file.open(movieFilename)) {
				fileExists = true;
				cleanedFilename = movieFilename;
			} else if (!movieFilename.equals(cleanedFilename) && file.open(cleanedFilename)) {
				fileExists = true;
			}
		}

		if (!fileExists) {
			warning("Movie %s does not exist", movieFilename.c_str());
			return;
		}

		_vm->_nextMovie.movie = cleanedFilename;
		_vm->getCurrentScore()->_stopPlay = true;

		_vm->_nextMovie.frameS.clear();
		_vm->_nextMovie.frameI = -1;

		if (frame.type == VOID)
			return;

		if (frame.type == STRING) {
			_vm->_nextMovie.frameS = *frame.u.s;
			return;
		}

		frame.toInt();

		_vm->_nextMovie.frameI = frame.u.i;

		return;
	}

	if (frame.type == VOID)
		return;

	_vm->_skipFrameAdvance = true;

	if (frame.type == STRING) {
		if (_vm->getCurrentScore())
			_vm->getCurrentScore()->setStartToLabel(*frame.u.s);
		return;
	}

	frame.toInt();

	if (_vm->getCurrentScore())
		_vm->getCurrentScore()->setCurrentFrame(frame.u.i);
}