Beispiel #1
0
void clearList(Common::List<T> &list) {
	while (!list.empty()) {
		T p = list.front();
		list.erase(list.begin());
		delete p;
	}
}
Beispiel #2
0
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);
		}
	}
}
Beispiel #3
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;
}
Beispiel #4
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;
}
Beispiel #5
0
/**
 * 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;
}
Beispiel #6
0
/**
 * 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;
}