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; }
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; }
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()); } }
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(); }
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; }
/** * 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); }
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; }
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(); }
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; }
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); }
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(); }
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; }
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; }
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; }
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); } }
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; }
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; }
/** * 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; }
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); } } }