/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "ultima/ultima4/metaengine.h" #include "ultima/ultima4/core/debugger.h" #include "ultima/ultima4/ultima4.h" #include "common/translation.h" #include "backends/keymapper/action.h" #include "backends/keymapper/standard-actions.h" namespace Ultima { namespace Ultima4 { struct KeybindingRecord { KeybindingAction _action; const char *_id; const char *_desc; const char *_method; const char *_key; const char *_joy; }; static const KeybindingRecord NORMAL_KEYS[] = { { KEYBIND_INTERACT, "INTERACT", _s("Interact"), "interact", "RETURN", nullptr }, { KEYBIND_ESCAPE, "ESCAPE", _s("Abort action"), "", "ESCAPE", nullptr }, { KEYBIND_UP, "UP", _s("Up"), "move up", "UP", nullptr }, { KEYBIND_DOWN, "DOWN", _s("Down"), "move down", "DOWN", nullptr }, { KEYBIND_LEFT, "LEFT", _s("Left"), "move left", "LEFT", nullptr }, { KEYBIND_RIGHT, "RIGHT", _s("Right"), "move right", "RIGHT", nullptr }, { KEYBIND_ATTACK, "ATTACK", _s("Attack"), "attack", "a", nullptr }, { KEYBIND_BOARD, "BOARD", _s("Board"), "board", "b", nullptr }, { KEYBIND_CAST, "CAST", _s("Cast"), "cast", "c", nullptr }, { KEYBIND_CLIMB, "CLIMB", _s("Climb"), "climb", "k", nullptr }, { KEYBIND_DESCEND, "DESCEND", _s("Descend"), "descend", "d", nullptr }, { KEYBIND_ENTER, "ENTER", _s("Enter"), "enter", "e", nullptr }, { KEYBIND_EXIT, "EXIT", _s("Exit"), "exit", "x", nullptr }, { KEYBIND_FIRE, "FIRE", _s("Fire"), "fire", "f", nullptr }, { KEYBIND_GET, "GET", _s("Get chest"), "get", "g", nullptr }, { KEYBIND_HOLE_UP, "HOLE-UP", _s("Hole up & camp"), "camp", "h", nullptr }, // I18N: Jimmy is used to open locked doors { KEYBIND_JIMMY, "JIMMY", _s("Jimmy"), "jimmy", "j", nullptr }, { KEYBIND_IGNITE, "IGNITE", _s("Ignite"), "ignite", "i", nullptr }, { KEYBIND_LOCATE, "LOCATE", _s("Locate position"), "locate", "l", nullptr }, { KEYBIND_MIX, "MIX", _s("Mix reagents"), "mix", "m", nullptr }, { KEYBIND_NEW_ORDER, "NEW-ORDER", _s("New order"), "order", "n", nullptr }, { KEYBIND_OPEN_DOOR, "OPEN-DOOR", _s("Open door"), "open", "o", nullptr }, // I18N: Going over something carefully { KEYBIND_PASS, "PASS", _s("Pass"), "pass", "SPACE", nullptr }, // I18N: Peer is used to look through keyholes or other small openings { KEYBIND_PEER, "PEER", _s("Peer"), "peer", "p", nullptr }, { KEYBIND_QUIT_SAVE, "QUIT-SAVE", _s("Quit and save"), "quitAndSave", "q", nullptr }, { KEYBIND_READY_WEAPON, "READY-WEAPON", _s("Ready weapon"), "ready", "r", nullptr }, { KEYBIND_SEARCH, "SEARCH", _s("Search"), "search", "s", nullptr }, { KEYBIND_STATS, "STATS", _s("Stats"), "stats", "z", nullptr }, { KEYBIND_TALK, "TALK", _s("Talk"), "talk", "t", nullptr }, { KEYBIND_USE, "USE", _s("Use"), "use", "u", nullptr }, { KEYBIND_WEAR, "WEAR", _s("Wear armor"), "wear", "w", nullptr }, { KEYBIND_YELL, "YELL", _s("Yell"), "yell", "y", nullptr }, { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr } }; static const KeybindingRecord CONFIG_KEYS[] = { { KEYBIND_SPEED_UP, "SPEED-UP", _s("Speed up"), "speed up", "KP_PLUS", nullptr }, { KEYBIND_SPEED_DOWN, "SPEED-DOWN", _s("Speed down"), "speed down", "KP_MINUS", nullptr }, { KEYBIND_SPEED_NORMAL, "SPEED-NORMAL", _s("Speed normal"), "speed normal", "KP_ENTER", nullptr }, { KEYBIND_COMBATSPEED_UP, "COMBATSPEED-UP", _s("Combat speed up"), "combat_speed up", "A+KP_PLUS", nullptr }, { KEYBIND_COMBATSPEED_DOWN, "COMBATSPEED-DOWN", _s("Combat speed down"), "combat_speed down", "A+KP_MINUS", nullptr }, { KEYBIND_COMBATSPEED_NORMAL, "COMBATSPEED-NORMAL", _s("Combat speed normal"), "combat_speed normal", "A+KP_ENTER", nullptr }, { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr } }; static const KeybindingRecord PARTY_KEYS[] = { { KEYBIND_PARTY0, "PARTY0", _s("Party - None"), "party 0", "0", nullptr }, { KEYBIND_PARTY1, "PARTY1", _s("Party - Character #1"), "party 1", "1", nullptr }, { KEYBIND_PARTY2, "PARTY2", _s("Party - Character #2"), "party 2", "2", nullptr }, { KEYBIND_PARTY3, "PARTY3", _s("Party - Character #3"), "party 3", "3", nullptr }, { KEYBIND_PARTY4, "PARTY4", _s("Party - Character #4"), "party 4", "4", nullptr }, { KEYBIND_PARTY5, "PARTY5", _s("Party - Character #5"), "party 5", "5", nullptr }, { KEYBIND_PARTY6, "PARTY6", _s("Party - Character #6"), "party 6", "6", nullptr }, { KEYBIND_PARTY7, "PARTY7", _s("Party - Character #7"), "party 7", "7", nullptr }, { KEYBIND_PARTY8, "PARTY8", _s("Party - Character #8"), "party 8", "8", nullptr }, { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr } }; static const KeybindingRecord CHEAT_KEYS[] = { { KEYBIND_CHEAT_DESTROY_CREATURES, "CHEAT-DESTROY_CREATURES", _s("Destroy all creatures"), "destroy_creatures", "A+a", nullptr }, { KEYBIND_CHEAT_COLLISIONS, "CHEAT-COLLISIONS", _s("Toggle collision handling"), "collisions", "A+c", nullptr }, { KEYBIND_CHEAT_DESTROY, "CHEAT-DESTROY", _s("Destroy object"), "destroy", "A+d", nullptr }, { KEYBIND_CHEAT_EQUIPMENT, "CHEAT-EQUIPMENT", _s("Full equipment"), "equipment", "A+e", nullptr }, { KEYBIND_CHEAT_FLEE, "CHEAT_FLEE", _s("Flee combat"), "flee", "A+f", nullptr }, { KEYBIND_CHEAT_GOTO, "CHEAT-GOTO", _s("Goto location"), "goto", "A+g", nullptr }, { KEYBIND_CHEAT_HELP, "CHEAT-HELP", _s("Help - Teleport to Lord British"), "goto", "A+h", nullptr }, { KEYBIND_CHEAT_ITEMS, "CHEAT-ITEMS", _s("Give items"), "items", "A+i", nullptr }, { KEYBIND_CHEAT_KARMA, "CHEAT-KARMA", _s("List karma"), "karma", "A+k", nullptr }, { KEYBIND_CHEAT_LEAVE, "CHEAT-LEAVE", _s("Leave location"), "leave", "A+l", nullptr }, { KEYBIND_CHEAT_MIXTURES, "CHEAT-MIXTURES", _s("Give mixtures"), "mixtures", "A+m", nullptr }, { KEYBIND_CHEAT_NO_COMBAT, "CHEAT-NOCOMBAT", _s("Combat encounters"), "combat", "A+n", nullptr }, { KEYBIND_CHEAT_OVERHEAD, "CHEAT_OVERHEAD", _s("Toggle overhead view"), "overhead", "A+o", nullptr }, { KEYBIND_CHEAT_PARTY, "CHEAT-PARTY", _s("Full party"), "companions", "A+p", nullptr }, { KEYBIND_CHEAT_REAGENTS, "CHEAT-REAGENTS", _s("Give reagents"), "reagents", "A+r", nullptr }, { KEYBIND_CHEAT_STATS, "CHEAT-STATS", _s("Full stats"), "fullstats", "A+s", nullptr }, { KEYBIND_CHEAT_TRANSPORT, "CHEAT-TRANSPORT", _s("Create transport"), "transport", "A+t", nullptr }, { KEYBIND_CHEAT_UP, "CHEAT-UP", _s("Up level"), "up", "A+UP", nullptr }, { KEYBIND_CHEAT_DOWN, "CHEAT-DOWN", _s("Down level"), "down", "A+DOWN", nullptr }, { KEYBIND_CHEAT_VIRTUE, "CHEAT-VIRTUE", _s("Grant virtue"), "virtue", "A+v", nullptr }, { KEYBIND_CHEAT_WIND, "CHEAT-WIND", _s("Change wind"), "wind", "A+w", nullptr }, { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr } }; static const KeybindingRecord INPUT_KEYS[] = { { KEYBIND_ESCAPE, "ESCAPE", _s("Abort action"), "", "ESCAPE", nullptr }, { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr } }; static const KeybindingRecord DIRECTION_KEYS[] = { { KEYBIND_ESCAPE, "ESCAPE", _s("Abort action"), nullptr, "ESCAPE", nullptr }, { KEYBIND_UP, "UP", _s("Up"), nullptr, "UP", nullptr }, { KEYBIND_DOWN, "DOWN", _s("Down"), nullptr, "DOWN", nullptr }, { KEYBIND_LEFT, "LEFT", _s("Left"), nullptr, "LEFT", nullptr }, { KEYBIND_RIGHT, "RIGHT", _s("Right"), nullptr, "RIGHT", nullptr }, { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr } }; static const KeybindingRecord MENU_KEYS[] = { { KEYBIND_INTERACT, "INTERACT", _s("Interact"), "interact", "RETURN", nullptr }, { KEYBIND_ESCAPE, "ESCAPE", _s("Abort action"), nullptr, "ESCAPE", nullptr }, { KEYBIND_UP, "UP", _s("Up"), nullptr, "UP", nullptr }, { KEYBIND_DOWN, "DOWN", _s("Down"), nullptr, "DOWN", nullptr }, { KEYBIND_LEFT, "LEFT", _s("Left"), nullptr, "LEFT", nullptr }, { KEYBIND_RIGHT, "RIGHT", _s("Right"), nullptr, "RIGHT", nullptr }, { KEYBIND_NONE, nullptr, nullptr, nullptr, nullptr, nullptr } }; struct KeysRecord { const char *_id; const char *_desc; const KeybindingRecord *_keys; }; static const KeysRecord NORMAL_RECORDS[] = { { "ultima4", "Ultima IV", NORMAL_KEYS }, { "ultima4_config", "Ultima IV - Configuration", CONFIG_KEYS }, { "ultima4_party", "Ultima IV - Party", PARTY_KEYS }, { "ultima4_cheats", "Ultima IV - Cheats", CHEAT_KEYS }, { nullptr, nullptr, nullptr } }; static const KeysRecord INPUT_RECORDS[] = { { "ultima4", "Ultima IV", INPUT_KEYS }, { nullptr, nullptr, nullptr } }; static const KeysRecord DIRECTION_RECORDS[] = { { "ultima4", "Ultima IV", DIRECTION_KEYS }, { nullptr, nullptr, nullptr } }; static const KeysRecord MENU_RECORDS[] = { { "ultima4", "Ultima IV", MENU_KEYS }, { nullptr, nullptr, nullptr } }; static const KeysRecord *MODE_RECORDS[5] = { NORMAL_RECORDS, INPUT_RECORDS, DIRECTION_RECORDS, MENU_RECORDS, NORMAL_RECORDS }; Common::KeymapArray MetaEngine::initKeymaps(KeybindingMode mode) { Common::KeymapArray keymapArray; Common::Keymap *keyMap; Common::Action *act; const KeysRecord *recPtr = MODE_RECORDS[mode]; for (int kCtr = 0; recPtr->_id; ++recPtr, ++kCtr) { // Core keymaps keyMap = new Common::Keymap(Common::Keymap::kKeymapTypeGame, recPtr->_id, recPtr->_desc); keymapArray.push_back(keyMap); if (kCtr == 0) { addMouseClickActions(*keyMap); } for (const KeybindingRecord *r = recPtr->_keys; r->_id; ++r) { act = new Common::Action(r->_id, _(r->_desc)); act->setCustomEngineActionEvent(r->_action); act->addDefaultInputMapping(r->_key); if (r->_joy) act->addDefaultInputMapping(r->_joy); if (r->_action == KEYBIND_UP || r->_action == KEYBIND_DOWN || r->_action == KEYBIND_LEFT || r->_action == KEYBIND_RIGHT) // Allow movement actions to be triggered on keyboard repeats act->allowKbdRepeats(); keyMap->addAction(act); } } return keymapArray; } void MetaEngine::addMouseClickActions(Common::Keymap &keyMap) { Common::Action *act; act = new Common::Action(Common::kStandardActionLeftClick, _("Left click")); act->setLeftClickEvent(); act->addDefaultInputMapping("MOUSE_LEFT"); act->addDefaultInputMapping("JOY_A"); keyMap.addAction(act); act = new Common::Action(Common::kStandardActionRightClick, _("Right click")); act->setRightClickEvent(); act->addDefaultInputMapping("MOUSE_RIGHT"); act->addDefaultInputMapping("JOY_B"); keyMap.addAction(act); } void MetaEngine::setKeybindingMode(KeybindingMode mode) { Common::Keymapper *const mapper = g_engine->getEventManager()->getKeymapper(); mapper->cleanupGameKeymaps(); Common::KeymapArray arr = initKeymaps(mode); for (uint idx = 0; idx < arr.size(); ++idx) mapper->addGameKeymap(arr[idx]); } void MetaEngine::executeAction(KeybindingAction keyAction) { Common::String methodName = getMethod(keyAction); if (!methodName.empty()) g_debugger->executeCommand(methodName); } Common::String MetaEngine::getMethod(KeybindingAction keyAction) { for (int kCtr = 0; kCtr < 4; ++kCtr) { for (const KeybindingRecord *r = NORMAL_RECORDS[kCtr]._keys; r->_id; ++r) { if (r->_action == keyAction) return r->_method; } } return Common::String(); } } // End of namespace Ultima8 } // End of namespace Ultima