Exemple #1
0
Common::List<Graphics::PixelFormat> DisplayManager::getSupportedPixelFormats() const {
	Common::List<Graphics::PixelFormat> list;

	// In order of preference
	list.push_back(PSPPixelFormat::convertToScummvmPixelFormat(PSPPixelFormat::Type_5650));
	list.push_back(PSPPixelFormat::convertToScummvmPixelFormat(PSPPixelFormat::Type_5551));
	list.push_back(PSPPixelFormat::convertToScummvmPixelFormat(PSPPixelFormat::Type_4444));
	list.push_back(Graphics::PixelFormat::createFormatCLUT8());

	return list;
}
Exemple #2
0
int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) {
	JNIEnv *env = JNI::getEnv();
	Common::List<Common::String> dirlist;
	dirlist.push_back("");

	int count = 0;
	while (!dirlist.empty()) {
		const Common::String dir = dirlist.back();
		dirlist.pop_back();

		jstring jpath = env->NewStringUTF(dir.c_str());
		jobjectArray jpathlist =
			(jobjectArray)env->CallObjectMethod(_am, MID_list, jpath);

		if (env->ExceptionCheck()) {
			warning("Error while calling AssetManager->list(%s). Ignoring.",
					dir.c_str());
			env->ExceptionDescribe();
			env->ExceptionClear();

			// May as well keep going ...
			continue;
		}

		env->DeleteLocalRef(jpath);

		for (jsize i = 0; i < env->GetArrayLength(jpathlist); ++i) {
			jstring elem = (jstring)env->GetObjectArrayElement(jpathlist, i);
			const char *p = env->GetStringUTFChars(elem, 0);
			Common::String thispath = dir;

			if (!thispath.empty())
				thispath += "/";

			thispath += p;

			// Assume files have a . in them, and directories don't
			if (strchr(p, '.')) {
				member_list.push_back(getMember(thispath));
				++count;
			} else {
				dirlist.push_back(thispath);
			}

			env->ReleaseStringUTFChars(elem, p);
			env->DeleteLocalRef(elem);
		}

		env->DeleteLocalRef(jpathlist);
	}

	return count;
}
Exemple #3
0
void initExtensions() {
	const char *exts = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
	Common::StringTokenizer tokenizer(exts, " ");
	while (!tokenizer.empty()) {
		g_extensions.push_back(tokenizer.nextToken());
	}
}
Exemple #4
0
void ThemeEngine::listUsableThemes(Common::Archive &archive, Common::List<ThemeDescriptor> &list) {
	ThemeDescriptor td;

	Common::ArchiveMemberList fileList;
	archive.listMatchingMembers(fileList, "*.zip");
	for (Common::ArchiveMemberList::iterator i = fileList.begin();
	        i != fileList.end(); ++i) {
		td.name.clear();
		if (themeConfigUsable(**i, td.name)) {
			td.filename = (*i)->getName();
			td.id = (*i)->getDisplayName();

			// If the name of the node object also contains
			// the ".zip" suffix, we will strip it.
			if (td.id.matchString("*.zip", true)) {
				for (int j = 0; j < 4; ++j)
					td.id.deleteLastChar();
			}

			list.push_back(td);
		}
	}

	fileList.clear();
}
Exemple #5
0
      virtual Common::List<Graphics::PixelFormat> getSupportedFormats() const
      {
         Common::List<Graphics::PixelFormat> result;

         /* RGBA8888 */
         result.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));

#ifdef FRONTEND_SUPPORTS_RGB565
         /* RGB565 - overlay */
         result.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
#endif
         /* RGB555 - fmtowns */
         result.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 10, 5, 0, 15));

         /* Palette - most games */
         result.push_back(Graphics::PixelFormat::createFormatCLUT8());
         return result;
      }
Common::List<Graphics::PixelFormat> OpenGLSdlGraphicsManager::getSupportedFormats() const {
	Common::List<Graphics::PixelFormat> formats;

	// Our default mode is (memory layout wise) RGBA8888 which is a different
	// logical layout depending on the endianness. We chose this mode because
	// it is the only 32bit color mode we can safely assume to be present in
	// OpenGL and OpenGL ES implementations. Thus, we need to supply different
	// logical formats based on endianness.
#ifdef SCUMM_LITTLE_ENDIAN
	// ABGR8888
	formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
#else
	// RGBA8888
	formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
#endif
	// RGB565
	formats.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
	// RGBA5551
	formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0));
	// RGBA4444
	formats.push_back(Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0));

#if !USE_FORCED_GLES && !USE_FORCED_GLES2
#if !USE_FORCED_GL
	if (!isGLESContext()) {
#endif
#ifdef SCUMM_LITTLE_ENDIAN
		// RGBA8888
		formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
#else
		// ABGR8888
		formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
#endif
#if !USE_FORCED_GL
	}
