void clearList(Common::List<T> &list) { while (!list.empty()) { T p = list.front(); list.erase(list.begin()); delete p; } }
void Location::freeList(Common::List<T> &list, bool removeAll, Common::MemFunc1<bool, T, Location> filter) { typedef typename Common::List<T>::iterator iterator; iterator it = list.begin(); while (it != list.end()) { T z = *it; if (!removeAll && filter(this, z)) { ++it; } else { z->_commands.clear(); it = list.erase(it); } } }
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; }
/** * 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; }