TWINE: started to split keymaps for ui, game and cutscenes

This commit is contained in:
Martin Gerhardy 2020-10-23 20:09:33 +02:00 committed by Eugene Sandulenko
parent c59fd6a32e
commit d417478b8c
11 changed files with 432 additions and 249 deletions

View file

@ -409,7 +409,7 @@ int32 Debug::debugProcessButton(int32 X, int32 Y) {
void Debug::debugPlasmaWindow(const char *text, int32 color) {
int32 textSize;
_engine->_menu->processPlasmaEffect(5, color);
_engine->_menu->processPlasmaEffect(0, 5, SCREEN_WIDTH, color);
if (!(_engine->getRandomNumber() % 5)) {
_engine->_menu->plasmaEffectPtr[_engine->getRandomNumber() % 320 * 10 + 6400] = 255;
}

View file

@ -274,7 +274,13 @@ void FlaMovies::playFlaMovie(const char *flaName) {
if (!strcmp((const char *)flaHeaderData.version, "V1.3")) {
int32 currentFrame = 0;
ScopedKeyMap scopedKeyMap(_engine, cutsceneKeyMapId);
do {
_engine->readKeys();
if (_engine->shouldQuit()) {
break;
}
if (currentFrame == flaHeaderData.numOfFrames) {
break;
}
@ -303,17 +309,7 @@ void FlaMovies::playFlaMovie(const char *flaName) {
currentFrame++;
_engine->_system->delayMillis(1000 / flaHeaderData.speed + 1);
_engine->readKeys();
if (_engine->shouldQuit()) {
break;
}
if (_engine->_input->isAnyKeyPressed()) {
break;
}
} while (true);
} while (!_engine->_input->isActionActive(TwinEActionType::CutsceneAbort));
}
if (_engine->cfgfile.CrossFade) {

View file

@ -21,11 +21,19 @@
*/
#include "twine/input.h"
#include "backends/keymapper/keymapper.h"
#include "common/events.h"
#include "common/keyboard.h"
#include "common/system.h"
#include "twine/actor.h"
#include "twine/twine.h"
namespace TwinE {
const char *mainKeyMapId = "mainKeyMap";
const char *uiKeyMapId = "uiKeyMap";
const char *cutsceneKeyMapId = "cutsceneKeyMap";
/** Pressed key char map - scanCodeTab2 */
static const struct KeyProperties {
uint8 high;
@ -65,22 +73,62 @@ static const struct KeyProperties {
{0x00, false, 0x00}};
static_assert(ARRAYSIZE(pressedKeyCharMap) == 31, "Expected size of key char map");
Input::Input(TwinEEngine *engine) : _engine(engine) {}
bool Input::isAnyKeyPressed() const {
return internalKeyCode != 0;
ScopedKeyMapperDisable::ScopedKeyMapperDisable() {
g_system->getEventManager()->getKeymapper()->setEnabled(false);
}
bool Input::isPressed(Common::KeyCode keycode) const {
return false; // TODO:
ScopedKeyMapperDisable::~ScopedKeyMapperDisable() {
g_system->getEventManager()->getKeymapper()->setEnabled(true);
}
ScopedKeyMap::ScopedKeyMap(TwinEEngine* engine, const char *id) : _engine(engine) {
_prevKeyMap = _engine->_input->currentKeyMap();
_engine->_input->enabledKeyMap(cutsceneKeyMapId);
}
ScopedKeyMap::~ScopedKeyMap() {
_engine->_input->enabledKeyMap(_prevKeyMap.c_str());
}
Input::Input(TwinEEngine *engine) : _engine(engine) {}
bool Input::isPressed(Common::KeyCode keycode, bool onlyFirstTime) const {
if (onlyFirstTime) {
return _pressed[keycode] == 1;
}
return _pressed[keycode] > 0;
}
bool Input::isActionActive(TwinEActionType actionType, bool onlyFirstTime) const {
if (onlyFirstTime) {
return actionStates[actionType] == 1;
}
return actionStates[actionType] > 0;
}
bool Input::toggleActionIfActive(TwinEActionType actionType) {
if (actionStates[actionType] > 0) {
actionStates[actionType] = 0;
return true;
}
return false;
}
bool Input::isQuickBehaviourActionActive() const {
return isActionActive(TwinEActionType::QuickBehaviourNormal) || isActionActive(TwinEActionType::QuickBehaviourAthletic) || isActionActive(TwinEActionType::QuickBehaviourAggressive) || isActionActive(TwinEActionType::QuickBehaviourDiscreet);
}
void Input::enabledKeyMap(const char *id) {
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
const Common::KeymapArray &keymaps = keymapper->getKeymaps();
for (Common::Keymap *keymap : keymaps) {
keymap->setEnabled(keymap->getId() == id);
}
_currentKeyMap = id;
}
void Input::readKeys() {
if (_engine->shouldQuit()) {
internalKeyCode = 1;
skippedKey = 1;
return;
}
++_tickCounter;
skippedKey = 0;
internalKeyCode = 0;
@ -89,7 +137,7 @@ void Input::readKeys() {
uint8 localKey = 0;
switch (event.type) {
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
actionStates[event.customType] = false;
actionStates[event.customType] = 0;
localKey = twineactions[event.customType].localKey;
break;
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
@ -103,29 +151,25 @@ void Input::readKeys() {
break;
default:
localKey = twineactions[event.customType].localKey;
actionStates[event.customType] = true;
debug("repeat: %i", event.kbdRepeat);
actionStates[event.customType] = 1 + event.kbdRepeat;
break;
}
} else {
localKey = twineactions[event.customType].localKey;
actionStates[event.customType] = true;
debug("repeat: %i", event.kbdRepeat);
actionStates[event.customType] = 1 + event.kbdRepeat;
}
break;
case Common::EVENT_LBUTTONDOWN:
leftMouse = 1;
break;
case Common::EVENT_KEYDOWN: {
if (event.kbd.keycode == Common::KeyCode::KEYCODE_RETURN || event.kbd.keycode == Common::KeyCode::KEYCODE_KP_ENTER) {
_hitEnter = true;
}
case Common::EVENT_KEYDOWN:
_pressed[event.kbd.keycode] = 1 + event.kbdRepeat;
break;
}
case Common::EVENT_KEYUP: {
if (event.kbd.keycode == Common::KeyCode::KEYCODE_RETURN || event.kbd.keycode == Common::KeyCode::KEYCODE_KP_ENTER) {
_hitEnter = false;
}
case Common::EVENT_KEYUP:
_pressed[event.kbd.keycode] = 0;
break;
}
case Common::EVENT_RBUTTONDOWN:
rightMouse = 1;
break;

View file

@ -29,6 +29,12 @@
namespace TwinE {
class TwinEEngine;
extern const char *mainKeyMapId;
extern const char *uiKeyMapId;
extern const char *cutsceneKeyMapId;
enum TwinEActionType {
Pause,
NextRoom,
@ -61,9 +67,19 @@ enum TwinEActionType {
Escape,
PageUp,
UIEnter,
UIAbort,
UILeft,
UIRight,
UIUp,
UIDown,
CutsceneAbort,
Max
};
// TODO: get rid of this table
static constexpr const struct ActionMapping {
TwinEActionType action;
uint8 localKey;
@ -97,8 +113,14 @@ static constexpr const struct ActionMapping {
{InventoryMenu, 0x36},
{SpecialAction, 0x11},
{Escape, 0x01},
{PageUp, 0x49} // TODO: used for what?
};
{PageUp, 0x49}, // TODO: used for what?
{UIEnter, 0x00},
{UIAbort, 0x00},
{UILeft, 0x00},
{UIRight, 0x00},
{UIUp, 0x00},
{UIDown, 0x00},
{CutsceneAbort, 0x00}};
static_assert(ARRAYSIZE(twineactions) == TwinEActionType::Max, "Unexpected action mapping array size");
@ -109,17 +131,31 @@ struct MouseStatusStruct {
int32 y = 0;
};
class TwinEEngine;
struct ScopedKeyMapperDisable {
ScopedKeyMapperDisable();
~ScopedKeyMapperDisable();
};
class ScopedKeyMap {
private:
TwinEEngine* _engine;
Common::String _prevKeyMap;
public:
ScopedKeyMap(TwinEEngine* engine, const char *id);
~ScopedKeyMap();
};
class Input {
private:
TwinEEngine *_engine;
bool _hitEnter = false;
int _tickCounter = 0;
uint8 _pressed[Common::KEYCODE_LAST]{0};
Common::String _currentKeyMap;
public:
Input(TwinEEngine *engine);
bool actionStates[TwinEActionType::Max]{false};
uint8 actionStates[TwinEActionType::Max]{false};
int16 skippedKey = 0;
int16 pressedKey = 0;
int16 internalKeyCode = 0;
@ -130,14 +166,45 @@ public:
int16 leftMouse = 0;
int16 rightMouse = 0;
bool isAnyKeyPressed() const;
/**
* @brief Dependent on the context we are currently in the game, we might want to disable certain keymaps.
* Like disabling ui keymaps when we are in-game - or vice versa.
*/
void enabledKeyMap(const char *id);
bool isPressed(Common::KeyCode keycode) const;
const Common::String currentKeyMap() const;
inline bool isPressedEnter() const {
return isPressed(Common::KEYCODE_RETURN) || isPressed(Common::KEYCODE_KP_ENTER);
/**
* @param onlyFirstTime If this is set to @c true, repeating key press events are not taken into account here
* This means, that even if the key is held down, this will return @c false. @c false as value for this parameter
* will return @c true also for repeating key presses.
*
* @sa isPressed()
*/
bool isActionActive(TwinEActionType actionType, bool onlyFirstTime = true) const;
/**
* @brief If the action is active, the internal state is reset and a following call of this method won't return
* @c true anymore
*/
bool toggleActionIfActive(TwinEActionType actionType);
/**
* @param onlyFirstTime If this is set to @c true, repeating key press events are not taken into account here
* This means, that even if the key is held down, this will return @c false. @c false as value for this parameter
* will return @c true also for repeating key presses.
*
* @note You won't receive any pressed events if you have that key bound to a @c TwinEActionType value.
* @sa isActionActive()
*/
bool isPressed(Common::KeyCode keycode, bool onlyFirstTime = true) const;
inline bool isPressedEnter(bool onlyFirstTime = true) const {
return isPressed(Common::KEYCODE_RETURN, onlyFirstTime) || isPressed(Common::KEYCODE_KP_ENTER, onlyFirstTime);
}
bool isQuickBehaviourActionActive() const;
/**
* Gets mouse positions
* @param mouseData structure that contains mouse position info
@ -147,6 +214,10 @@ public:
void readKeys();
};
inline const Common::String Input::currentKeyMap() const {
return _currentKeyMap;
}
} // namespace TwinE
#endif

View file

@ -34,8 +34,8 @@
#include "twine/gamestate.h"
#include "twine/grid.h"
#include "twine/hqrdepack.h"
#include "twine/interface.h"
#include "twine/input.h"
#include "twine/interface.h"
#include "twine/menuoptions.h"
#include "twine/movements.h"
#include "twine/music.h"
@ -281,13 +281,13 @@ void Menu::plasmaEffectRenderFrame() {
*(dest++) = *(src++);
}
void Menu::processPlasmaEffect(int32 top, int32 color) {
void Menu::processPlasmaEffect(int32 left, int32 top, int32 right, int32 color) {
const int32 max_value = color + 15;
plasmaEffectRenderFrame();
const uint8 *in = plasmaEffectPtr + 5 * PLASMA_WIDTH;
uint8 *out = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top];
uint8 *out = (uint8 *)_engine->frontVideoBuffer.getPixels() + _engine->screenLookupTable[top] + left;
for (int32 i = 0; i < 25; i++) {
for (int32 j = 0; j < kMainMenuButtonWidth; j++) {
@ -348,13 +348,13 @@ void Menu::drawButtonGfx(int32 width, int32 topheight, int32 buttonId, int32 tex
}
};
processPlasmaEffect(top, 80);
processPlasmaEffect(left, top, right, 80);
if (!(_engine->getRandomNumber() % 5)) {
plasmaEffectPtr[_engine->getRandomNumber() % 140 * 10 + 1900] = 255;
}
_engine->_interface->drawSplittedBox(newWidth, top, right, bottom, 68);
} else {
processPlasmaEffect(top, 64);
processPlasmaEffect(left, top, right, 64);
if (!(_engine->getRandomNumber() % 5)) {
plasmaEffectPtr[_engine->getRandomNumber() % 320 * 10 + 6400] = 255;
}
@ -431,21 +431,20 @@ int32 Menu::processMenu(int16 *menuSettings) {
const int32 numEntry = menuSettings[MenuSettings_NumberOfButtons];
int32 maxButton = numEntry - 1;
_engine->_input->enabledKeyMap(uiKeyMapId);
_engine->_screens->loadMenuImage(false);
do {
_engine->readKeys();
_engine->_input->key = _engine->_input->pressedKey;
if (_engine->_input->isPressed(Common::KeyCode::KEYCODE_DOWN)) { // on arrow key down
debug("pressed down");
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown)) {
currentButton++;
if (currentButton == numEntry) { // if current button is the last, than next button is the first
currentButton = 0;
}
buttonsNeedRedraw = true;
}
if (((uint8)_engine->_input->key & 1)) { // on arrow key up
debug("pressed up");
} else if (_engine->_input->toggleActionIfActive(TwinEActionType::UIUp)) {
currentButton--;
if (currentButton < 0) { // if current button is the first, than previous button is the last
currentButton = maxButton;
@ -461,10 +460,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
switch (id) {
case kMusicVolume: {
int volume = mixer->getVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType);
if (((uint8)_engine->_input->key & 4)) { // on arrow key left
if (_engine->_input->isActionActive(TwinEActionType::UILeft)) {
volume -= 4;
}
if (((uint8)_engine->_input->key & 8)) { // on arrow key right
if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
volume += 4;
}
_engine->_music->musicVolume(volume);
@ -472,10 +471,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
}
case kSoundVolume: {
int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSFXSoundType);
if (((uint8)_engine->_input->key & 4)) { // on arrow key left
if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
volume -= 4;
}
if (((uint8)_engine->_input->key & 8)) { // on arrow key right
if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
volume += 4;
}
mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
@ -483,10 +482,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
}
case kCDVolume: {
AudioCDManager::Status status = _engine->_system->getAudioCDManager()->getStatus();
if (((uint8)_engine->_input->key & 4)) { // on arrow key left
if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
status.volume -= 4;
}
if (((uint8)_engine->_input->key & 8)) { // on arrow key right
if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
status.volume += 4;
}
_engine->_system->getAudioCDManager()->setVolume(status.volume);
@ -494,10 +493,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
}
case kLineVolume: {
int volume = mixer->getVolumeForSoundType(Audio::Mixer::kSpeechSoundType);
if (((uint8)_engine->_input->key & 4)) { // on arrow key left
if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
volume -= 4;
}
if (((uint8)_engine->_input->key & 8)) { // on arrow key right
if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
volume += 4;
}
mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
@ -505,10 +504,10 @@ int32 Menu::processMenu(int16 *menuSettings) {
}
case kMasterVolume: {
int volume = mixer->getVolumeForSoundType(Audio::Mixer::kPlainSoundType);
if (((uint8)_engine->_input->key & 4)) { // on arrow key left
if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UILeft))) { // on arrow key left
volume -= 4;
}
if (((uint8)_engine->_input->key & 8)) { // on arrow key right
if (((uint8)_engine->_input->toggleActionIfActive(TwinEActionType::UIRight))) { // on arrow key right
volume += 4;
}
mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
@ -532,7 +531,7 @@ int32 Menu::processMenu(int16 *menuSettings) {
if (musicChanged) {
// TODO: update volume settings
}
} while (!(_engine->_input->skippedKey & 2) && !(_engine->_input->skippedKey & 1));
} while (!_engine->_input->toggleActionIfActive(TwinEActionType::UIEnter));
currentButton = *(menuSettings + MenuSettings_FirstButton + currentButton * 2); // get current browsed button
@ -872,20 +871,18 @@ void Menu::processBehaviourMenu() {
_engine->_animations->setAnimAtKeyframe(behaviourAnimState[_engine->_actor->heroBehaviour], _engine->_animations->animTable[_engine->_actor->heroAnimIdx[_engine->_actor->heroBehaviour]], behaviourEntity, &behaviourAnimData[_engine->_actor->heroBehaviour]);
_engine->readKeys();
int32 tmpTime = _engine->lbaTime;
while (_engine->_input->skippedKey & 4 || (_engine->_input->internalKeyCode >= twineactions[TwinEActionType::QuickBehaviourNormal].localKey && _engine->_input->internalKeyCode <= twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey)) {
while (_engine->_input->isActionActive(TwinEActionType::BehaviourMenu) || _engine->_input->isQuickBehaviourActionActive()) {
_engine->readKeys();
_engine->_input->key = _engine->_input->pressedKey;
int heroBehaviour = (int)_engine->_actor->heroBehaviour;
if (_engine->_input->key & 8) {
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
heroBehaviour++;
}
if (_engine->_input->key & 4) {
if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
heroBehaviour--;
}
@ -965,14 +962,12 @@ void Menu::drawItem(int32 item) {
}
void Menu::drawInventoryItems() {
int32 item;
_engine->_interface->drawTransparentBox(17, 10, 622, 320, 4);
drawBox(17, 10, 622, 320);
drawMagicItemsBox(110, 18, 188, 311, 75);
_engine->copyBlockPhys(17, 10, 622, 320);
for (item = 0; item < NUM_INVENTORY_ITEMS; item++) {
for (int32 item = 0; item < NUM_INVENTORY_ITEMS; item++) {
drawItem(item);
}
}
@ -1002,7 +997,7 @@ void Menu::processInventoryMenu() {
_engine->_text->setFontCrossColor(4);
_engine->_text->initDialogueBox();
while (_engine->_input->internalKeyCode != 1) {
while (_engine->_input->isActionActive(TwinEActionType::InventoryMenu)) {
_engine->readKeys();
int32 prevSelectedItem = inventorySelectedItem;
@ -1026,7 +1021,7 @@ void Menu::processInventoryMenu() {
if (_engine->loopCurrentKey == 1 || _engine->loopPressedKey & 0x20)
break;
if (_engine->_input->key & 2) { // down
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIDown)) {
inventorySelectedItem++;
if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
inventorySelectedItem = 0;
@ -1035,7 +1030,7 @@ void Menu::processInventoryMenu() {
bx = 3;
}
if (_engine->_input->key & 1) { // up
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIUp)) {
inventorySelectedItem--;
if (inventorySelectedItem < 0) {
inventorySelectedItem = NUM_INVENTORY_ITEMS - 1;
@ -1044,7 +1039,7 @@ void Menu::processInventoryMenu() {
bx = 3;
}
if (_engine->_input->key & 4) { // left
if (_engine->_input->toggleActionIfActive(TwinEActionType::UILeft)) {
inventorySelectedItem -= 4;
if (inventorySelectedItem < 0) {
inventorySelectedItem += NUM_INVENTORY_ITEMS;
@ -1053,7 +1048,7 @@ void Menu::processInventoryMenu() {
bx = 3;
}
if (_engine->_input->key & 8) { // right
if (_engine->_input->toggleActionIfActive(TwinEActionType::UIRight)) {
inventorySelectedItem += 4;
if (inventorySelectedItem >= NUM_INVENTORY_ITEMS) {
inventorySelectedItem -= NUM_INVENTORY_ITEMS;

View file

@ -115,7 +115,7 @@ public:
* @param top top height where the effect will be draw in the front buffer
* @param color plasma effect start color
*/
void processPlasmaEffect(int32 top, int32 color);
void processPlasmaEffect(int32 left, int32 top, int32 right, int32 color);
/**
* Draw the entire button box

View file

@ -21,11 +21,11 @@
*/
#include "twine/menuoptions.h"
#include "common/keyboard.h"
#include "common/system.h"
#include "twine/flamovies.h"
#include "twine/gamestate.h"
#include "twine/interface.h"
#include "twine/input.h"
#include "twine/interface.h"
#include "twine/menu.h"
#include "twine/music.h"
#include "twine/resources.h"
@ -138,7 +138,7 @@ void MenuOptions::drawSelectableCharacter(int32 x, int32 y, int32 arg) {
if (arg != 0) {
_engine->_interface->drawSplittedBox(left, top, right, bottom, 91);
} else {
_engine->_interface->blitBox(left, top, right, bottom, (const int8*)_engine->workVideoBuffer.getPixels(), left, top, (int8*)_engine->frontVideoBuffer.getPixels());
_engine->_interface->blitBox(left, top, right, bottom, (const int8 *)_engine->workVideoBuffer.getPixels(), left, top, (int8 *)_engine->frontVideoBuffer.getPixels());
right2 = right;
_engine->_interface->drawTransparentBox(left, top, right2, bottom, 4);
}
@ -162,19 +162,20 @@ void MenuOptions::drawSelectableCharacters() {
// 0001F18C
void MenuOptions::drawPlayerName(int32 centerx, int32 top, int32 type) {
if (type == 1) {
_engine->_menu->processPlasmaEffect(top, 1);
}
const int left = _engine->_text->dialTextBoxLeft;
const int right = _engine->_text->dialTextBoxRight;
if (type == 1) {
_engine->_menu->processPlasmaEffect(left, top, right, 1);
}
const int bottom = _engine->_text->dialTextBoxBottom;
_engine->_menu->drawBox(left, top, right, bottom);
_engine->_interface->drawTransparentBox(left + 1, top + 1, right - 1, bottom - 1, 3);
_engine->_text->drawText(centerx - _engine->_text->getTextSize(playerName) / 2, top, playerName);
_engine->copyBlockPhys(left, top, right, bottom);
_engine->flip();
// TODO: _engine->copyBlockPhys(left, top, right, bottom);
}
int32 MenuOptions::enterPlayerName(int32 textIdx) {
@ -191,18 +192,35 @@ int32 MenuOptions::enterPlayerName(int32 textIdx) {
_engine->copyBlockPhys(0, 0, SCREEN_WIDTH - 1, 99);
drawPlayerName(halfScreenWidth, 100, 1);
drawSelectableCharacters();
_engine->flip();
do {
_engine->readKeys();
// we don't want custom events here - as we are entering the player name
ScopedKeyMapperDisable scopedKeyMapperDisable;
for (;;) {
Common::Event event;
while (g_system->getEventManager()->pollEvent(event)) {
if (event.type == Common::EVENT_KEYDOWN) {
if (event.kbd.keycode == Common::KEYCODE_KP_ENTER || event.kbd.keycode == Common::KEYCODE_RETURN) {
return 1;
}
const size_t size = strlen(playerName);
if (size >= sizeof(playerName) - 1) {
return 1;
}
playerName[size] = event.kbd.ascii;
playerName[size + 1] = '\0';
debug("name: %s", playerName);
drawPlayerName(halfScreenWidth, 100, 1);
_engine->flip();
}
}
if (_engine->shouldQuit()) {
break;
}
} while (_engine->_input->isPressedEnter());
_engine->_system->delayMillis(1);
};
}
_engine->_screens->copyScreen(_engine->workVideoBuffer, _engine->frontVideoBuffer);
_engine->flip();
return 1;
}

View file

@ -44,7 +44,7 @@ public:
int32 canShowCredits = 0;
char playerName[256] = "";
char playerName[32] = "";
/** Main menu new game options */
void newGameMenu();

View file

@ -56,177 +56,231 @@ public:
Common::KeymapArray TwinEMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "twine", "Little Big Adventure");
Action *act;
KeymapArray array(3);
{
Keymap *gameKeyMap = new Keymap(Keymap::kKeymapTypeGame, mainKeyMapId, "Little Big Adventure");
act = new Action("PAUSE", _("Pause"));
act->setCustomEngineActionEvent(TwinEActionType::Pause);
act->addDefaultInputMapping("p");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("NEXTROOM", _("Debug Next Room"));
act->setCustomEngineActionEvent(TwinEActionType::NextRoom);
act->addDefaultInputMapping("r");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("PREVIOUSROOM", _("Debug Previous Room"));
act->setCustomEngineActionEvent(TwinEActionType::PreviousRoom);
act->addDefaultInputMapping("f");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("APPLYCELLINGGRID", _("Debug Apply Celling Grid"));
act->setCustomEngineActionEvent(TwinEActionType::ApplyCellingGrid);
act->addDefaultInputMapping("t");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("INCREASECELLINGGRIDINDEX", _("Debug Increase Celling Grid Index"));
act->setCustomEngineActionEvent(TwinEActionType::IncreaseCellingGridIndex);
act->addDefaultInputMapping("g");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("DECREASECELLINGGRIDINDEX", _("Debug Decrease Celling Grid Index"));
act->setCustomEngineActionEvent(TwinEActionType::DecreaseCellingGridIndex);
act->addDefaultInputMapping("b");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("DEBUGGRIDCAMERAPRESSUP", _("Debug Grid Camera Up"));
act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressUp);
act->addDefaultInputMapping("s");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("DEBUGGRIDCAMERAPRESSDOWN", _("Debug Grid Camera Down"));
act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressDown);
act->addDefaultInputMapping("x");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("DEBUGGRIDCAMERAPRESSLEFT", _("Debug Grid Camera Left"));
act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressLeft);
act->addDefaultInputMapping("y");
act->addDefaultInputMapping("z");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("DEBUGGRIDCAMERAPRESSRIGHT", _("Debug Grid Camera Right"));
act->setCustomEngineActionEvent(TwinEActionType::DebugGridCameraPressRight);
act->addDefaultInputMapping("c");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("NORMALBEHAVIOUR", _("Normal Behaviour"));
act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourNormal);
act->addDefaultInputMapping("F1");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("ATHLETICBEHAVIOUR", _("Athletic Behaviour"));
act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourAthletic);
act->addDefaultInputMapping("F2");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("AGGRESSIVEBEHAVIOUR", _("Aggressive Behaviour"));
act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourAggressive);
act->addDefaultInputMapping("F3");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("DISCREETBEHAVIOUR", _("Discreet Behaviour"));
act->setCustomEngineActionEvent(TwinEActionType::QuickBehaviourDiscreet);
act->addDefaultInputMapping("F4");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("BEHAVIOURACTION", _("Behaviour Action"));
act->setCustomEngineActionEvent(TwinEActionType::ExecuteBehaviourAction);
act->addDefaultInputMapping("SPACE");
act->addDefaultInputMapping("JOY_A");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("CHANGEBEHAVIOUR", _("Change Behaviour"));
act->setCustomEngineActionEvent(TwinEActionType::BehaviourMenu);
act->addDefaultInputMapping("CTRL");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("OPTIONSMENU", _("Options Menu"));
act->setCustomEngineActionEvent(TwinEActionType::OptionsMenu);
act->addDefaultInputMapping("F6");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("CENTER", _("Center"));
act->setCustomEngineActionEvent(TwinEActionType::RecenterScreenOnTwinsen);
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("KP_ENTER");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("USESELECTEDOBJECT", _("Use Selected Object"));
act->setCustomEngineActionEvent(TwinEActionType::UseSelectedObject);
act->addDefaultInputMapping("SHIFT+RETURN");
act->addDefaultInputMapping("SHIFT+KP_ENTER");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("THROWMAGICBALL", _("Throw Magic Ball"));
act->setCustomEngineActionEvent(TwinEActionType::ThrowMagicBall);
act->addDefaultInputMapping("ALT");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("MOVEFORWARD", _("Move Forward"));
act->setCustomEngineActionEvent(TwinEActionType::MoveForward);
act->addDefaultInputMapping("UP");
act->addDefaultInputMapping("KP8");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("MOVEBACKWARD", _("Move Backward"));
act->setCustomEngineActionEvent(TwinEActionType::MoveBackward);
act->addDefaultInputMapping("DOWN");
act->addDefaultInputMapping("KP2");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("TurnRight", _("Turn Right"));
act = new Action("TURNRIGHT", _("Turn Right"));
act->setCustomEngineActionEvent(TwinEActionType::TurnRight);
act->addDefaultInputMapping("RIGHT");
act->addDefaultInputMapping("KP6");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("TurnLeft", _("Turn Left"));
act = new Action("TURNLEFT", _("Turn Left"));
act->setCustomEngineActionEvent(TwinEActionType::TurnLeft);
act->addDefaultInputMapping("LEFT");
act->addDefaultInputMapping("KP4");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("USEPROTOPACK", _("Use Protopack"));
act->setCustomEngineActionEvent(TwinEActionType::UseProtoPack);
act->addDefaultInputMapping("j");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("OPENHOLOMAP", _("Open Holomap"));
act->setCustomEngineActionEvent(TwinEActionType::OpenHolomap);
act->addDefaultInputMapping("h");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("INVENTORY", _("Inventory"));
act->setCustomEngineActionEvent(TwinEActionType::InventoryMenu);
act->addDefaultInputMapping("LSHIFT");
act->addDefaultInputMapping("RSHIFT");
act->addDefaultInputMapping("i");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("SPECIALACTION", _("Special Action"));
act->setCustomEngineActionEvent(TwinEActionType::SpecialAction);
act->addDefaultInputMapping("w");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("ESCAPE", _("Escape"));
act->setCustomEngineActionEvent(TwinEActionType::Escape);
act->addDefaultInputMapping("ESCAPE");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
act = new Action("PAGEUP", _("Page Up"));
act->setCustomEngineActionEvent(TwinEActionType::PageUp);
act->addDefaultInputMapping("PAGEUP");
engineKeyMap->addAction(act);
gameKeyMap->addAction(act);
const int delta = (int)TwinEActionType::Max - (int)engineKeyMap->getActions().size();
if (delta != 0) {
error("Registered key map actions differs from TwinEActionType by %i", delta);
array[0] = gameKeyMap;
}
return Keymap::arrayOf(engineKeyMap);
{
Keymap *uiKeyMap = new Keymap(Keymap::kKeymapTypeGame, uiKeyMapId, "Little Big Adventure UI");
act = new Action("ACCEPT", _("Accept"));
act->setCustomEngineActionEvent(TwinEActionType::UIEnter);
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("KP_ENTER");
uiKeyMap->addAction(act);
act = new Action("ABORT", _("Abort"));
act->setCustomEngineActionEvent(TwinEActionType::UIAbort);
act->addDefaultInputMapping("ESCAPE");
uiKeyMap->addAction(act);
act = new Action("UP", _("Up"));
act->setCustomEngineActionEvent(TwinEActionType::UIUp);
act->addDefaultInputMapping("UP");
act->addDefaultInputMapping("KP8");
uiKeyMap->addAction(act);
act = new Action("DOWN", _("Down"));
act->setCustomEngineActionEvent(TwinEActionType::UIDown);
act->addDefaultInputMapping("DOWN");
act->addDefaultInputMapping("KP2");
uiKeyMap->addAction(act);
act = new Action("RIGHT", _("Right"));
act->setCustomEngineActionEvent(TwinEActionType::UIRight);
act->addDefaultInputMapping("RIGHT");
act->addDefaultInputMapping("KP6");
uiKeyMap->addAction(act);
act = new Action("LEFT", _("Left"));
act->setCustomEngineActionEvent(TwinEActionType::UILeft);
act->addDefaultInputMapping("LEFT");
act->addDefaultInputMapping("KP4");
uiKeyMap->addAction(act);
array[1] = uiKeyMap;
}
{
Keymap *cutsceneKeyMap = new Keymap(Keymap::kKeymapTypeGame, cutsceneKeyMapId, "Little Big Adventure Cutscenes");
act = new Action("ABORT", _("Abort"));
act->setCustomEngineActionEvent(TwinEActionType::CutsceneAbort);
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("KP_ENTER");
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("SPACE");
cutsceneKeyMap->addAction(act);
array[2] = cutsceneKeyMap;
}
return array;
}
} // namespace TwinE

View file

@ -198,6 +198,7 @@ void Redraw::updateOverlayTypePosition(int16 X1, int16 Y1, int16 X2, int16 Y2) {
}
}
// TODO: convert to bool and check if this isn't always true...
void Redraw::redrawEngineActions(int32 bgRedraw) { // fullRedraw
int16 tmp_projPosX;
int16 tmp_projPosY;

View file

@ -29,6 +29,7 @@
#include "common/str.h"
#include "common/system.h"
#include "common/textconsole.h"
#include "common/translation.h"
#include "engines/util.h"
#include "graphics/managed_surface.h"
#include "graphics/palette.h"
@ -47,8 +48,8 @@
#include "twine/grid.h"
#include "twine/holomap.h"
#include "twine/hqrdepack.h"
#include "twine/interface.h"
#include "twine/input.h"
#include "twine/interface.h"
#include "twine/menu.h"
#include "twine/menuoptions.h"
#include "twine/movements.h"
@ -323,6 +324,8 @@ void TwinEEngine::processActorSamplePosition(int32 actorIdx) {
}
int32 TwinEEngine::runGameEngine() { // mainLoopInteration
_input->enabledKeyMap(mainKeyMapId);
readKeys();
if (_scene->needChangeScene > -1) {
@ -364,7 +367,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
_redraw->redrawEngineActions(1);
}
if (loopCurrentKey == twineactions[TwinEActionType::OptionsMenu].localKey) {
if (_input->toggleActionIfActive(TwinEActionType::OptionsMenu)) {
freezeTime();
_sound->pauseSamples();
_menu->OptionsMenuState[MenuSettings_FirstButton] = 15; // TODO: why? - where is the reset? kReturnGame
@ -379,7 +382,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
// inventory menu
loopInventoryItem = -1;
if (loopCurrentKey == twineactions[TwinEActionType::InventoryMenu].localKey && _scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
if (_input->isActionActive(TwinEActionType::InventoryMenu) && _scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
freezeTime();
_menu->processInventoryMenu();
@ -488,19 +491,19 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
}
// Process behaviour menu
if ((loopCurrentKey == twineactions[TwinEActionType::BehaviourMenu].localKey ||
loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourNormal].localKey ||
loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAthletic].localKey ||
loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAggressive].localKey ||
loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey) &&
if ((_input->isActionActive(TwinEActionType::BehaviourMenu, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourNormal, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourAggressive, false) ||
_input->isActionActive(TwinEActionType::QuickBehaviourDiscreet, false)) &&
_scene->sceneHero->entity != -1 && _scene->sceneHero->controlMode == kManual) {
if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourNormal].localKey) {
if (_input->isActionActive(TwinEActionType::QuickBehaviourNormal, false)) {
_actor->heroBehaviour = HeroBehaviourType::kNormal;
} else if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAthletic].localKey) {
} else if (_input->isActionActive(TwinEActionType::QuickBehaviourAthletic, false)) {
_actor->heroBehaviour = HeroBehaviourType::kAthletic;
} else if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourAggressive].localKey) {
} else if (_input->isActionActive(TwinEActionType::QuickBehaviourAggressive, false)) {
_actor->heroBehaviour = HeroBehaviourType::kAggressive;
} else if (loopCurrentKey == twineactions[TwinEActionType::QuickBehaviourDiscreet].localKey) {
} else if (_input->isActionActive(TwinEActionType::QuickBehaviourDiscreet, false)) {
_actor->heroBehaviour = HeroBehaviourType::kDiscrete;
}
freezeTime();
@ -510,7 +513,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
}
// use Proto-Pack
if (loopCurrentKey == twineactions[TwinEActionType::UseProtoPack].localKey && _gameState->gameFlags[InventoryItems::kiProtoPack] == 1) {
if (_input->isActionActive(TwinEActionType::UseProtoPack, false) && _gameState->gameFlags[InventoryItems::kiProtoPack] == 1) {
if (_gameState->gameFlags[InventoryItems::kiBookOfBu]) {
_scene->sceneHero->body = 0;
} else {
@ -543,7 +546,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
}
// Process Pause
if (loopCurrentKey == twineactions[TwinEActionType::Pause].localKey) {
if (_input->toggleActionIfActive(TwinEActionType::Pause)) {
freezeTime();
_text->setFontColor(15);
_text->drawText(5, 446, "Pause"); // no key for pause in Text Bank
@ -554,7 +557,7 @@ int32 TwinEEngine::runGameEngine() { // mainLoopInteration
break;
}
g_system->delayMillis(10);
} while (_input->internalKeyCode != 0x19 && !_input->pressedKey);
} while (!_input->toggleActionIfActive(TwinEActionType::Pause));
unfreezeTime();
_redraw->redrawEngineActions(1);
}
@ -760,6 +763,7 @@ bool TwinEEngine::gameEngineLoop() { // mainLoop
_screens->lockPalette = true;
_movements->setActorAngle(0, -256, 5, &loopMovePtr);
while (quitGame == -1) {
start = g_system->getMillis();