void clearList(Common::List<T> &list) { while (!list.empty()) { T p = list.front(); list.erase(list.begin()); delete p; } }
SciVersion GameFeatures::detectMessageFunctionType() { if (_messageFunctionType != SCI_VERSION_NONE) return _messageFunctionType; if (getSciVersion() > SCI_VERSION_1_1) { _messageFunctionType = SCI_VERSION_1_1; return _messageFunctionType; } else if (getSciVersion() < SCI_VERSION_1_1) { _messageFunctionType = SCI_VERSION_1_LATE; return _messageFunctionType; } Common::List<ResourceId> resources = g_sci->getResMan()->listResources(kResourceTypeMessage, -1); if (resources.empty()) { // No messages found, so this doesn't really matter anyway... _messageFunctionType = SCI_VERSION_1_1; return _messageFunctionType; } Resource *res = g_sci->getResMan()->findResource(*resources.begin(), false); assert(res); // Only v2 Message resources use the kGetMessage kernel function. // v3-v5 use the kMessage kernel function. if (READ_SCI11ENDIAN_UINT32(res->data) / 1000 == 2) _messageFunctionType = SCI_VERSION_1_LATE; else _messageFunctionType = SCI_VERSION_1_1; debugC(1, kDebugLevelVM, "Detected message function type: %s", getSciVersionDesc(_messageFunctionType)); return _messageFunctionType; }
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 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(); }
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; }
/** * Process to handle changes in the mouse buttons. */ static void MouseProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; bool lastLWasDouble; bool lastRWasDouble; uint32 lastLeftClick, lastRightClick; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); _ctx->lastLWasDouble = false; _ctx->lastRWasDouble = false; _ctx->lastLeftClick = _ctx->lastRightClick = DwGetCurrentTime(); while (true) { if (mouseButtons.empty()) { // allow scheduling CORO_SLEEP(1); continue; } // get next mouse button event Common::EventType type = *mouseButtons.begin(); mouseButtons.erase(mouseButtons.begin()); int xp, yp; GetCursorXYNoWait(&xp, &yp, true); const Common::Point mousePos(xp, yp); switch (type) { case Common::EVENT_LBUTTONDOWN: // left button press if (DwGetCurrentTime() - _ctx->lastLeftClick < (uint32)dclickSpeed) { // Left button double-click if (TinselV2) { // Kill off the button process and fire off the action command g_scheduler->killMatchingProcess(PID_BTN_CLICK, -1); PlayerEvent(PLR_ACTION, clickPos); } else { // signal left drag start ProcessButEvent(PLR_DRAG1_START); // signal left double click event ProcessButEvent(PLR_DLEFT); } _ctx->lastLWasDouble = true; } else { // Initial mouse down - either for a single click, or potentially // the start of a double-click action if (TinselV2) { PlayerEvent(PLR_DRAG1_START, mousePos); ProvNotProcessed(); PlayerEvent(PLR_PROV_WALKTO, mousePos); } else { // signal left drag start ProcessButEvent(PLR_DRAG1_START); // signal left single click event ProcessButEvent(PLR_SLEFT); } _ctx->lastLWasDouble = false; } break; case Common::EVENT_LBUTTONUP: // left button release // update click timer if (_ctx->lastLWasDouble == false) { _ctx->lastLeftClick = DwGetCurrentTime(); // If player control is enabled, start a process which, if it times out, // will activate a single button click if (TinselV2 && ControlIsOn()) { clickPos = mousePos; g_scheduler->createProcess(PID_BTN_CLICK, SingleLeftProcess, NULL, 0); } } else _ctx->lastLeftClick -= dclickSpeed; if (TinselV2) // Signal left drag end PlayerEvent(PLR_DRAG1_END, mousePos); else // signal left drag end ProcessButEvent(PLR_DRAG1_END); break; case Common::EVENT_RBUTTONDOWN: // right button press if (DwGetCurrentTime() - _ctx->lastRightClick < (uint32)dclickSpeed) { // Right button double-click if (TinselV2) { PlayerEvent(PLR_NOEVENT, clickPos); } else { // signal right drag start ProcessButEvent(PLR_DRAG2_START); // signal right double click event ProcessButEvent(PLR_DRIGHT); } _ctx->lastRWasDouble = true; } else { if (TinselV2) { PlayerEvent(PLR_DRAG2_START, mousePos); PlayerEvent(PLR_LOOK, mousePos); } else { // signal right drag start ProcessButEvent(PLR_DRAG2_START); // signal right single click event ProcessButEvent(PLR_SRIGHT); } _ctx->lastRWasDouble = false; } break; case Common::EVENT_RBUTTONUP: // right button release // update click timer if (_ctx->lastRWasDouble == false) _ctx->lastRightClick = DwGetCurrentTime(); else _ctx->lastRightClick -= dclickSpeed; if (TinselV2) // Signal left drag end PlayerEvent(PLR_DRAG2_END, mousePos); else // signal right drag end ProcessButEvent(PLR_DRAG2_END); break; default: break; } } CORO_END_CODE; }
/** * Process to handle keypresses */ void KeyboardProcess(CORO_PARAM, const void *) { // COROUTINE CORO_BEGIN_CONTEXT; CORO_END_CONTEXT(_ctx); CORO_BEGIN_CODE(_ctx); while (true) { if (keypresses.empty()) { // allow scheduling CORO_SLEEP(1); continue; } // Get the next keyboard event off the stack Common::Event evt = *keypresses.begin(); keypresses.erase(keypresses.begin()); const Common::Point mousePos = _vm->getMousePosition(); // Switch for special keys switch (evt.kbd.keycode) { // Drag action case Common::KEYCODE_LALT: case Common::KEYCODE_RALT: if (evt.type == Common::EVENT_KEYDOWN) { if (!bSwapButtons) ProcessButEvent(PLR_DRAG2_START); else ProcessButEvent(PLR_DRAG1_START); } else { if (!bSwapButtons) ProcessButEvent(PLR_DRAG1_END); else ProcessButEvent(PLR_DRAG2_END); } continue; case Common::KEYCODE_LCTRL: case Common::KEYCODE_RCTRL: if (evt.type == Common::EVENT_KEYDOWN) { ProcessKeyEvent(PLR_LOOK); } else { // Control key release } continue; default: break; } // At this point only key down events need processing if (evt.type == Common::EVENT_KEYUP) continue; if (_vm->_keyHandler != NULL) // Keyboard is hooked, so pass it on to that handler first if (!_vm->_keyHandler(evt.kbd)) continue; switch (evt.kbd.keycode) { /*** SPACE = WALKTO ***/ case Common::KEYCODE_SPACE: ProcessKeyEvent(PLR_WALKTO); continue; /*** RETURN = ACTION ***/ case Common::KEYCODE_RETURN: case Common::KEYCODE_KP_ENTER: ProcessKeyEvent(PLR_ACTION); continue; /*** l = LOOK ***/ case Common::KEYCODE_l: // LOOK ProcessKeyEvent(PLR_LOOK); continue; case Common::KEYCODE_ESCAPE: ProcessKeyEvent(PLR_ESCAPE); continue; #ifdef SLOW_RINCE_DOWN case '>': AddInterlude(1); continue; case '<': AddInterlude(-1); continue; #endif case Common::KEYCODE_F1: // Options dialog ProcessKeyEvent(PLR_MENU); continue; case Common::KEYCODE_F5: // Save game ProcessKeyEvent(PLR_SAVE); continue; case Common::KEYCODE_F7: // Load game ProcessKeyEvent(PLR_LOAD); continue; case Common::KEYCODE_m: // Debug facility - scene hopper if (TinselV2 && (evt.kbd.flags == Common::KBD_ALT)) ProcessKeyEvent(PLR_JUMP); break; case Common::KEYCODE_q: if ((evt.kbd.flags == Common::KBD_CTRL) || (evt.kbd.flags == Common::KBD_ALT)) ProcessKeyEvent(PLR_QUIT); continue; case Common::KEYCODE_PAGEUP: case Common::KEYCODE_KP9: ProcessKeyEvent(PLR_PGUP); continue; case Common::KEYCODE_PAGEDOWN: case Common::KEYCODE_KP3: ProcessKeyEvent(PLR_PGDN); continue; case Common::KEYCODE_HOME: case Common::KEYCODE_KP7: ProcessKeyEvent(PLR_HOME); continue; case Common::KEYCODE_END: case Common::KEYCODE_KP1: ProcessKeyEvent(PLR_END); continue; default: ProcessKeyEvent(PLR_NOEVENT); break; } } CORO_END_CODE; }
/** * 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; }
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); } }