#endif
#endif

	// RGB555, this is used by SCUMM HE 16 bit games.
	// This is not natively supported by OpenGL ES implementations, we convert
	// the pixel format internally.
	formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));

	formats.push_back(Graphics::PixelFormat::createFormatCLUT8());

	return formats;
}
bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList) const {
	// Loop until we find the closing brace
	Common::String line = stream.readLine();
	trimCommentsAndWhiteSpace(&line);

	// Criteria can be empty
	if (line.contains('}')) {
		return false;
	}

	// Create a new List to hold the CriteriaEntries
	criteriaList.push_back(Common::List<Puzzle::CriteriaEntry>());

	while (!stream.eos() && !line.contains('}')) {
		Puzzle::CriteriaEntry entry;

		// Split the string into tokens using ' ' as a delimiter
		Common::StringTokenizer tokenizer(line);
		Common::String token;

		// Parse the id out of the first token
		token = tokenizer.nextToken();
		sscanf(token.c_str(), "[%u]", &(entry.key));

		// Parse the operator out of the second token
		token = tokenizer.nextToken();
		if (token.c_str()[0] == '=')
			entry.criteriaOperator = Puzzle::EQUAL_TO;
		else if (token.c_str()[0] == '!')
			entry.criteriaOperator = Puzzle::NOT_EQUAL_TO;
		else if (token.c_str()[0] == '>')
			entry.criteriaOperator = Puzzle::GREATER_THAN;
		else if (token.c_str()[0] == '<')
			entry.criteriaOperator = Puzzle::LESS_THAN;

		// First determine if the last token is an id or a value
		// Then parse it into 'argument'
		token = tokenizer.nextToken();
		if (token.contains('[')) {
			sscanf(token.c_str(), "[%u]", &(entry.argument));
			entry.argumentIsAKey = true;
		} else {
			sscanf(token.c_str(), "%u", &(entry.argument));
			entry.argumentIsAKey = false;
		}

		criteriaList.back().push_back(entry);

		line = stream.readLine();
		trimCommentsAndWhiteSpace(&line);
	}

	return true;
}
Exemple #8
0
/**
 * Process a keyboard event
 */
