Пример #1
0
bool AgiEngine::showPredictiveDialog() {
	GUI::PredictiveDialog predictiveDialog;

	inGameTimerPause();
	predictiveDialog.runModal();
	inGameTimerResume();

	Common::String predictiveResult(predictiveDialog.getResult());
	uint16 predictiveResultLen = predictiveResult.size();
	if (predictiveResult.size()) {
		// User actually entered something
		for (int16 resultPos = 0; resultPos < predictiveResultLen; resultPos++) {
			keyEnqueue(predictiveResult[resultPos]);
		}
		if (!cycleInnerLoopIsActive()) {
			if (_text->promptIsEnabled()) {
				// add ENTER, when the input is probably meant for the prompt
				keyEnqueue(AGI_KEY_ENTER);
			}
		} else {
			switch (_game.cycleInnerLoopType) {
			case CYCLE_INNERLOOP_GETSTRING:
			case CYCLE_INNERLOOP_GETNUMBER:
				// add ENTER, when the input is probably meant for GetString/GetNumber
				keyEnqueue(AGI_KEY_ENTER);
				break;
			default:
				break;
			}
		}
		return true;
	}
	return false;
}
Пример #2
0
void AgiEngine::processScummVMEvents() {
	Common::Event event;
	int key = 0;

	while (_eventMan->pollEvent(event)) {
		switch (event.type) {
		case Common::EVENT_PREDICTIVE_DIALOG:
			showPredictiveDialog();
			break;
		case Common::EVENT_LBUTTONDOWN:
			if (_game.mouseEnabled) {
				key = AGI_MOUSE_BUTTON_LEFT;
				_mouse.button = kAgiMouseButtonLeft;
				keyEnqueue(key);
				_mouse.pos.x = event.mouse.x;
				_mouse.pos.y = event.mouse.y;
			}
			break;
		case Common::EVENT_RBUTTONDOWN:
			if (_game.mouseEnabled) {
				key = AGI_MOUSE_BUTTON_RIGHT;
				_mouse.button = kAgiMouseButtonRight;
				keyEnqueue(key);
				_mouse.pos.x = event.mouse.x;
				_mouse.pos.y = event.mouse.y;
			}
			break;
		case Common::EVENT_WHEELUP:
			if (_game.mouseEnabled) {
				key = AGI_MOUSE_WHEEL_UP;
				keyEnqueue(key);
			}
			break;
		case Common::EVENT_WHEELDOWN:
			if (_game.mouseEnabled) {
				key = AGI_MOUSE_WHEEL_DOWN;
				keyEnqueue(key);
			}
			break;
		case Common::EVENT_MOUSEMOVE:
			if (_game.mouseEnabled) {
				_mouse.pos.x = event.mouse.x;
				_mouse.pos.y = event.mouse.y;

				if (!_game.mouseFence.isEmpty()) {
					if (_mouse.pos.x < _game.mouseFence.left)
						_mouse.pos.x = _game.mouseFence.left;
					if (_mouse.pos.x > _game.mouseFence.right)
						_mouse.pos.x = _game.mouseFence.right;
					if (_mouse.pos.y < _game.mouseFence.top)
						_mouse.pos.y = _game.mouseFence.top;
					if (_mouse.pos.y > _game.mouseFence.bottom)
						_mouse.pos.y = _game.mouseFence.bottom;

					g_system->warpMouse(_mouse.pos.x, _mouse.pos.y);
				}
			}

			break;
		case Common::EVENT_LBUTTONUP:
		case Common::EVENT_RBUTTONUP:
			if (_game.mouseEnabled) {
				_mouse.button = kAgiMouseButtonUp;
				_mouse.pos.x = event.mouse.x;
				_mouse.pos.y = event.mouse.y;
			}
			break;
		case Common::EVENT_KEYDOWN:
			if (event.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_SHIFT) && event.kbd.keycode == Common::KEYCODE_d) {
				_console->attach();
				break;
			}

			key = event.kbd.ascii;
			if (event.kbd.keycode >= Common::KEYCODE_KP0 && event.kbd.keycode <= Common::KEYCODE_KP9) {
				if (!(event.kbd.flags & Common::KBD_NUM)) {
					// HACK: Num-Lock not enabled
					// We shouldn't get a valid ascii code in these cases. We fix it here, so that cursor keys
					// on the numpad work properly.
					key = 0;
				}
			}

			if ((key) && (key <= 0xFF)) {
				// No special key, directly accept it
				// Is ISO-8859-1, we need lower 128 characters only, which is plain ASCII, so no mapping required
				if (Common::isAlpha(key)) {
					// Key is A-Z.
					// Map Ctrl-A to 1, Ctrl-B to 2, etc.
					if (event.kbd.flags & Common::KBD_CTRL) {
						key = toupper(key) - 'A' + 1;
					} else if (event.kbd.flags & Common::KBD_ALT) {
						// Map Alt-A, Alt-B etc. to special scancode values according to an internal scancode table.
						key = scancodeTable[toupper(key) - 'A'] << 8;
					}
				}
			} else {
				key = 0;
				switch (event.kbd.keycode) {
				case Common::KEYCODE_LEFT:
				case Common::KEYCODE_KP4:
					if (_allowSynthetic || !event.synthetic)
						key = AGI_KEY_LEFT;
					break;
				case Common::KEYCODE_RIGHT:
				case Common::KEYCODE_KP6:
					if (_allowSynthetic || !event.synthetic)
						key = AGI_KEY_RIGHT;
					break;
				case Common::KEYCODE_UP:
				case Common::KEYCODE_KP8:
					if (_allowSynthetic || !event.synthetic)
						key = AGI_KEY_UP;
					break;
				case Common::KEYCODE_DOWN:
				case Common::KEYCODE_KP2:
					if (_allowSynthetic || !event.synthetic)
						key = AGI_KEY_DOWN;
					break;
				case Common::KEYCODE_PAGEUP:
				case Common::KEYCODE_KP9:
					if (_allowSynthetic || !event.synthetic)
						key = AGI_KEY_UP_RIGHT;
					break;
				case Common::KEYCODE_PAGEDOWN:
				case Common::KEYCODE_KP3:
					if (_allowSynthetic || !event.synthetic)
						key = AGI_KEY_DOWN_RIGHT;
					break;
				case Common::KEYCODE_HOME:
				case Common::KEYCODE_KP7:
					if (_allowSynthetic || !event.synthetic)
						key = AGI_KEY_UP_LEFT;
					break;
				case Common::KEYCODE_END:
				case Common::KEYCODE_KP1:
					if (_allowSynthetic || !event.synthetic)
						key = AGI_KEY_DOWN_LEFT;
					break;
				case Common::KEYCODE_KP5:
					key = AGI_KEY_STATIONARY;
					break;
				case Common::KEYCODE_F1:
					key = AGI_KEY_F1;
					break;
				case Common::KEYCODE_F2:
					key = AGI_KEY_F2;
					break;
				case Common::KEYCODE_F3:
					key = AGI_KEY_F3;
					break;
				case Common::KEYCODE_F4:
					key = AGI_KEY_F4;
					break;
				case Common::KEYCODE_F5:
					key = AGI_KEY_F5;
					break;
				case Common::KEYCODE_F6:
					key = AGI_KEY_F6;
					break;
				case Common::KEYCODE_F7:
					key = AGI_KEY_F7;
					break;
				case Common::KEYCODE_F8:
					key = AGI_KEY_F8;
					break;
				case Common::KEYCODE_F9:
					key = AGI_KEY_F9;
					break;
				case Common::KEYCODE_F10:
					key = AGI_KEY_F10;
					break;
				case Common::KEYCODE_F11:
					key = AGI_KEY_F11;
					break;
				case Common::KEYCODE_F12:
					key = AGI_KEY_F12;
					break;
				case Common::KEYCODE_KP_ENTER:
					key = AGI_KEY_ENTER;
					break;
				default:
					break;
				}
			}
			if (key)
				keyEnqueue(key);
			break;

		case Common::EVENT_KEYUP:
			if (_keyHoldMode) {
				// Original AGI actually created direction events in here
				// We don't do that, that's why we create a stationary event instead, which will
				// result in a direction change to 0 in handleController().
				switch (event.kbd.keycode) {
				case Common::KEYCODE_LEFT:
				case Common::KEYCODE_RIGHT:
				case Common::KEYCODE_UP:
				case Common::KEYCODE_DOWN:
				case Common::KEYCODE_HOME:
				case Common::KEYCODE_END:
				case Common::KEYCODE_PAGEUP:
				case Common::KEYCODE_PAGEDOWN:
				case Common::KEYCODE_KP4:
				case Common::KEYCODE_KP6:
				case Common::KEYCODE_KP8:
				case Common::KEYCODE_KP2:
				case Common::KEYCODE_KP9:
				case Common::KEYCODE_KP3:
				case Common::KEYCODE_KP7:
				case Common::KEYCODE_KP1:
					keyEnqueue(AGI_KEY_STATIONARY);
					break;
				default:
					break;
				}
			}
			break;

		default:
			break;
		}
	}
}
Пример #3
0
int AgiEngine::handleController(int key) {
	VtEntry *v = &_game.viewTable[0];
	int i;

	// AGI 3.149 games, The Black Cauldron and King's Quest 4 need KEY_ESCAPE to use menus
	// Games with the GF_ESCPAUSE flag need KEY_ESCAPE to pause the game
	if (key == 0 ||
		(key == KEY_ESCAPE && getVersion() != 0x3149 && getGameID() != GID_BC && getGameID() != GID_KQ4 && !(getFeatures() & GF_ESCPAUSE)) )
		return false;

	if ((getGameID() == GID_MH1 || getGameID() == GID_MH2) && (key == KEY_ENTER) &&
			(_game.inputMode == INPUT_NONE)) {
		key = 0x20; // Set Enter key to Space in Manhunter when there's no text input
	}

	debugC(3, kDebugLevelInput, "key = %04x", key);

	for (i = 0; i < MAX_CONTROLLERS; i++) {
		if (_game.controllers[i].keycode == key) {
			debugC(3, kDebugLevelInput, "event %d: key press", _game.controllers[i].controller);
			_game.controllerOccured[_game.controllers[i].controller] = true;
			return true;
		}
	}

	if (key == BUTTON_LEFT) {
		if ((getflag(fMenusWork) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) {
			newInputMode(INPUT_MENU);
			return true;
		}
	}

	// Show predictive dialog if the user clicks on input area
	if (key == BUTTON_LEFT &&
			(int)_mouse.y >= _game.lineUserInput * CHAR_LINES &&
			(int)_mouse.y <= (_game.lineUserInput + 1) * CHAR_LINES) {
		GUI::PredictiveDialog _predictiveDialog;
		_predictiveDialog.runModal();
		strcpy(_predictiveResult, _predictiveDialog.getResult());
		if (strcmp(_predictiveResult, "")) {
			if (_game.inputMode == INPUT_NONE) {
				for (int n = 0; _predictiveResult[n]; n++)
					keyEnqueue(_predictiveResult[n]);
			} else {
				strcpy((char *)_game.inputBuffer, _predictiveResult);
				handleKeys(KEY_ENTER);
			}
		}
		/*
		if (predictiveDialog()) {
			if (_game.inputMode == INPUT_NONE) {
				for (int n = 0; _predictiveResult[n]; n++)
					keyEnqueue(_predictiveResult[n]);
			} else {
				strcpy((char *)_game.inputBuffer, _predictiveResult);
				handleKeys(KEY_ENTER);
			}
		}
		*/
		return true;
	}

	if (_game.playerControl) {
		int d = 0;

		if (!KEY_ASCII(key)) {
			switch (key) {
			case KEY_UP:
				d = 1;
				break;
			case KEY_DOWN:
				d = 5;
				break;
			case KEY_LEFT:
				d = 7;
				break;
			case KEY_RIGHT:
				d = 3;
				break;
			case KEY_UP_RIGHT:
				d = 2;
				break;
			case KEY_DOWN_RIGHT:
				d = 4;
				break;
			case KEY_UP_LEFT:
				d = 8;
				break;
			case KEY_DOWN_LEFT:
				d = 6;
				break;
			}
		}

		if (!(getFeatures() & GF_AGIMOUSE)) {
			// Handle mouse button events
			if (key == BUTTON_LEFT) {
				if (getGameID() == GID_PQ1 && _game.vars[vCurRoom] == 116) {
					// WORKAROUND: Special handling for mouse clicks in the newspaper
					// screen of PQ1. Fixes bug #3018770.
					d = 3;	// fake a right arrow key (next page)
				} else {
					// Click-to-walk mouse interface
					v->flags |= fAdjEgoXY;
					v->parm1 = WIN_TO_PIC_X(_mouse.x);
					v->parm2 = WIN_TO_PIC_Y(_mouse.y);
					return true;
				}
			}
		}

		if (d || key == KEY_STATIONARY) {
			v->flags &= ~fAdjEgoXY;
			v->direction = v->direction == d ? 0 : d;
			return true;
		}
	}

	return false;
}
Пример #4
0
int AgiEngine::selectSlot() {
	int i, key, active = 0;
	int rc = -1;
	int hm = 1, vm = 3;	// box margins
	int xmin, xmax, slotClicked;
	char desc[NUM_VISIBLE_SLOTS][40];
	int textCenter, buttonLength, buttonX[2], buttonY;
	const char *buttonText[] = { "  OK  ", "Cancel", NULL };

	_noSaveLoadAllowed = true;

	for (i = 0; i < NUM_VISIBLE_SLOTS; i++) {
		getSavegameDescription(_firstSlot + i, desc[i]);
	}

	textCenter = GFX_WIDTH / CHAR_LINES / 2;
	buttonLength = 6;
	buttonX[0] = (textCenter - 3 * buttonLength / 2) * CHAR_COLS;
	buttonX[1] = (textCenter + buttonLength / 2) * CHAR_COLS;
	buttonY = (vm + 17) * CHAR_LINES;

	for (i = 0; i < 2; i++)
		_gfx->drawCurrentStyleButton(buttonX[i], buttonY, buttonText[i], false, false, i == 0);

	AllowSyntheticEvents on(this);
	int oldFirstSlot = _firstSlot + 1;
	int oldActive = active + 1;

	while (!(shouldQuit() || _restartGame)) {
		int sbPos = 0;

		// Use the extreme scrollbar positions only if the extreme
		// slots are in sight. (We have to calculate this even if we
		// don't redraw the save slots, because it's also used for
		// clicking in the scrollbar.

		if (_firstSlot == 0)
			sbPos = 1;
		else if (_firstSlot == NUM_SLOTS - NUM_VISIBLE_SLOTS)
			sbPos = NUM_VISIBLE_SLOTS - 2;
		else {
			sbPos = 2 + (_firstSlot * (NUM_VISIBLE_SLOTS - 4)) / (NUM_SLOTS - NUM_VISIBLE_SLOTS - 1);
			if (sbPos >= NUM_VISIBLE_SLOTS - 3)
				sbPos = NUM_VISIBLE_SLOTS - 3;
		}

		if (oldFirstSlot != _firstSlot || oldActive != active) {
			char dstr[64];
			for (i = 0; i < NUM_VISIBLE_SLOTS; i++) {
				sprintf(dstr, "[%2d. %-28.28s]", i + _firstSlot, desc[i]);
				printText(dstr, 0, hm + 1, vm + 4 + i,
						(40 - 2 * hm) - 1, i == active ? MSG_BOX_COLOR : MSG_BOX_TEXT,
						i == active ? MSG_BOX_TEXT : MSG_BOX_COLOR);
			}

			char upArrow[] = "^";
			char downArrow[] = "v";
			char scrollBar[] = " ";

			for (i = 1; i < NUM_VISIBLE_SLOTS - 1; i++)
				printText(scrollBar, 35, hm + 1, vm + 4 + i, 1, MSG_BOX_COLOR, 7, true);

			printText(upArrow, 35, hm + 1, vm + 4, 1, 8, 7);
			printText(downArrow, 35, hm + 1, vm + 4 + NUM_VISIBLE_SLOTS - 1, 1, 8, 7);
			printText(scrollBar, 35, hm + 1, vm + 4 + sbPos, 1, MSG_BOX_COLOR, MSG_BOX_TEXT);

			oldActive = active;
			oldFirstSlot = _firstSlot;
		}

		pollTimer();
		key = doPollKeyboard();

		// It may happen that somebody will open GMM while
		// this dialog is open, and load a game
		// We are processing it here, effectively jumping
		// out of the dead loop
		if (getflag(fRestoreJustRan)) {
			rc = -2;
			goto getout;
		}

		switch (key) {
		case KEY_ENTER:
			rc = active;
			strncpy(_game.strings[MAX_STRINGS], desc[i], MAX_STRINGLEN);
			goto press;
		case KEY_ESCAPE:
			rc = -1;
			goto getout;
		case BUTTON_LEFT:
			if (_gfx->testButton(buttonX[0], buttonY, buttonText[0])) {
				rc = active;
				strncpy(_game.strings[MAX_STRINGS], desc[i], MAX_STRINGLEN);
				goto press;
			}
			if (_gfx->testButton(buttonX[1], buttonY, buttonText[1])) {
				rc = -1;
				goto getout;
			}
			slotClicked = ((int)_mouse.y - 1) / CHAR_COLS - (vm + 4);
			xmin = (hm + 1) * CHAR_COLS;
			xmax = xmin + CHAR_COLS * 34;
			if ((int)_mouse.x >= xmin && (int)_mouse.x <= xmax) {
				if (slotClicked >= 0 && slotClicked < NUM_VISIBLE_SLOTS)
					active = slotClicked;
			}
			xmin = (hm + 36) * CHAR_COLS;
			xmax = xmin + CHAR_COLS;
			if ((int)_mouse.x >= xmin && (int)_mouse.x <= xmax) {
				if (slotClicked >= 0 && slotClicked < NUM_VISIBLE_SLOTS) {
					if (slotClicked == 0)
						keyEnqueue(KEY_UP);
					else if (slotClicked == NUM_VISIBLE_SLOTS - 1)
						keyEnqueue(KEY_DOWN);
					else if (slotClicked < sbPos)
						keyEnqueue(KEY_UP_RIGHT);
					else if (slotClicked > sbPos)
						keyEnqueue(KEY_DOWN_RIGHT);
				}
			}
			break;
		case KEY_DOWN:
			active++;
			if (active >= NUM_VISIBLE_SLOTS) {
				if (_firstSlot + NUM_VISIBLE_SLOTS < NUM_SLOTS) {
					_firstSlot++;
					for (i = 1; i < NUM_VISIBLE_SLOTS; i++)
						memcpy(desc[i - 1], desc[i], sizeof(desc[0]));
					getSavegameDescription(_firstSlot + NUM_VISIBLE_SLOTS - 1, desc[NUM_VISIBLE_SLOTS - 1]);
				}
				active = NUM_VISIBLE_SLOTS - 1;
			}
			break;
		case KEY_UP:
			active--;
			if (active < 0) {
				active = 0;
				if (_firstSlot > 0) {
					_firstSlot--;
					for (i = NUM_VISIBLE_SLOTS - 1; i > 0; i--)
						memcpy(desc[i], desc[i - 1], sizeof(desc[0]));
					getSavegameDescription(_firstSlot, desc[0]);
				}
			}
			break;

		// Page Up/Down and mouse wheel scrolling all leave 'active'
		// unchanged so that a visible slot will remain selected.

		case WHEEL_DOWN:
			if (_firstSlot < NUM_SLOTS - NUM_VISIBLE_SLOTS) {
				_firstSlot++;
				for (i = 1; i < NUM_VISIBLE_SLOTS; i++)
					memcpy(desc[i - 1], desc[i], sizeof(desc[0]));
				getSavegameDescription(_firstSlot + NUM_VISIBLE_SLOTS - 1, desc[NUM_VISIBLE_SLOTS - 1]);
			}
			break;
		case WHEEL_UP:
			if (_firstSlot > 0) {
				_firstSlot--;
				for (i = NUM_VISIBLE_SLOTS - 1; i > 0; i--)
					memcpy(desc[i], desc[i - 1], sizeof(desc[0]));
				getSavegameDescription(_firstSlot, desc[0]);
			}
			break;
		case KEY_DOWN_RIGHT:
			// This is probably triggered by Page Down.
			_firstSlot += NUM_VISIBLE_SLOTS;
			if (_firstSlot > NUM_SLOTS - NUM_VISIBLE_SLOTS) {
				_firstSlot = NUM_SLOTS - NUM_VISIBLE_SLOTS;
			}
			for (i = 0; i < NUM_VISIBLE_SLOTS; i++)
				getSavegameDescription(_firstSlot + i, desc[i]);
			break;
		case KEY_UP_RIGHT:
			// This is probably triggered by Page Up.
			_firstSlot -= NUM_VISIBLE_SLOTS;
			if (_firstSlot < 0) {
				_firstSlot = 0;
			}
			for (i = 0; i < NUM_VISIBLE_SLOTS; i++)
				getSavegameDescription(_firstSlot + i, desc[i]);
			break;
		}
		_gfx->doUpdate();
	}

press:
	debugC(8, kDebugLevelMain | kDebugLevelInput, "Button pressed: %d", rc);

getout:
	closeWindow();

	_noSaveLoadAllowed = false;

	return rc;
}