Skip to content

Commit

Permalink
AGI: Add optional "pause, when entering commands" feature
Browse files Browse the repository at this point in the history
Shows a prompt window and pauses the game (just like original AGI
did, but original AGI only did it in Hercules rendering mode).
  • Loading branch information
Martin Kiewitz committed Feb 28, 2016
1 parent aded46f commit e6466b2
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 21 deletions.
10 changes: 10 additions & 0 deletions engines/agi/detection.cpp
Expand Up @@ -181,6 +181,16 @@ static const ADExtraGuiOptionsMap optionsList[] = {
}
},

{
GAMEOPTION_COMMAND_PROMPT_WINDOW,
{
_s("Pause, when entering commands"),
_s("Shows a command prompt window and pauses the game (like in SCI) instead of a real-time prompt."),
"commandpromptwindow",
false
}
},

AD_EXTRA_GUI_OPTIONS_TERMINATOR
};

Expand Down
7 changes: 4 additions & 3 deletions engines/agi/detection_tables.h
Expand Up @@ -26,11 +26,12 @@ namespace Agi {
#define GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE GUIO_GAMEOPTIONS2
#define GAMEOPTION_DISABLE_MOUSE GUIO_GAMEOPTIONS3
#define GAMEOPTION_USE_HERCULES_FONT GUIO_GAMEOPTIONS4
#define GAMEOPTION_COMMAND_PROMPT_WINDOW GUIO_GAMEOPTIONS5
// TODO: properly implement GAMEOPTIONs

#define GAMEOPTIONS_DEFAULT GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_DISABLE_MOUSE,GAMEOPTION_USE_HERCULES_FONT)
#define GAMEOPTIONS_AMIGA GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE,GAMEOPTION_USE_HERCULES_FONT)
#define GAMEOPTIONS_FANMADE_MOUSE GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_USE_HERCULES_FONT)
#define GAMEOPTIONS_DEFAULT GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_DISABLE_MOUSE,GAMEOPTION_USE_HERCULES_FONT,GAMEOPTION_COMMAND_PROMPT_WINDOW)
#define GAMEOPTIONS_AMIGA GUIO4(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_AMIGA_ALTERNATIVE_PALETTE,GAMEOPTION_USE_HERCULES_FONT,GAMEOPTION_COMMAND_PROMPT_WINDOW)
#define GAMEOPTIONS_FANMADE_MOUSE GUIO3(GAMEOPTION_ORIGINAL_SAVELOAD,GAMEOPTION_USE_HERCULES_FONT,GAMEOPTION_COMMAND_PROMPT_WINDOW)

#define GAME_LVFPN(id,extra,fname,md5,size,lang,ver,features,gid,platform,interp,guioptions) { \
{ \
Expand Down
43 changes: 43 additions & 0 deletions engines/agi/systemui.cpp
Expand Up @@ -44,6 +44,8 @@ SystemUI::SystemUI(AgiEngine *vm, GfxMgr *gfx, TextMgr *text) {
_textStatusSoundOn = "Sound:on";
_textStatusSoundOff = "Sound:off";

_textEnterCommand = "Enter input\n\n";

_textPause = " Game paused.\nPress Enter to continue.";
_textPauseButton = nullptr;

Expand Down Expand Up @@ -214,6 +216,47 @@ const char *SystemUI::getInventoryTextReturnToGame() {
return _textInventoryReturnToGame;
}

bool SystemUI::askForCommand(Common::String &commandText) {
// Let user enter the command (this was originally only available for Hercules rendering, we allow it everywhere)
bool previousEditState = _text->inputGetEditStatus();
byte previousEditCursor = _text->inputGetCursorChar();

_text->drawMessageBox(_textEnterCommand, 0, 36, true);

_text->inputEditOn();

_text->charPos_Push();
_text->charAttrib_Push();

_text->charPos_SetInsideWindow(2, 0);
_text->charAttrib_Set(15, 0);
_text->clearBlockInsideWindow(2, 0, 36, 0); // input line is supposed to be black
_text->inputSetCursorChar('_');

_text->stringSet(commandText.c_str()); // Set current command text (may be a command recall)

_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_GETSTRING);
_text->stringEdit(35); // only allow up to 35 characters

_text->charAttrib_Pop();
_text->charPos_Pop();
_text->inputSetCursorChar(previousEditCursor);
if (!previousEditState) {
_text->inputEditOff();
}

_text->closeWindow();

if (!_text->stringWasEntered()) {
// User cancelled? exit now
return false;
}

commandText.clear();
commandText += (char *)_text->_inputString;
return true;
}

int16 SystemUI::figureOutAutomaticSaveGameSlot(const char *automaticSaveDescription) {
int16 matchedGameSlotId = -1;
int16 freshGameSlotId = -1;
Expand Down
4 changes: 4 additions & 0 deletions engines/agi/systemui.h
Expand Up @@ -77,6 +77,8 @@ class SystemUI {
const char *getInventoryTextSelectItems();
const char *getInventoryTextReturnToGame();

bool askForCommand(Common::String &commandText);

int16 figureOutAutomaticSaveGameSlot(const char *automaticSaveDescription);
int16 figureOutAutomaticRestoreGameSlot(const char *automaticSaveDescription);

Expand Down Expand Up @@ -130,6 +132,8 @@ class SystemUI {
const char *_textStatusSoundOn;
const char *_textStatusSoundOff;

const char *_textEnterCommand;

const char *_textPause;
const char *_textPauseButton;
const char *_textRestart;
Expand Down
96 changes: 80 additions & 16 deletions engines/agi/text.cpp
Expand Up @@ -20,6 +20,7 @@
*
*/

#include "common/config-manager.h"
#include "agi/agi.h"
#include "agi/sprite.h" // for commit_both()
#include "agi/graphics.h"
Expand Down Expand Up @@ -74,6 +75,12 @@ TextMgr::TextMgr(AgiEngine *vm, Words *words, GfxMgr *gfx) {
configureScreen(2);

_messageBoxCancelled = false;

_optionCommandPromptWindow = false;

if (ConfMan.getBool("commandpromptwindow")) {
_optionCommandPromptWindow = true;
}
}

TextMgr::~TextMgr() {
Expand Down Expand Up @@ -671,6 +678,30 @@ void TextMgr::promptKeyPress(uint16 newKey) {
int16 maxChars = 0;
int16 scriptsInputLen = _vm->getVar(VM_VAR_MAX_INPUT_CHARACTERS);

bool acceptableInput = false;

// FEATURE: Sierra didn't check for valid characters (filtered out umlauts etc.)
// In text-mode this sort of worked at least with the DOS interpreter
// but as soon as invalid characters were used in graphics mode they weren't properly shown
switch (_vm->getLanguage()) {
case Common::RU_RUS:
if (newKey >= 0x20)
acceptableInput = true;
break;
default:
if ((newKey >= 0x20) && (newKey <= 0x7f))
acceptableInput = true;
break;
}

if (_optionCommandPromptWindow) {
// Forward to command prompt window, using last command
if (acceptableInput) {
promptCommandWindow(false, newKey);
}
return;
}

if (_messageState.dialogue_Open) {
maxChars = TEXT_STRING_MAX_SIZE - 4;
} else {
Expand Down Expand Up @@ -715,22 +746,6 @@ void TextMgr::promptKeyPress(uint16 newKey) {
}
default:
if (maxChars > _promptCursorPos) {
bool acceptableInput = false;

// FEATURE: Sierra didn't check for valid characters (filtered out umlauts etc.)
// In text-mode this sort of worked at least with the DOS interpreter
// but as soon as invalid characters were used in graphics mode they weren't properly shown
switch (_vm->getLanguage()) {
case Common::RU_RUS:
if (newKey >= 0x20)
acceptableInput = true;
break;
default:
if ((newKey >= 0x20) && (newKey <= 0x7f))
acceptableInput = true;
break;
}

if (acceptableInput) {
_prompt[_promptCursorPos] = newKey;
_promptCursorPos++;
Expand All @@ -747,6 +762,11 @@ void TextMgr::promptKeyPress(uint16 newKey) {
}

void TextMgr::promptCancelLine() {
if (_optionCommandPromptWindow) {
// Abort, in case command prompt window is active
return;
}

while (_promptCursorPos) {
promptKeyPress(0x08); // Backspace until prompt is empty
}
Expand All @@ -755,6 +775,12 @@ void TextMgr::promptCancelLine() {
void TextMgr::promptEchoLine() {
int16 previousLen = strlen((char *)_promptPrevious);

if (_optionCommandPromptWindow) {
// Forward to command prompt window, using last command
promptCommandWindow(true, 0);
return;
}

if (_promptCursorPos < previousLen) {
inputEditOn();

Expand All @@ -771,6 +797,11 @@ void TextMgr::promptRedraw() {
char *textPtr = nullptr;

if (_promptEnabled) {
if (_optionCommandPromptWindow) {
// Abort, in case command prompt window is active
return;
}

inputEditOn();
clearLine(_promptRow, _textAttrib.background);
charPos_Set(_promptRow, 0);
Expand All @@ -788,6 +819,10 @@ void TextMgr::promptRedraw() {

// for AGI1
void TextMgr::promptClear() {
if (_optionCommandPromptWindow) {
// Abort, in case command prompt window is active
return;
}
clearLine(_promptRow, _textAttrib.background);
}

Expand All @@ -797,6 +832,35 @@ void TextMgr::promptRememberForAutoComplete(bool entered) {
#endif
}

void TextMgr::promptCommandWindow(bool recallLastCommand, uint16 newKey) {
Common::String commandText;

if (recallLastCommand) {
commandText += Common::String((char *)_promptPrevious);
}
if (newKey) {
if (newKey != ' ') {
// Only add char, when it's not a space.
// Original AGI did not filter space, but it makes no sense to start with a space.
// Space would get filtered anyway during dictionary parsing.
commandText += newKey;
}
}

if (_systemUI->askForCommand(commandText)) {
if (commandText.size()) {
// Something actually was entered?
strncpy((char *)&_prompt, commandText.c_str(), sizeof(_prompt));
promptRememberForAutoComplete(true);
memcpy(&_promptPrevious, &_prompt, sizeof(_prompt));
// parse text
_vm->_words->parseUsingDictionary((char *)&_prompt);

_prompt[0] = 0;
}
}
}

bool TextMgr::stringWasEntered() {
return _inputStringEntered;
}
Expand Down
4 changes: 4 additions & 0 deletions engines/agi/text.h
Expand Up @@ -163,6 +163,8 @@ class TextMgr {
bool _inputEditEnabled;
byte _inputCursorChar;

bool _optionCommandPromptWindow;

bool _promptEnabled;
int16 _promptRow;
int16 _promptCursorPos;
Expand All @@ -189,6 +191,8 @@ class TextMgr {
void promptClear(); // for AGI1
void promptRememberForAutoComplete(bool entered = false); // for auto-completion

void promptCommandWindow(bool recallLastCommand, uint16 newKey);

int16 _inputStringRow;
int16 _inputStringColumn;
bool _inputStringEntered;
Expand Down
2 changes: 1 addition & 1 deletion engines/agi/words.cpp
Expand Up @@ -293,7 +293,7 @@ int16 Words::findWordInDictionary(const Common::String &userInputLowcased, uint1
return wordId;
}

void Words::parseUsingDictionary(char *rawUserInput) {
void Words::parseUsingDictionary(const char *rawUserInput) {
Common::String userInput;
Common::String userInputLowcased;
const char *userInputPtr = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion engines/agi/words.h
Expand Up @@ -57,7 +57,7 @@ class Words {
void unloadDictionary();

void clearEgoWords();
void parseUsingDictionary(char *rawUserInput);
void parseUsingDictionary(const char *rawUserInput);

private:
void cleanUpInput(const char *userInput, Common::String &cleanInput);
Expand Down

0 comments on commit e6466b2

Please sign in to comment.