void TinselEngine::ProcessKeyEvent(const Common::Event &event) {

	// Handle any special keys immediately
	switch (event.kbd.keycode) {
	case Common::KEYCODE_d:
		if ((event.kbd.flags == Common::KBD_CTRL) && (event.type == Common::EVENT_KEYDOWN)) {
			// Activate the debugger
			assert(_console);
			_console->attach();
			return;
		}
		break;
	default:
		break;
	}

	// Check for movement keys
	int idx = 0;
	switch (event.kbd.keycode) {
	case Common::KEYCODE_UP:
	case Common::KEYCODE_KP8:
		idx = MSK_UP;
		break;
	case Common::KEYCODE_DOWN:
	case Common::KEYCODE_KP2:
		idx = MSK_DOWN;
		break;
	case Common::KEYCODE_LEFT:
	case Common::KEYCODE_KP4:
		idx = MSK_LEFT;
		break;
	case Common::KEYCODE_RIGHT:
	case Common::KEYCODE_KP6:
		idx = MSK_RIGHT;
		break;
	default:
		break;
	}
	if (idx != 0) {
		if (event.type == Common::EVENT_KEYDOWN)
			_dosPlayerDir |= idx;
		else
			_dosPlayerDir &= ~idx;
		return;
	}

	// All other keypresses add to the queue for processing in KeyboardProcess
	keypresses.push_back(event);
}
Exemple #9
0
reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv) {
	uint16 operation = argv[0].toUint16();
	Video::VideoDecoder *videoDecoder = 0;
	bool reshowCursor = g_sci->_gfxCursor->isVisible();

	switch (operation) {
	case 1:	// Play
		// 6 params
		s->_videoState.reset();
		s->_videoState.fileName = Common::String::format("%d.duk", argv[1].toUint16());

		videoDecoder = new Video::AVIDecoder();

		if (!videoDecoder->loadFile(s->_videoState.fileName)) {
			warning("Could not open Duck %s", s->_videoState.fileName.c_str());
			break;
		}

		if (reshowCursor)
			g_sci->_gfxCursor->kernelHide();

		{
		// Duck videos are 16bpp, so we need to change the active pixel format
		int oldWidth = g_system->getWidth();
		int oldHeight = g_system->getHeight();
		Common::List<Graphics::PixelFormat> formats;
		formats.push_back(videoDecoder->getPixelFormat());
		initGraphics(640, 480, true, formats);

		if (g_system->getScreenFormat().bytesPerPixel != videoDecoder->getPixelFormat().bytesPerPixel)
			error("Could not switch screen format for the duck video");

		playVideo(videoDecoder, s->_videoState);

		// Switch back to 8bpp
		initGraphics(oldWidth, oldHeight, oldWidth > 320);
		}

		if (reshowCursor)
			g_sci->_gfxCursor->kernelShow();
		break;
	default:
		kStub(s, argc, argv);
		break;
	}

	return s->r_acc;
}
Exemple #10
0
void EMIEngine::purgeText() {
	Common::List<TextObject *> toDelete;

	foreach (TextObject *t, TextObject::getPool()) {
		if (t->getStackLevel() == 0) {
			toDelete.push_back(t);
		}
	}

	while (!toDelete.empty()) {
		TextObject *t = toDelete.front();
		toDelete.pop_front();
		delete t;
	}

	invalidateTextObjectsSortOrder();
}
Exemple #11
0
bool Diving::play(uint16 playerCount, bool hasPearlLocation) {
	init();
	initScreen();

	_vm->_draw->blitInvalidated();
	_vm->_video->retrace();

	EvilFish shark(*_objects, 320, 0, 14, 8, 9, 3);

	Common::List<ANIObject *> objects;

	objects.push_back(_water);
	objects.push_back(&shark);

	shark.enter(EvilFish::kDirectionLeft, 90);

	while (!_vm->_util->keyPressed() && !_vm->shouldQuit()) {
		int16 left, top, right, bottom;

		// Clear the previous animation frames
		for (Common::List<ANIObject *>::iterator o = objects.reverse_begin();
		     o != objects.end(); --o) {

			(*o)->clear(*_vm->_draw->_backSurface, left, top, right, bottom);
			_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
		}

		// Draw the current animation frames
		for (Common::List<ANIObject *>::iterator o = objects.begin();
		     o != objects.end(); ++o) {

			(*o)->draw(*_vm->_draw->_backSurface, left, top, right, bottom);
			_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);

			(*o)->advance();
		}

		_vm->_draw->blitInvalidated();

		_vm->_util->waitEndFrame();
		_vm->_util->processInput();
	}

	deinit();
	return true;
}
Exemple #12
0
void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut) {
    // This happens when quitting during the "eye" cutscene.
    if (_vm->shouldQuit())
        return;

    _leadOutFrame = _decoder->getFrameCount();
    if (_leadOutFrame > 60)
        _leadOutFrame -= 60;

    _movieTexts = movieTexts;
    _numMovieTexts = numMovieTexts;
    _currentMovieText = 0;
    _leadOut = leadOut;

    if (leadIn) {
        _vm->_sound->playMovieSound(leadIn, kLeadInSound);
    }

    if (_bgSoundStream) {
        _snd->playInputStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream);
    }

    bool terminated = false;

    Common::List<Common::Event> stopEvents;
    Common::Event stopEvent;
    stopEvents.clear();
    stopEvent.type = Common::EVENT_KEYDOWN;
    stopEvent.kbd = Common::KEYCODE_ESCAPE;
    stopEvents.push_back(stopEvent);

    terminated = !playVideo(stopEvents);

    closeTextObject(_currentMovieText, NULL);

    if (terminated) {
        _snd->stopHandle(*_bgSoundHandle);
        _vm->_sound->stopMovieSounds();
        _vm->_sound->stopSpeech();
    }

    while (_snd->isSoundHandleActive(*_bgSoundHandle))
        _system->delayMillis(100);
}
Exemple #13
0
Common::Archive *ResLoaderInsMalcolm::load(Common::ArchiveMemberPtr memberFile, Common::SeekableReadStream &stream) const {
	Common::List<Common::String> filenames;
	Common::ScopedPtr<PlainArchive> result(new PlainArchive(memberFile));
	if (!result)
		return 0;

	// thanks to eriktorbjorn for this code (a bit modified though)
	stream.seek(3, SEEK_SET);

	// first file is the index table
	uint32 size = stream.readUint32LE();
	Common::String temp;

	for (uint32 i = 0; i < size; ++i) {
		byte c = stream.readByte();

		if (c == '\\') {
			temp.clear();
		} else if (c == 0x0D) {
			// line endings are CRLF
			c = stream.readByte();
			assert(c == 0x0A);
			++i;

			filenames.push_back(temp);
		} else {
			temp += (char)c;
		}
	}

	stream.seek(3, SEEK_SET);

	for (Common::List<Common::String>::iterator file = filenames.begin(); file != filenames.end(); ++file) {
		const uint32 fileSize = stream.readUint32LE();
		const uint32 fileOffset = stream.pos();

		result->addFileEntry(*file, PlainArchive::Entry(fileOffset, fileSize));
		stream.seek(fileSize, SEEK_CUR);
	}

	return result.release();
}
Exemple #14
0
bool TinselEngine::pollEvent() {
	Common::Event event;

	if (!g_system->getEventManager()->pollEvent(event))
		return false;

	// Handle the various kind of events
	switch (event.type) {
	case Common::EVENT_LBUTTONDOWN:
	case Common::EVENT_LBUTTONUP:
	case Common::EVENT_RBUTTONDOWN:
	case Common::EVENT_RBUTTONUP:
		// Add button to queue for the mouse process
		mouseButtons.push_back(event.type);
		break;

	case Common::EVENT_MOUSEMOVE:
		{
			// This fragment takes care of Tinsel 2 when it's been compiled with
			// blank areas at the top and bottom of thes creen
			int ySkip = TinselV2 ? (g_system->getHeight() - _vm->screen().h) / 2 : 0;
			if ((event.mouse.y >= ySkip) && (event.mouse.y < (g_system->getHeight() - ySkip)))
				_mousePos = Common::Point(event.mouse.x, event.mouse.y - ySkip);
		}
		break;

	case Common::EVENT_KEYDOWN:
	case Common::EVENT_KEYUP:
		ProcessKeyEvent(event);
		break;

	default:
		break;
	}

	return true;
}
Common::List<Graphics::PixelFormat> OpenGLSdlGraphicsManager::getSupportedFormats() const {
	Common::List<Graphics::PixelFormat> formats;

	// RGBA8888
	formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
	// RGB565
	formats.push_back(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
	// RGBA5551
	formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0));
	// RGBA4444
	formats.push_back(Graphics::PixelFormat(2, 4, 4, 4, 4, 12, 8, 4, 0));

