aboutsummaryrefslogtreecommitdiff
path: root/engines/agi
diff options
context:
space:
mode:
authorMartin Kiewitz2016-02-01 01:34:36 +0100
committerMartin Kiewitz2016-02-01 01:34:36 +0100
commitc28e101cdbfcc28f080da245e49f5b764bb8fc44 (patch)
tree77e6025b13008783b0839e1e4a71246683e19235 /engines/agi
parent73242aa5bc15746572c183b24c77e7fb20c023a0 (diff)
downloadscummvm-rg350-c28e101cdbfcc28f080da245e49f5b764bb8fc44.tar.gz
scummvm-rg350-c28e101cdbfcc28f080da245e49f5b764bb8fc44.tar.bz2
scummvm-rg350-c28e101cdbfcc28f080da245e49f5b764bb8fc44.zip
AGI: implement predictive dialog
Diffstat (limited to 'engines/agi')
-rw-r--r--engines/agi/agi.h8
-rw-r--r--engines/agi/cycle.cpp27
-rw-r--r--engines/agi/keyboard.cpp240
-rw-r--r--engines/agi/op_cmd.cpp11
-rw-r--r--engines/agi/text.cpp29
-rw-r--r--engines/agi/text.h7
6 files changed, 194 insertions, 128 deletions
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 1e6001dae3..9d220d2062 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -231,8 +231,7 @@ struct gameIdList {
struct Mouse {
int button;
- int x;
- int y;
+ Common::Point pos;
};
// Used by AGI Mouse protocol 1.0 for v27 (i.e. button pressed -variable).
@@ -942,7 +941,12 @@ public:
void cleanKeyboard();
int16 getSpecialMenuControllerSlot();
+
+ bool handleMouseClicks(uint16 &key);
bool handleController(uint16 key);
+
+ bool showPredictiveDialog();
+
uint16 agiGetKeypress();
int waitKey();
int waitAnyKey();
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index 6506ee29eb..67a238df08 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -206,8 +206,8 @@ int AgiEngine::mainCycle(bool onlyCheckForEvents) {
//
// We run AGIMOUSE always as a side effect
//if (getFeatures() & GF_AGIMOUSE) {
- setVar(VM_VAR_MOUSE_X, _mouse.x / 2);
- setVar(VM_VAR_MOUSE_Y, _mouse.y);
+ setVar(VM_VAR_MOUSE_X, _mouse.pos.x / 2);
+ setVar(VM_VAR_MOUSE_Y, _mouse.pos.y);
//}
switch (_game.inputMode) {
@@ -245,21 +245,27 @@ int AgiEngine::mainCycle(bool onlyCheckForEvents) {
setVar(VM_VAR_KEY, keyAscii);
}
+ handleMouseClicks(key);
+
if (!cycleInnerLoopIsActive()) {
// no inner loop active at the moment, regular processing
switch (_game.inputMode) {
case INPUTMODE_NORMAL:
- if (!handleController(key)) {
- if (key == 0 || (!_text->promptIsEnabled()))
- break;
-
- _text->promptCharPress(key);
+ if (key) {
+ if (!handleController(key)) {
+ if ((key) && (_text->promptIsEnabled())) {
+ _text->promptCharPress(key);
+ }
+ }
}
break;
case INPUTMODE_NONE:
- handleController(key);
- if (key)
- _game.keypress = key;
+ if (key) {
+ handleController(key);
+ if (key) {
+ _game.keypress = key;
+ }
+ }
break;
default:
break;
@@ -274,7 +280,6 @@ int AgiEngine::mainCycle(bool onlyCheckForEvents) {
switch (_game.cycleInnerLoopType) {
case CYCLE_INNERLOOP_GETSTRING: // loop called from TextMgr::stringEdit()
case CYCLE_INNERLOOP_GETNUMBER:
- //handleController(key);
if (key) {
_text->stringCharPress(key);
}
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 2a5f801a25..07aec985c8 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -68,52 +68,16 @@ void AgiEngine::processEvents() {
while (_eventMan->pollEvent(event)) {
switch (event.type) {
- case Common::EVENT_PREDICTIVE_DIALOG: {
- GUI::PredictiveDialog _predictiveDialog;
- _predictiveDialog.runModal();
-#if 0
- strcpy(_predictiveResult, _predictiveDialog.getResult());
- if (strcmp(_predictiveResult, "")) {
- if (_game.inputMode == INPUTMODE_NORMAL) {
- //strcpy((char *)_game.inputBuffer, _predictiveResult);
- //handleKeys(KEY_ENTER);
- // TODO: repair predictive
- } else if (_game.inputMode == INPUTMODE_GETSTRING) {
- strcpy(_game.strings[_stringdata.str], _predictiveResult);
- newInputMode(INPUTMODE_NORMAL);
- //_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
- // _stringdata.y, ' ', 15, 0);
- } else if (_game.inputMode == INPUTMODE_NONE) {
- for (int n = 0; _predictiveResult[n]; n++)
- keyEnqueue(_predictiveResult[n]);
- }
- }
-#endif
- /*
- if (predictiveDialog()) {
- if (_game.inputMode == INPUT_NORMAL) {
- strcpy((char *)_game.inputBuffer, _predictiveResult);
- handleKeys(KEY_ENTER);
- } else if (_game.inputMode == INPUT_GETSTRING) {
- strcpy(_game.strings[_stringdata.str], _predictiveResult);
- newInputMode(INPUT_NORMAL);
- _gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
- _stringdata.y, ' ', _game.colorFg, _game.colorBg);
- } else if (_game.inputMode == INPUT_NONE) {
- for (int n = 0; _predictiveResult[n]; n++)
- keyEnqueue(_predictiveResult[n]);
- }
- }
- */
- }
+ 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.x = event.mouse.x;
- _mouse.y = event.mouse.y;
+ _mouse.pos.x = event.mouse.x;
+ _mouse.pos.y = event.mouse.y;
}
break;
case Common::EVENT_RBUTTONDOWN:
@@ -121,8 +85,8 @@ void AgiEngine::processEvents() {
key = AGI_MOUSE_BUTTON_RIGHT;
_mouse.button = kAgiMouseButtonRight;
keyEnqueue(key);
- _mouse.x = event.mouse.x;
- _mouse.y = event.mouse.y;
+ _mouse.pos.x = event.mouse.x;
+ _mouse.pos.y = event.mouse.y;
}
break;
case Common::EVENT_WHEELUP:
@@ -139,20 +103,20 @@ void AgiEngine::processEvents() {
break;
case Common::EVENT_MOUSEMOVE:
if (_game.mouseEnabled) {
- _mouse.x = event.mouse.x;
- _mouse.y = event.mouse.y;
+ _mouse.pos.x = event.mouse.x;
+ _mouse.pos.y = event.mouse.y;
if (!_game.mouseFence.isEmpty()) {
- if (_mouse.x < _game.mouseFence.left)
- _mouse.x = _game.mouseFence.left;
- if (_mouse.x > _game.mouseFence.right)
- _mouse.x = _game.mouseFence.right;
- if (_mouse.y < _game.mouseFence.top)
- _mouse.y = _game.mouseFence.top;
- if (_mouse.y > _game.mouseFence.bottom)
- _mouse.y = _game.mouseFence.bottom;
-
- g_system->warpMouse(_mouse.x, _mouse.y);
+ 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);
}
}
@@ -161,8 +125,8 @@ void AgiEngine::processEvents() {
case Common::EVENT_RBUTTONUP:
if (_game.mouseEnabled) {
_mouse.button = kAgiMouseButtonUp;
- _mouse.x = event.mouse.x;
- _mouse.y = event.mouse.y;
+ _mouse.pos.x = event.mouse.x;
+ _mouse.pos.y = event.mouse.y;
}
break;
case Common::EVENT_KEYDOWN:
@@ -347,6 +311,86 @@ int16 AgiEngine::getSpecialMenuControllerSlot() {
return -1;
}
+bool AgiEngine::handleMouseClicks(uint16 &key) {
+ // No mouse click? -> exit
+ if (key != AGI_MOUSE_BUTTON_LEFT)
+ return false;
+
+ Common::Rect displayLineRect(DISPLAY_WIDTH, FONT_DISPLAY_HEIGHT);
+ int16 statusRow = _text->statusRow_Get();
+
+ displayLineRect.moveTo(0, statusRow * FONT_DISPLAY_HEIGHT);
+
+ if (displayLineRect.contains(_mouse.pos)) {
+ if (getFlag(VM_FLAG_MENUS_WORK) && _menu->isAvailable()) {
+ warning("click on status line -> menu TODO");
+ // TODO: menu
+ // This should be done in a better way as in simulate ESC key
+ // Sierra seems to have hardcoded it in some way, but we would have to verify, what flags
+ // they checked. The previous way wasn't accurate. Mouse support for menu is missing atm anyway.
+ //if ((getflag(VM_FLAG_MENUS_WORK) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) {
+ // newInputMode(INPUTMODE_MENU);
+ // return true;
+ //}
+ key = 0; // eat event
+ return true;
+ }
+ }
+
+ if (_text->promptIsEnabled() && (!cycleInnerLoopIsActive()) ) {
+ // Prompt is currently enabled, but no inner loop is active
+ int16 promptRow = _text->promptRow_Get();
+
+ displayLineRect.moveTo(0, promptRow * FONT_DISPLAY_HEIGHT);
+
+ if (displayLineRect.contains(_mouse.pos)) {
+ // and user clicked within the line of the prompt
+ showPredictiveDialog();
+
+ key = 0; // eat event
+ return true;
+ }
+ }
+
+ if (cycleInnerLoopIsActive()) {
+ // inner loop active, check what kind of loop it is. Then process / forward it
+ switch (_game.cycleInnerLoopType) {
+ case CYCLE_INNERLOOP_GETSTRING:
+ case CYCLE_INNERLOOP_GETNUMBER: {
+ // process in here
+ int16 stringRow, stringColumn, stringMaxLen;
+
+ _text->stringPos_Get(stringRow, stringColumn);
+ stringMaxLen = _text->stringGetMaxLen();
+
+ Common::Rect displayRect(stringMaxLen * FONT_DISPLAY_WIDTH, FONT_DISPLAY_HEIGHT);
+ displayRect.moveTo(stringColumn * FONT_DISPLAY_WIDTH, stringRow * FONT_DISPLAY_HEIGHT);
+
+ if (displayRect.contains(_mouse.pos)) {
+ // user clicked inside the input space
+ showPredictiveDialog();
+
+ key = 0; // eat event
+ return true;
+ }
+ break;
+ }
+ case CYCLE_INNERLOOP_INVENTORY:
+ // TODO: forward
+ break;
+ case CYCLE_INNERLOOP_MENU:
+ // TODO: forward
+ break;
+ case CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT:
+ // TODO: forward
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
bool AgiEngine::handleController(uint16 key) {
ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
@@ -407,51 +451,6 @@ bool AgiEngine::handleController(uint16 key) {
}
}
- if (key == AGI_MOUSE_BUTTON_LEFT) {
- // call mouse when click is done on status bar
- // TODO
- // This should be done in a better way as in simulate ESC key
- // Sierra seems to have hardcoded it in some way, but we would have to verify, what flags
- // they checked. The previous way wasn't accurate. Mouse support for menu is missing atm anyway.
- //if ((getflag(VM_FLAG_MENUS_WORK) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) {
- // newInputMode(INPUTMODE_MENU);
- // return true;
- //}
- }
-
- // Show predictive dialog if the user clicks on input area
- if (key == AGI_MOUSE_BUTTON_LEFT &&
- (int)_mouse.y >= _text->promptRow_Get() * FONT_DISPLAY_HEIGHT &&
- (int)_mouse.y <= (_text->promptRow_Get() + 1) * FONT_DISPLAY_HEIGHT) {
- GUI::PredictiveDialog _predictiveDialog;
- _predictiveDialog.runModal();
-#if 0
- strcpy(_predictiveResult, _predictiveDialog.getResult());
- if (strcmp(_predictiveResult, "")) {
- if (_game.inputMode == INPUTMODE_NONE) {
- for (int n = 0; _predictiveResult[n]; n++)
- keyEnqueue(_predictiveResult[n]);
- } else {
- //strcpy((char *)_game.inputBuffer, _predictiveResult);
- //handleKeys(KEY_ENTER);
- // TODO
- }
- }
-#endif
- /*
- 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;
- }
-
int16 newDirection = 0;
switch (key) {
@@ -498,8 +497,8 @@ bool AgiEngine::handleController(uint16 key) {
//v->flags |= fAdjEgoXY;
// setting fAdjEgoXY here will at least break "climbing the log" in SQ2
// in case you walked to the log by using the mouse, so don't!!!
- int16 egoDestinationX = _mouse.x;
- int16 egoDestinationY = _mouse.y;
+ int16 egoDestinationX = _mouse.pos.x;
+ int16 egoDestinationY = _mouse.pos.y;
adjustPosToGameScreen(egoDestinationX, egoDestinationY);
screenObjEgo->motionType = kMotionEgo;
@@ -534,6 +533,41 @@ bool AgiEngine::handleController(uint16 key) {
return false;
}
+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;
+}
+
int AgiEngine::waitKey() {
int key = 0;
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 4b82d2464a..f36090dafa 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -1851,8 +1851,7 @@ void cmdConfigureScreen(AgiGame *state, uint8 *parameter) {
uint16 promptRow = parameter[1];
uint16 statusRow = parameter[2];
- state->_vm->_text->configureScreen(lineMinPrint);
-
+ textMgr->configureScreen(lineMinPrint);
textMgr->statusRow_Set(statusRow);
textMgr->promptRow_Set(promptRow);
}
@@ -2256,8 +2255,8 @@ void cmdPushScript(AgiGame *state, uint8 *parameter) {
// We run AGIMOUSE always as a side effect
//if (getFeatures() & GF_AGIMOUSE || true) {
vm->setVar(VM_VAR_MOUSE_BUTTONSTATE, state->_vm->_mouse.button);
- vm->setVar(VM_VAR_MOUSE_X, state->_vm->_mouse.x / 2);
- vm->setVar(VM_VAR_MOUSE_Y, state->_vm->_mouse.y);
+ vm->setVar(VM_VAR_MOUSE_X, vm->_mouse.pos.x / 2);
+ vm->setVar(VM_VAR_MOUSE_Y, vm->_mouse.pos.y);
/*} else {
if (getVersion() >= 0x2915) {
debug(0, "push.script");
@@ -2277,8 +2276,8 @@ void cmdMousePosn(AgiGame *state, uint8 *parameter) {
AgiEngine *vm = state->_vm;
uint16 destVarNr1 = parameter[0];
uint16 destVarNr2 = parameter[1];
- int16 mouseX = state->_vm->_mouse.x;
- int16 mouseY = state->_vm->_mouse.y;
+ int16 mouseX = vm->_mouse.pos.x;
+ int16 mouseY = vm->_mouse.pos.y;
state->_vm->adjustPosToGameScreen(mouseX, mouseY);
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index 8806aeee28..c6c0f93651 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -64,6 +64,8 @@ TextMgr::TextMgr(AgiEngine *vm, Words *words, GfxMgr *gfx) {
promptDisable();
promptReset();
+ _inputStringRow = 0;
+ _inputStringColumn = 0;
_inputStringMaxLen = 0;
_inputStringCursorPos = 0;
_inputString[0] = 0;
@@ -107,16 +109,21 @@ void TextMgr::charPos_Set(int16 row, int16 column) {
_textPos.column = column;
}
-void TextMgr::charPos_Get(TextPos_Struct *posPtr) {
- posPtr->row = _textPos.row;
- posPtr->column = _textPos.column;
-}
-
void TextMgr::charPos_Set(TextPos_Struct *posPtr) {
_textPos.row = posPtr->row;
_textPos.column = posPtr->column;
}
+void TextMgr::charPos_Get(int16 &row, int16 &column) {
+ row = _textPos.row;
+ column = _textPos.column;
+}
+
+void TextMgr::charPos_Get(TextPos_Struct *posPtr) {
+ posPtr->row = _textPos.row;
+ posPtr->column = _textPos.column;
+}
+
void TextMgr::charPos_Push() {
if (_textPosArrayCount < TEXTPOSARRAY_MAX) {
charPos_Get(&_textPosArray[_textPosArrayCount]);
@@ -735,9 +742,21 @@ void TextMgr::stringSet(const char *text) {
_inputString[sizeof(_inputString) - 1] = 0; // terminator
}
+void TextMgr::stringPos_Get(int16 &row, int16 &column) {
+ row = _inputStringRow;
+ column = _inputStringColumn;
+}
+int16 TextMgr::stringGetMaxLen() {
+ return _inputStringMaxLen;
+}
+
void TextMgr::stringEdit(int16 stringMaxLen) {
int16 inputStringLen = strlen((const char *)_inputString);
+ // Remember current position for predictive dialog
+ _inputStringRow = _textPos.row;
+ _inputStringColumn = _textPos.column;
+
// Caller can set the input string
_inputStringCursorPos = 0;
while (_inputStringCursorPos < inputStringLen) {
diff --git a/engines/agi/text.h b/engines/agi/text.h
index b42f0982d5..febb50fcb9 100644
--- a/engines/agi/text.h
+++ b/engines/agi/text.h
@@ -107,8 +107,9 @@ public:
void charPos_Clip(int16 &row, int16 &column);
void charPos_Set(int16 row, int16 column);
- void charPos_Get(TextPos_Struct *posPtr);
void charPos_Set(TextPos_Struct *posPtr);
+ void charPos_Get(int16 &row, int16 &column);
+ void charPos_Get(TextPos_Struct *posPtr);
void charPos_Push();
void charPos_Pop();
void charPos_SetInsideWindow(int16 windowRow, int16 windowColumn);
@@ -181,12 +182,16 @@ public:
void promptClear(); // for AGI1
void promptRememberForAutoComplete(bool entered = false); // for auto-completion
+ int16 _inputStringRow;
+ int16 _inputStringColumn;
bool _inputStringEntered;
int16 _inputStringMaxLen;
int16 _inputStringCursorPos;
byte _inputString[42];
bool stringWasEntered();
+ void stringPos_Get(int16 &row, int16 &column);
+ int16 stringGetMaxLen();
void stringSet(const char *text);
void stringEdit(int16 stringMaxLen);
void stringCharPress(int16 newChar);