BLADERUNNER: Add confirm and delete keymaps for KIA

This commit is contained in:
antoniou79 2022-04-06 13:05:59 +03:00
parent 9d9b6be671
commit c2aa001fbd
11 changed files with 138 additions and 42 deletions

View File

@ -1292,11 +1292,13 @@ bool BladeRunnerEngine::isAllowedRepeatedCustomEvent(const Common::Event &currev
switch (currevent.type) {
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
switch ((BladeRunnerEngineMappableAction)currevent.customType) {
case kMpblActionCutsceneSkip:
case kMpActionCutsceneSkip:
// fall through
case kMpActionDialogueSkip:
// fall through
case kMpActionToggleKiaOptions:
// fall through
case kMpConfirmDlg:
return true;
default:
@ -1324,12 +1326,7 @@ bool BladeRunnerEngine::isAllowedRepeatedKey(const Common::KeyState &currKeyStat
// This is noticable when choosing an already saved game to overwrite
// and holding down Enter would cause the confirmation dialogue to pop up
// and it would subsequently confirm it as well.
// TODO if we introduce a custom confirm action for KIA, then that action should be repeatable
// and KEYCODE_RETURN and KEYCODE_KP_ENTER should be removed from this clause;
// the action should be added to the switch cases in isAllowedRepeatedCustomEvent()
return currKeyState.keycode == Common::KEYCODE_RETURN
|| currKeyState.keycode == Common::KEYCODE_KP_ENTER
|| currKeyState.keycode == Common::KEYCODE_BACKSPACE
return currKeyState.keycode == Common::KEYCODE_BACKSPACE
|| currKeyState.keycode == Common::KEYCODE_SPACE
|| currKeyState.keycode == Common::KEYCODE_KP_MINUS
|| currKeyState.keycode == Common::KEYCODE_KP_PLUS
@ -1369,7 +1366,7 @@ void BladeRunnerEngine::handleEvents() {
handleMouseAction(event.mouse.x, event.mouse.y, false, false);
break;
case kMpblActionCutsceneSkip:
case kMpActionCutsceneSkip:
// fall through
case kMpActionDialogueSkip:
// fall through
@ -1390,6 +1387,10 @@ void BladeRunnerEngine::handleEvents() {
case kMpActionOpenKIATabClueDatabase:
// fall through
case kMpActionOpenKIATabQuitGame:
// fall through
case kMpConfirmDlg:
// fall through
case kMpDeleteSelectedSvdGame:
handleCustomEventStop(event);
break;
@ -1410,7 +1411,7 @@ void BladeRunnerEngine::handleEvents() {
handleMouseAction(event.mouse.x, event.mouse.y, false, true);
break;
case kMpblActionCutsceneSkip:
case kMpActionCutsceneSkip:
// fall through
case kMpActionDialogueSkip:
// fall through
@ -1431,6 +1432,10 @@ void BladeRunnerEngine::handleEvents() {
case kMpActionOpenKIATabClueDatabase:
// fall through
case kMpActionOpenKIATabQuitGame:
// fall through
case kMpConfirmDlg:
// fall through
case kMpDeleteSelectedSvdGame:
if (isAllowedRepeatedCustomEvent(event)
&& _activeCustomEvents->size() < kMaxCustomConcurrentRepeatableEvents) {
if (_activeCustomEvents->empty()) {
@ -1496,12 +1501,23 @@ void BladeRunnerEngine::handleEvents() {
&& (timeNow - _customEventRepeatTimeLast >= _customEventRepeatTimeDelay)) {
_customEventRepeatTimeLast = timeNow;
_customEventRepeatTimeDelay = kKeyRepeatSustainDelay;
uint16 aceSize = _activeCustomEvents->size();
for (ActiveCustomEventsArray::iterator it = _activeCustomEvents->begin(); it != _activeCustomEvents->end(); it++) {
// kbdRepeat field will be unused here since we emulate the kbd repeat behavior anyway,
// but maybe it's good to set it for consistency
it->kbdRepeat = true;
// reissue the custom start event
handleCustomEventStart(*it);
// This extra check is needed since it's possible that during this for loop
// within the above handleCustomEventStart() execution,
// cleanupPendingRepeatingEvents() is called
// and elements from _activeCustomEvents are removed!
// TODO This is probably an indication that this could be reworked
// as something cleaner and safer.
// Or event repetition could be handled by the keymapper code (outside the engine code)
if (aceSize != _activeCustomEvents->size()) {
break;
}
}
} else if (isAllowedRepeatedKey(_currentKeyDown)
&& (timeNow - _keyRepeatTimeLast >= _keyRepeatTimeDelay)) {
@ -1603,6 +1619,10 @@ void BladeRunnerEngine::cleanupPendingRepeatingEvents(const Common::String &keym
for (ActiveCustomEventsArray::iterator actIt = _activeCustomEvents->begin(); actIt != _activeCustomEvents->end(); ++actIt) {
if ((actIt->type != Common::EVENT_INVALID) && (actIt->customType == (*kmIt)->event.customType)) {
_activeCustomEvents->erase(actIt);
// When erasing an element from an array, erase(iterator pos)
// will return an iterator pointing to the next element in the array.
// Thus, we should check if we reached the end() here, to avoid moving
// the iterator in the next loop repetition to an invalid memory location.
if (actIt == _activeCustomEvents->end()) {
break;
}
@ -1633,13 +1653,13 @@ void BladeRunnerEngine::handleCustomEventStop(Common::Event &event) {
}
void BladeRunnerEngine::handleCustomEventStart(Common::Event &event) {
if (_vqaIsPlaying && (BladeRunnerEngineMappableAction)event.customType == kMpblActionCutsceneSkip) {
if (_vqaIsPlaying && (BladeRunnerEngineMappableAction)event.customType == kMpActionCutsceneSkip) {
_vqaStopIsRequested = true;
_vqaIsPlaying = false;
return;
}
if (_vqaStopIsRequested && (BladeRunnerEngineMappableAction)event.customType == kMpblActionCutsceneSkip) {
if (_vqaStopIsRequested && (BladeRunnerEngineMappableAction)event.customType == kMpActionCutsceneSkip) {
return;
}

View File

@ -297,10 +297,16 @@ public:
// This is because the original, when holding down right mouse button, would just toggle McCoy's mode once.
// We keep the behavior for "right mouse button".
// The continuous fast toggle behavior when holding down <SPACEBAR> feels more like a bug anyway.
// NOTE In the original, the KP_PERIOD key with NUMLOCK on, would work as a normal '.' character
// in the KIA Save Game screen. With NUMLOCK off, it would work as a delete request for the selected entry.
// However, NUMLOCK is currently not working as a modifier key for keymaps,
// so maybe we can implement the original behavior more accurately,
// when that is fixed in the keymapper or hardware-input code.
// For now, KP_PERIOD will work (by default) as a delete request.
enum BladeRunnerEngineMappableAction {
// kMpActionLeftClick, // default <left click> (select, walk-to, run-to, look-at, talk-to, use, shoot (combat mode), KIA (click on McCoy))
kMpActionToggleCombat, // default <right click> or <Spacebar>
kMpblActionCutsceneSkip, // default <Return> or <KP_Enter> or <Esc> or <Spacebar>
kMpActionCutsceneSkip, // default <Return> or <KP_Enter> or <Esc> or <Spacebar>
kMpActionDialogueSkip, // default <Return> or <KP_Enter>
kMpActionToggleKiaOptions, // default <Esc> opens/closes KIA, in Options tab
kMpActionOpenKiaDatabase, // default <Tab> - only opens KIA (if closed), in one of the database tabs (the last active one, or else the first)
@ -312,7 +318,9 @@ public:
kMpActionOpenKIATabClueDatabase, // default <F6>
kMpActionOpenKIATabQuitGame, // default <F10>
kMpActionScrollUp, // ScummVM addition (scroll list up)
kMpActionScrollDown // ScummVM addition (scroll list down)
kMpActionScrollDown, // ScummVM addition (scroll list down)
kMpConfirmDlg, // default <Return> or <KP_Enter>
kMpDeleteSelectedSvdGame // default <Delete> or <KP_Period>
};
private:

View File

@ -135,7 +135,7 @@ Common::KeymapArray BladeRunnerMetaEngine::initKeymaps(const char *target) const
// I18N: This keymap allows skipping video cutscenes
act = new Action("SKIPVIDEO", _("Skip cutscene"));
act->setCustomEngineActionEvent(BladeRunnerEngine::kMpblActionCutsceneSkip);
act->setCustomEngineActionEvent(BladeRunnerEngine::kMpActionCutsceneSkip);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("KP_ENTER");
@ -175,6 +175,31 @@ Common::KeymapArray BladeRunnerMetaEngine::initKeymaps(const char *target) const
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
gameplayKeymap->addAction(act);
// I18N: This keymap works within the KIA Save Game screen
// and allows confirming popup dialogue prompts (eg. for save game deletion or overwriting)
// and also submitting a new save game name, or choosing an existing save game for overwriting.
act = new Action("KIACONFIRMDLG", _("Confirm"));
act->setCustomEngineActionEvent(BladeRunnerEngine::kMpConfirmDlg);
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("KP_ENTER");
act->addDefaultInputMapping("JOY_B");
kiaOnlyKeymap->addAction(act);
// I18N: This keymap works within the KIA Save Game screen
// and allows submitting a selected existing save game for deletion.
act = new Action("KIADELETESVDGAME", _("Delete Selected Saved Game"));
act->setCustomEngineActionEvent(BladeRunnerEngine::kMpDeleteSelectedSvdGame);
act->addDefaultInputMapping("DELETE");
// TODO In the original KP_PERIOD with NUMLOCK on, would work as a normal '.' character.
// KP_PERIOD with NUMLOCK off, would work as a delete request for the selected saved game.
// However, NUMLOCK is currently not working as a modifier key for keymaps,
// so maybe we should implement this original behavior more accurately,
// when that is fixed in the keymapper or hardware-input code.
// For now, KP_PERIOD will work (by default) as a delete request.
act->addDefaultInputMapping("KP_PERIOD");
act->addDefaultInputMapping("JOY_X");
kiaOnlyKeymap->addAction(act);
// I18N: This keymap allows scrolling texts and lists upwards
act = new Action("KIASCROLLUP", _("Scroll Up"));
act->setCustomEngineActionEvent(BladeRunnerEngine::kMpActionScrollUp);

View File

@ -117,6 +117,10 @@ class KIA {
public:
// Indicates when KIA opens after player has died
// or the game just launched and there are existing saved games to load.
// In forced open mode, certain KIA tabs are not available,
// such as the Save Game tab and the Crime Scene, Suspect, Clue database tabs.
bool _forceOpen;
KIALog *_log;

View File

@ -225,22 +225,6 @@ void KIASectionSave::draw(Graphics::Surface &surface) {
_buttons->drawTooltip(surface, _mouseX, _mouseY);
}
bool KIASectionSave::isKeyConfirmModalDialogue(const Common::KeyState &kbd) {
if (kbd.keycode == Common::KEYCODE_RETURN || kbd.keycode == Common::KEYCODE_KP_ENTER) {
return true;
}
return false;
}
bool KIASectionSave::isKeyRequestDeleteEntry(const Common::KeyState &kbd) {
if (_selectedLineId != _newSaveLineId
&& ( kbd.keycode == Common::KEYCODE_DELETE
|| (kbd.keycode == Common::KEYCODE_KP_PERIOD && !(kbd.flags & Common::KBD_NUM)))) {
return true;
}
return false;
}
void KIASectionSave::handleKeyUp(const Common::KeyState &kbd) {
if (_state == kStateNormal) {
_uiContainer->handleKeyUp(kbd);
@ -248,19 +232,32 @@ void KIASectionSave::handleKeyUp(const Common::KeyState &kbd) {
}
void KIASectionSave::handleKeyDown(const Common::KeyState &kbd) {
if (_state == kStateNormal) {
_uiContainer->handleKeyDown(kbd);
}
}
void KIASectionSave::handleCustomEventStop(const Common::Event &evt) {
if (_state == kStateNormal) {
_uiContainer->handleCustomEventStop(evt);
}
}
void KIASectionSave::handleCustomEventStart(const Common::Event &evt) {
if (_state == kStateNormal) {
// Delete a saved game entry either with Delete key or numpad's (keypad's) Del key (when Num Lock Off)
if (isKeyRequestDeleteEntry(kbd)) {
if (_selectedLineId != _newSaveLineId
&& evt.customType == BladeRunnerEngine::BladeRunnerEngineMappableAction::kMpDeleteSelectedSvdGame) {
changeState(kStateDelete);
}
_uiContainer->handleKeyDown(kbd);
_uiContainer->handleCustomEventStart(evt);
} else if (_state == kStateOverwrite) {
if (isKeyConfirmModalDialogue(kbd)) {
if (evt.customType == BladeRunnerEngine::BladeRunnerEngineMappableAction::kMpConfirmDlg) {
save();
changeState(kStateNormal);
}
} else if (_state == kStateDelete) {
if (isKeyConfirmModalDialogue(kbd)) {
if (evt.customType == BladeRunnerEngine::BladeRunnerEngineMappableAction::kMpConfirmDlg) {
deleteSave();
changeState(kStateNormal);
}

View File

@ -83,6 +83,8 @@ public:
void handleMouseUp(bool mainButton) override;
void handleMouseScroll(int direction) override;
void handleCustomEventStart(const Common::Event &evt) override;
void handleCustomEventStop(const Common::Event &evt) override;
private:
static void scrollBoxCallback(void *callbackData, void *source, int lineData, int mouseButton);
static void inputBoxCallback(void *callbackData, void *source);
@ -93,9 +95,6 @@ private:
void changeState(State state);
void save();
void deleteSave();
bool isKeyConfirmModalDialogue(const Common::KeyState &kbd);
bool isKeyRequestDeleteEntry(const Common::KeyState &kbd);
};
} // End of namespace BladeRunner

View File

@ -24,6 +24,7 @@
namespace Common{
struct KeyState;
struct Event;
}
namespace Graphics {
@ -55,6 +56,8 @@ public:
virtual void handleMouseScroll(int direction) {} // Added by ScummVM team
virtual void handleKeyUp(const Common::KeyState &kbd) {}
virtual void handleKeyDown(const Common::KeyState &kbd) {}
virtual void handleCustomEventStop(const Common::Event &evt) {}
virtual void handleCustomEventStart(const Common::Event &evt) {}
};
} // End of namespace BladeRunner

View File

@ -128,6 +128,39 @@ void UIContainer::handleKeyDown(const Common::KeyState &kbd) {
}
}
void UIContainer::handleCustomEventStop(const Common::Event &evt) {
if (_handleSpecificNumOfTopLayers <= 0) {
for (Common::Array<UIComponent*>::iterator component = _components.begin(); component != _components.end(); ++component) {
(*component)->handleCustomEventStop(evt);
}
} else {
int countOfTopLayersToHandle = _handleSpecificNumOfTopLayers;
Common::Array<UIComponent*>::iterator component = _components.end();
do {
--component;
--countOfTopLayersToHandle;
(*component)->handleCustomEventStop(evt);
} while (component != _components.begin() && countOfTopLayersToHandle != 0);
}
}
void UIContainer::handleCustomEventStart(const Common::Event &evt) {
if (_handleSpecificNumOfTopLayers <= 0) {
for (Common::Array<UIComponent*>::iterator component = _components.begin(); component != _components.end(); ++component) {
(*component)->handleCustomEventStart(evt);
}
} else {
int countOfTopLayersToHandle = _handleSpecificNumOfTopLayers;
Common::Array<UIComponent*>::iterator component = _components.end();
do {
--component;
--countOfTopLayersToHandle;
(*component)->handleCustomEventStart(evt);
} while (component != _components.begin() && countOfTopLayersToHandle != 0);
}
}
void UIContainer::add(UIComponent *component) {
_components.push_back(component);
}

View File

@ -48,6 +48,8 @@ public:
void handleMouseScroll(int direction) override; // Added by ScummVM team
void handleKeyUp(const Common::KeyState &kbd) override;
void handleKeyDown(const Common::KeyState &kbd) override;
void handleCustomEventStop(const Common::Event &evt) override;
void handleCustomEventStart(const Common::Event &evt) override;
void add(UIComponent *component);
void clear();

View File

@ -93,15 +93,19 @@ void UIInputBox::handleKeyDown(const Common::KeyState &kbd) {
_text += kc;
} else if (kbd.keycode == Common::KEYCODE_BACKSPACE) {
_text.deleteLastChar();
} else if ((kbd.keycode == Common::KEYCODE_RETURN || kbd.keycode == Common::KEYCODE_KP_ENTER)
&& !_text.empty()) {
if (_valueChangedCallback) {
_valueChangedCallback(_callbackData, this);
}
}
}
}
void UIInputBox::handleCustomEventStart(const Common::Event &evt) {
if (_isVisible
&& evt.customType == BladeRunnerEngine::BladeRunnerEngineMappableAction::kMpConfirmDlg
&& !_text.empty()
&& _valueChangedCallback) {
_valueChangedCallback(_callbackData, this);
}
}
bool UIInputBox::getValidChar(const uint16 &kAscii16bit, uint8 &targetAscii) {
if (kAscii16bit != 0) {
// The above check for kAscii16bit > 0 gets rid of the tentative warning:

View File

@ -55,6 +55,7 @@ public:
void hide();
void handleKeyDown(const Common::KeyState &kbd) override;
void handleCustomEventStart(const Common::Event &evt) override;
private:
bool getValidChar(const uint16 &kc16bit, uint8 &kc8bit);