#ifndef USE_GLES
	// ARGB8888, this should not be here, but Sword25 requires it. :-/
	formats.push_back(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24));

	// RGB555, this is used by SCUMM HE 16 bit games.
	formats.push_back(Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
#endif

	formats.push_back(Graphics::PixelFormat::createFormatCLUT8());

	return formats;
}
Exemple #16
0
Common::List<Math::Line3d> Sector::getBridgesTo(Sector *sector) const {
	// This returns a list of "bridges", which are edges that can be travelled
	// through to get to another sector. 0 bridges mean the sectors aren't
	// connected.

	// The algorithm starts by considering all the edges of sector A
	// bridges. It then narrows them down by cutting the bridges against
	// sector B, so we end up with a list of lines which are at the border
	// of sector A and inside sector B.

	Common::List<Math::Line3d> bridges;
	Common::List<Math::Line3d>::iterator it;

	for (int i = 0; i < _numVertices; i++) {
		bridges.push_back(Math::Line3d(_vertices[i], _vertices[i + 1]));
	}

	Math::Vector3d *sectorVertices = sector->getVertices();
	for (int i = 0; i < sector->getNumVertices(); i++) {
		Math::Vector3d pos, edge, delta_b1, delta_b2;
		Math::Line3d line(sectorVertices[i], sectorVertices[i + 1]);
		it = bridges.begin();
		while (it != bridges.end()) {
			Math::Line3d &bridge = (*it);
			edge = line.end() - line.begin();
			delta_b1 = bridge.begin() - line.begin();
			delta_b2 = bridge.end() - line.begin();
			Math::Vector3d cross_b1 = Math::Vector3d::crossProduct(edge, delta_b1);
			Math::Vector3d cross_b2 = Math::Vector3d::crossProduct(edge, delta_b2);
			bool b1_out = cross_b1.dotProduct(_normal) < 0;
			bool b2_out = cross_b2.dotProduct(_normal) < 0;

			bool useXZ = (g_grim->getGameType() == GType_MONKEY4);

			if (b1_out && b2_out) {
				// Both points are outside.
				it = bridges.erase(it);
				continue;
			} else if (b1_out) {
				if (bridge.intersectLine2d(line, &pos, useXZ)) {
					bridge = Math::Line3d(pos, bridge.end());
				}
			} else if (b2_out) {
				if (bridge.intersectLine2d(line, &pos, useXZ)) {
					bridge = Math::Line3d(bridge.begin(), pos);
				}
			}

			++it;
		}
	}

	// All the bridges should be at the same height on both sectors.
	it = bridges.begin();
	while (it != bridges.end()) {
		if (g_grim->getGameType() == GType_MONKEY4) {
			// Set pac contains sectors which are not parallel to any
			// other sector or share any edge. Since one sector isn't
			// a plane, finding the intersections in 3D would be complicated.
			//
			// Checking for bridges using a projection in 2D and having a height
			// threshold to avoid that characters jump from lower to higher floors
			// seems to be a good compromise.
			//
			// The value of at least 0.1 was chosen to fix a path finding issue
			// in set pac when guybrush tried to reach the pile of rocks.
			if (fabs(getProjectionToPlane((*it).begin()).y() - sector->getProjectionToPlane((*it).begin()).y()) > 0.1f ||
					fabs(getProjectionToPlane((*it).end()).y() - sector->getProjectionToPlane((*it).end()).y()) > 0.1f) {
				it = bridges.erase(it);
				continue;
			}
		} else {
			if (fabs(getProjectionToPlane((*it).begin()).z() - sector->getProjectionToPlane((*it).begin()).z()) > 0.01f ||
					fabs(getProjectionToPlane((*it).end()).z() - sector->getProjectionToPlane((*it).end()).z()) > 0.01f) {
				it = bridges.erase(it);
				continue;
			}
		}
		++it;
	}
	return bridges;
}
Exemple #17
0
Common::List<Math::Line3d> Sector::getBridgesTo(Sector *sector) const {
	// This returns a list of "bridges", which are edges that can be travelled
	// through to get to another sector. 0 bridges mean the sectors aren't
	// connected.

	// The algorithm starts by considering all the edges of sector A
	// bridges. It then narrows them down by cutting the bridges against
	// sector B, so we end up with a list of lines which are at the border
	// of sector A and inside sector B.

	Common::List<Math::Line3d> bridges;
	Common::List<Math::Line3d>::iterator it;

	for (int i = 0; i < _numVertices; i++){
		bridges.push_back(Math::Line3d(_vertices[i], _vertices[i+1]));
	}

	Math::Vector3d* sectorVertices = sector->getVertices();
	for (int i = 0; i < sector->getNumVertices(); i++) {
		Math::Vector3d pos, edge, delta_b1, delta_b2;
		Math::Line3d line(sectorVertices[i], sectorVertices[i+1]);
		it = bridges.begin();
		while (it != bridges.end()) {
			Math::Line3d& bridge = (*it);
			edge = line.end() - line.begin();
			delta_b1 = bridge.begin() - line.begin();
			delta_b2 = bridge.end() - line.begin();
			bool b1_out = edge.x() * delta_b1.y() < edge.y() * delta_b1.x();
			bool b2_out = edge.x() * delta_b2.y() < edge.y() * delta_b2.x();

			if (b1_out && b2_out) {
				// Both points are outside.
				it = bridges.erase(it);
				continue;
			} else if (b1_out) {
				if (bridge.intersectLine2d(line, &pos)) {
					bridge = Math::Line3d(pos, bridge.end());
				}
			} else if (b2_out) {
				if (bridge.intersectLine2d(line, &pos)) {
					bridge = Math::Line3d(bridge.begin(), pos);
				}
			}

			if ((bridge.end() - bridge.begin()).getMagnitude() < 0.01f) {
				it = bridges.erase(it);
				continue;
			}
			++it;
		}
	}

	// All the bridges should be at the same height on both sectors.
	while (it != bridges.end()) {
		if (fabs(getProjectionToPlane((*it).begin()).z() - sector->getProjectionToPlane((*it).begin()).z()) > 0.01f ||
			fabs(getProjectionToPlane((*it).end()).z() - sector->getProjectionToPlane((*it).end()).z()) > 0.01f) {
			it = bridges.erase(it);
			continue;
		}
		++it;
	}
	return bridges;
}
Exemple #18
0
void Actor::walkTo(const Math::Vector3d &p) {
	if (p == _pos)
		_walking = false;
	else {
		_walking = true;
		_destPos = p;
		_path.clear();

		if (_constrain) {
			g_grim->getCurrSet()->findClosestSector(p, NULL, &_destPos);

			Common::List<PathNode *> openList;
			Common::List<PathNode *> closedList;

			PathNode *start = new PathNode;
			start->parent = NULL;
			start->pos = _pos;
			start->dist = 0.f;
			start->cost = 0.f;
			openList.push_back(start);
			g_grim->getCurrSet()->findClosestSector(_pos, &start->sect, NULL);

			Common::List<Sector *> sectors;
			for (int i = 0; i < g_grim->getCurrSet()->getSectorCount(); ++i) {
				Sector *s = g_grim->getCurrSet()->getSectorBase(i);
				int type = s->getType();
				if ((type == Sector::WalkType || type == Sector::HotType || type == Sector::FunnelType) && s->isVisible()) {
					sectors.push_back(s);
				}
			}

			Sector *endSec = NULL;
			g_grim->getCurrSet()->findClosestSector(_destPos, &endSec, NULL);

			do {
				PathNode *node = NULL;
				float cost = -1.f;
				for (Common::List<PathNode *>::iterator j = openList.begin(); j != openList.end(); ++j) {
					PathNode *n = *j;
					float c = n->dist + n->cost;
					if (cost < 0.f || c < cost) {
						cost = c;
						node = n;
					}
				}
				closedList.push_back(node);
				openList.remove(node);
				Sector *sector = node->sect;

				if (sector == endSec) {
					PathNode *n = closedList.back();
					// Don't put the start position in the list, or else
					// the first angle calculated in updateWalk() will be
					// meaningless. The only node without parent is the start
					// one.
					while (n->parent) {
						_path.push_back(n->pos);
						n = n->parent;
					}

					break;
				}

				for (Common::List<Sector *>::iterator i = sectors.begin(); i != sectors.end(); ++i) {
					Sector *s = *i;
					bool inClosed = false;
					for (Common::List<PathNode *>::iterator j = closedList.begin(); j != closedList.end(); ++j) {
						if ((*j)->sect == s) {
							inClosed = true;
							break;
						}
					}
					if (inClosed)
						continue;

					Common::List<Math::Line3d> bridges = sector->getBridgesTo(s);
					if (bridges.empty())
						continue; // The sectors are not adjacent.

					Math::Vector3d closestPoint = s->getClosestPoint(_destPos);
					Math::Vector3d best;
					float bestDist = 1e6f;
					Math::Line3d l(node->pos, closestPoint);
					while (!bridges.empty()) {
						Math::Line3d bridge = bridges.back();
						Math::Vector3d pos;
						const bool useXZ = (g_grim->getGameType() == GType_MONKEY4);
						if (!bridge.intersectLine2d(l, &pos, useXZ)) {
							pos = bridge.middle();
						}
						float dist = (pos - closestPoint).getMagnitude();
						if (dist < bestDist) {
							bestDist = dist;
							best = pos;
						}
						bridges.pop_back();
					}
					best = handleCollisionTo(node->pos, best);

					PathNode *n = NULL;
					for (Common::List<PathNode *>::iterator j = openList.begin(); j != openList.end(); ++j) {
						if ((*j)->sect == s) {
							n = *j;
							break;
						}
					}
					if (n) {
						float newCost = node->cost + (best - node->pos).getMagnitude();
						if (newCost < n->cost) {
							n->cost = newCost;
							n->parent = node;
							n->pos = best;
							n->dist = (n->pos - _destPos).getMagnitude();
						}
					} else {
						n = new PathNode;
						n->parent = node;
						n->sect = s;
						n->pos = best;
						n->dist = (n->pos - _destPos).getMagnitude();
						n->cost = node->cost + (n->pos - node->pos).getMagnitude();
						openList.push_back(n);
					}
				}
			} while (!openList.empty());

			for (Common::List<PathNode *>::iterator j = closedList.begin(); j != closedList.end(); ++j) {
				delete *j;
			}
			for (Common::List<PathNode *>::iterator j = openList.begin(); j != openList.end(); ++j) {
				delete *j;
			}
		}

		_path.push_front(_destPos);
	}
}
Exemple #19
0
int Actor::fillPathArray(const Point &fromPoint, const Point &toPoint, Point &bestPoint) {
	int bestRating;
	int currentRating;
	Point bestPath;
	int pointCounter;
	const PathDirectionData *samplePathDirection;
	Point nextPoint;
	int directionCount;
	int16 compressX = (_vm->getGameId() == GID_ITE) ? 2 : 1;

	Common::List<PathDirectionData> pathDirectionQueue;

	pointCounter = 0;
	bestRating = quickDistance(fromPoint, toPoint, compressX);
	bestPath = fromPoint;

	for (int8 startDirection = 0; startDirection < 4; startDirection++) {
		PathDirectionData tmp = { startDirection, fromPoint.x, fromPoint.y };
		pathDirectionQueue.push_back(tmp);
	}

	if (validPathCellPoint(fromPoint)) {
		setPathCell(fromPoint, kDirUp);

#ifdef ACTOR_DEBUG
		addDebugPoint(fromPoint, 24+36);
#endif
	}

	while (!pathDirectionQueue.empty()) {
		PathDirectionData curPathDirection = pathDirectionQueue.front();
		pathDirectionQueue.pop_front();
		for (directionCount = 0; directionCount < 3; directionCount++) {
			samplePathDirection = &pathDirectionLUT[curPathDirection.direction][directionCount];
			nextPoint = Point(curPathDirection.x, curPathDirection.y);
			nextPoint.x += samplePathDirection->x;
			nextPoint.y += samplePathDirection->y;

			if (!validPathCellPoint(nextPoint)) {
				continue;
			}

			if (getPathCell(nextPoint) != kPathCellEmpty) {
				continue;
			}

			setPathCell(nextPoint, samplePathDirection->direction);

#ifdef ACTOR_DEBUG
			addDebugPoint(nextPoint, samplePathDirection->direction + 96);
#endif
			PathDirectionData tmp = {
				samplePathDirection->direction,
				nextPoint.x, nextPoint.y };
			pathDirectionQueue.push_back(tmp);
			++pointCounter;
			if (nextPoint == toPoint) {
				bestPoint = toPoint;
				return pointCounter;
			}
			currentRating = quickDistance(nextPoint, toPoint, compressX);
			if (currentRating < bestRating) {
				bestRating = currentRating;
				bestPath = nextPoint;
			}
		}
	}

	bestPoint = bestPath;
	return pointCounter;
}
Exemple #20
0
void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::List<ResultAction *> &actionList) const {
	// Loop until we find the closing brace
	Common::String line = stream.readLine();
	trimCommentsAndWhiteSpace(&line);

	// TODO: Re-order the if-then statements in order of highest occurrence
	while (!stream.eos() && !line.contains('}')) {
		if (line.empty()) {
			line = stream.readLine();
			trimCommentsAndWhiteSpace(&line);

			continue;
		}

		// Parse for the action type
		if (line.matchString("*:add*", true)) {
			actionList.push_back(new ActionAdd(line));
		} else if (line.matchString("*:animplay*", true)) {
			actionList.push_back(new ActionPlayAnimation(line));
		} else if (line.matchString("*:animpreload*", true)) {
			actionList.push_back(new ActionPreloadAnimation(line));
		} else if (line.matchString("*:animunload*", true)) {
			//actionList.push_back(new ActionUnloadAnimation(line));
		} else if (line.matchString("*:attenuate*", true)) {
			// TODO: Implement ActionAttenuate
		} else if (line.matchString("*:assign*", true)) {
			actionList.push_back(new ActionAssign(line));
		} else if (line.matchString("*:change_location*", true)) {
			actionList.push_back(new ActionChangeLocation(line));
		} else if (line.matchString("*:crossfade*", true)) {
			// TODO: Implement ActionCrossfade
		} else if (line.matchString("*:debug*", true)) {
			// TODO: Implement ActionDebug
		} else if (line.matchString("*:delay_render*", true)) {
			// TODO: Implement ActionDelayRender
		} else if (line.matchString("*:disable_control*", true)) {
			actionList.push_back(new ActionDisableControl(line));
		} else if (line.matchString("*:disable_venus*", true)) {
			// TODO: Implement ActionDisableVenus
		} else if (line.matchString("*:display_message*", true)) {
			// TODO: Implement ActionDisplayMessage
		} else if (line.matchString("*:dissolve*", true)) {
			// TODO: Implement ActionDissolve
		} else if (line.matchString("*:distort*", true)) {
			// TODO: Implement ActionDistort
		} else if (line.matchString("*:enable_control*", true)) {
			actionList.push_back(new ActionEnableControl(line));
		} else if (line.matchString("*:flush_mouse_events*", true)) {
			// TODO: Implement ActionFlushMouseEvents
		} else if (line.matchString("*:inventory*", true)) {
			// TODO: Implement ActionInventory
		} else if (line.matchString("*:kill*", true)) {
			// TODO: Implement ActionKill
		} else if (line.matchString("*:menu_bar_enable*", true)) {
			// TODO: Implement ActionMenuBarEnable
		} else if (line.matchString("*:music*", true)) {
			actionList.push_back(new ActionMusic(line));
		} else if (line.matchString("*:pan_track*", true)) {
			// TODO: Implement ActionPanTrack
		} else if (line.matchString("*:playpreload*", true)) {
			actionList.push_back(new ActionPlayPreloadAnimation(line));
		} else if (line.matchString("*:preferences*", true)) {
			// TODO: Implement ActionPreferences
		} else if (line.matchString("*:quit*", true)) {
			actionList.push_back(new ActionQuit());
		} else if (line.matchString("*:random*", true)) {
			actionList.push_back(new ActionRandom(line));
		} else if (line.matchString("*:region*", true)) {
			// TODO: Implement ActionRegion
		} else if (line.matchString("*:restore_game*", true)) {
			// TODO: Implement ActionRestoreGame
		} else if (line.matchString("*:rotate_to*", true)) {
			// TODO: Implement ActionRotateTo
		} else if (line.matchString("*:save_game*", true)) {
			// TODO: Implement ActionSaveGame
		} else if (line.matchString("*:set_partial_screen*", true)) {
			actionList.push_back(new ActionSetPartialScreen(line));
		} else if (line.matchString("*:set_screen*", true)) {
			actionList.push_back(new ActionSetScreen(line));
		} else if (line.matchString("*:set_venus*", true)) {
			// TODO: Implement ActionSetVenus
		} else if (line.matchString("*:stop*", true)) {
			// TODO: Implement ActionStop
		} else if (line.matchString("*:streamvideo*", true)) {
			actionList.push_back(new ActionStreamVideo(line));
		} else if (line.matchString("*:syncsound*", true)) {
			// TODO: Implement ActionSyncSound
		} else if (line.matchString("*:timer*", true)) {
			actionList.push_back(new ActionTimer(line));
		} else if (line.matchString("*:ttytext*", true)) {
			// TODO: Implement ActionTTYText
		} else if (line.matchString("*:universe_music*", true)) {
			// TODO: Implement ActionUniverseMusic
		} else if (line.matchString("*:copy_file*", true)) {
			// Not used. Purposely left empty
		} else {
			warning("Unhandled result action type: %s", line.c_str());
		}

		line = stream.readLine();
		trimCommentsAndWhiteSpace(&line);
	}

	return;
}
Exemple #21
0
/**
 * Create a ScummEngine instance, based on the given detector data.
 *
 * This is heavily based on our MD5 detection scheme.
 */
Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) const {
	assert(syst);
	assert(engine);
	const char *gameid = ConfMan.get("gameid").c_str();

	// We start by checking whether the specified game ID is obsolete.
	// If that is the case, we automatically upgrade the target to use
	// the correct new game ID (and platform, if specified).
	for (const ADObsoleteGameID *o = obsoleteGameIDsTable; o->from; ++o) {
		if (!scumm_stricmp(gameid, o->from)) {
			// Match found, perform upgrade
			gameid = o->to;
			ConfMan.set("gameid", o->to);

			if (o->platform != Common::kPlatformUnknown)
				ConfMan.set("platform", Common::getPlatformCode(o->platform));

			warning("Target upgraded from game ID %s to %s", o->from, o->to);
			ConfMan.flushToDisk();
			break;
		}
	}

	// Fetch the list of files in the current directory
	Common::FSList fslist;
	Common::FSNode dir(ConfMan.get("path"));
	if (!dir.isDirectory())
		return Common::kInvalidPathError;
	if (!dir.getChildren(fslist, Common::FSNode::kListFilesOnly))
		return Common::kNoGameDataFoundError;

	// Invoke the detector, but fixed to the specified gameid.
	Common::List<DetectorResult> results;
	::detectGames(fslist, results, gameid);

	// Unable to locate game data
	if (results.empty())
		return Common::kNoGameDataFoundError;

	// No unique match found. If a platform override is present, try to
	// narrow down the list a bit more.
	if (results.size() > 1 && ConfMan.hasKey("platform")) {
		Common::Platform platform = Common::parsePlatform(ConfMan.get("platform"));
		Common::List<DetectorResult> tmp;

		// Copy only those candidates which match the platform setting
		for (Common::List<DetectorResult>::iterator
		          x = results.begin(); x != results.end(); ++x) {
			if (x->game.platform == platform) {
				tmp.push_back(*x);
			}
		}

		// If we narrowed it down too much, print a warning, else use the list
		// we just computed as new candidates list.
		if (tmp.empty()) {
			warning("Engine_SCUMM_create: Game data inconsistent with platform override");
		} else {
			results = tmp;
		}
	}

	// Still no unique match found -> print a warning
	if (results.size() > 1)
		warning("Engine_SCUMM_create: No unique game candidate found, using first one");

	// Simply use the first match
	DetectorResult res(*(results.begin()));
	debug(1, "Using gameid %s, variant %s, extra %s", res.game.gameid, res.game.variant, res.extra);

	// Print the MD5 of the game; either verbose using printf, in case of an
	// unknown MD5, or with a medium debug level in case of a known MD5 (for
	// debugging purposes).
	if (!findInMD5Table(res.md5.c_str())) {
		printf("Your game version appears to be unknown. If this is *NOT* a fan-modified\n");
		printf("version (in particular, not a fan-made translation), please, report the\n");
		printf("following data to the ScummVM team along with name of the game you tried\n");
		printf("to add and its version/language/etc.:\n");

		printf("  SCUMM gameid '%s', file '%s', MD5 '%s'\n\n",
				res.game.gameid,
				generateFilenameForDetection(res.fp.pattern, res.fp.genMethod).c_str(),
				res.md5.c_str());
	} else {
		debug(1, "Using MD5 '%s'", res.md5.c_str());
	}

	// If the GUI options were updated, we catch this here and update them in the users config
	// file transparently.
	Common::updateGameGUIOptions(res.game.guioptions, getGameGUIOptionsDescriptionLanguage(res.language));

	// Check for a user override of the platform. We allow the user to override
	// the platform, to make it possible to add games which are not yet in
	// our MD5 database but require a specific platform setting.
	// TODO: Do we really still need / want the platform override ?
	if (ConfMan.hasKey("platform"))
		res.game.platform = Common::parsePlatform(ConfMan.get("platform"));

	// Language override
	if (ConfMan.hasKey("language"))
		res.language = Common::parseLanguage(ConfMan.get("language"));

	// V3 FM-TOWNS games *always* should use the corresponding music driver,
	// anything else makes no sense for them.
	// TODO: Maybe allow the null driver, too?
	if (res.game.platform == Common::kPlatformFMTowns && res.game.version == 3)
		res.game.midi = MDT_TOWNS;
	// Finally, we have massaged the GameDescriptor to our satisfaction, and can
	// instantiate the appropriate game engine. Hooray!
	switch (res.game.version) {
	case 0:
		*engine = new ScummEngine_v0(syst, res);
		break;
	case 1:
	case 2:
		*engine = new ScummEngine_v2(syst, res);
		break;
	case 3:
		if (res.game.features & GF_OLD256)
			*engine = new ScummEngine_v3(syst, res);
		else
			*engine = new ScummEngine_v3old(syst, res);
		break;
	case 4:
		*engine = new ScummEngine_v4(syst, res);
		break;
	case 5:
		*engine = new ScummEngine_v5(syst, res);
		break;
	case 6:
		switch (res.game.heversion) {
#ifdef ENABLE_HE
		case 200:
			*engine = new ScummEngine_vCUPhe(syst, res);
			break;
		case 100:
			*engine = new ScummEngine_v100he(syst, res);
			break;
		case 99:
			*engine = new ScummEngine_v99he(syst, res);
			break;
		case 98:
		case 95:
		case 90:
			*engine = new ScummEngine_v90he(syst, res);
			break;
		case 85:
		case 80:
			*engine = new ScummEngine_v80he(syst, res);
			break;
		case 74:
		case 73:
		case 72:
			*engine = new ScummEngine_v72he(syst, res);
			break;
		case 71:
			*engine = new ScummEngine_v71he(syst, res);
			break;
#endif
		case 70:
			*engine = new ScummEngine_v70he(syst, res);
			break;
		case 62:
		case 61:
			*engine = new ScummEngine_v60he(syst, res);
			break;
		default:
			*engine = new ScummEngine_v6(syst, res);
		}
		break;
#ifdef ENABLE_SCUMM_7_8
	case 7:
		*engine = new ScummEngine_v7(syst, res);
		break;
	case 8:
		*engine = new ScummEngine_v8(syst, res);
		break;
#endif
	default:
		error("Engine_SCUMM_create(): Unknown version of game engine");
	}

	return Common::kNoError;
}
Exemple #22
0
static void detectGames(const Common::FSList &fslist, Common::List<DetectorResult> &results, const char *gameid) {
	DescMap fileMD5Map;
	DetectorResult dr;

	// Dive one level down since mac indy3/loom has its files split into directories. See Bug #1438631
	composeFileHashMap(fslist, fileMD5Map, 2, directoryGlobs);

	// Iterate over all filename patterns.
	for (const GameFilenamePattern *gfp = gameFilenamesTable; gfp->gameid; ++gfp) {
		// If a gameid was specified, we only try to detect that specific game,
		// so we can just skip over everything with a differing gameid.
		if (gameid && scumm_stricmp(gameid, gfp->gameid))
			continue;

		// Generate the detectname corresponding to the gfp. If the file doesn't
		// exist in the directory we are looking at, we can skip to the next
		// one immediately.
		Common::String file(generateFilenameForDetection(gfp->pattern, gfp->genMethod));
		if (!fileMD5Map.contains(file))
			continue;

		// Reset the DetectorResult variable
		dr.fp.pattern = gfp->pattern;
		dr.fp.genMethod = gfp->genMethod;
		dr.game.gameid = 0;
		dr.language = gfp->language;
		dr.md5.clear();
		dr.extra = 0;

		//  ____            _     _
		// |  _ \ __ _ _ __| |_  / |
		// | |_) / _` | '__| __| | |
		// |  __/ (_| | |  | |_  | |
		// |_|   \__,_|_|   \__| |_|
		//
		// PART 1: Trying to find an exact match using MD5.
		//
		//
		// Background: We found a valid detection file. Check if its MD5
		// checksum occurs in our MD5 table. If it does, try to use that
		// to find an exact match.
		//
		// We only do that if the MD5 hadn't already been computed (since
		// we may look at some detection files multiple times).
		//
		DetectorDesc &d = fileMD5Map[file];
		if (d.md5.empty()) {
			Common::SeekableReadStream *tmp = 0;
			bool isDiskImg = (file.hasSuffix(".d64") || file.hasSuffix(".dsk") || file.hasSuffix(".prg"));
			
			if (isDiskImg) {
				tmp = openDiskImage(d.node, gfp);

				debug(2, "Falling back to disk-based detection");
			} else {
				tmp = d.node.createReadStream();
			}

			Common::String md5str;
			if (tmp)
				md5str = computeStreamMD5AsString(*tmp, kMD5FileSizeLimit);
			if (!md5str.empty()) {

				d.md5 = md5str;
				d.md5Entry = findInMD5Table(md5str.c_str());

				dr.md5 = d.md5;

				if (d.md5Entry) {
					// Exact match found. Compute the precise game settings.
					computeGameSettingsFromMD5(fslist, gfp, d.md5Entry, dr);

					// Print some debug info
					int filesize = tmp->size();
					if (d.md5Entry->filesize != filesize)
					debug(1, "SCUMM detector found matching file '%s' with MD5 %s, size %d\n",
						file.c_str(), md5str.c_str(), filesize);

					// Sanity check: We *should* have found a matching gameid / variant at this point.
					// If not, then there's a bug in our data tables...
					assert(dr.game.gameid != 0);

					// Add it to the list of detected games
					results.push_back(dr);
				}
			}

			if (isDiskImg)
				closeDiskImage((ScummDiskImage*)tmp);
			delete tmp;
		}

		// If an exact match for this file has already been found, don't bother
		// looking at it anymore.
		if (d.md5Entry)
			continue;


		//  ____            _     ____
		// |  _ \ __ _ _ __| |_  |___ \ *
		// | |_) / _` | '__| __|   __) |
		// |  __/ (_| | |  | |_   / __/
		// |_|   \__,_|_|   \__| |_____|
		//
		// PART 2: Fuzzy matching for files with unknown MD5.
		//


		// We loop over the game variants matching the gameid associated to
		// the gfp record. We then try to decide for each whether it could be
		// appropriate or not.
		dr.md5 = d.md5;
		for (const GameSettings *g = gameVariantsTable; g->gameid; ++g) {
			// Skip over entries with a different gameid.
			if (g->gameid[0] == 0 || scumm_stricmp(gfp->gameid, g->gameid))
				continue;

			dr.game = *g;
			dr.extra = g->variant; // FIXME: We (ab)use 'variant' for the 'extra' description for now.

			if (gfp->platform != Common::kPlatformUnknown)
				dr.game.platform = gfp->platform;


			// If a variant has been specified, use that!
			if (gfp->variant) {
				if (!scumm_stricmp(gfp->variant, g->variant)) {
					// perfect match found
					results.push_back(dr);
					break;
				}
				continue;
			}

			// HACK: Perhaps it is some modified translation?
			dr.language = detectLanguage(fslist, g->id);

			// Add the game/variant to the candidates list if it is consistent
			// with the file(s) we are seeing.
			if (testGame(g, fileMD5Map, file))
				results.push_back(dr);
		}
	}
}