/* 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 .
*
*/
/*
* Based on ScottFree interpreter version 1.14 developed by Swansea
* University Computer Society without disassembly of any other game
* drivers, only of game databases as permitted by EEC law (for purposes
* of compatibility).
*
* Licensed under GPLv2
*
* https://github.com/angstsmurf/spatterlight/tree/master/terps/scott
*/
#include "common/str.h"
#include "glk/scott/scott.h"
#include "glk/scott/globals.h"
#include "glk/scott/command_parser.h"
namespace Glk {
namespace Scott {
#define MAX_WORDLENGTH 128
#define MAX_WORDS 128
#define MAX_BUFFER 128
void freeStrings() {
if (_G(_firstErrorMessage) != nullptr) {
delete[] _G(_firstErrorMessage);
_G(_firstErrorMessage) = nullptr;
}
if (_G(_wordsInInput) == 0) {
if (_G(_unicodeWords) != nullptr || _G(_charWords) != nullptr) {
g_scott->fatal("ERROR! Wordcount 0 but word arrays not empty!\n");
}
return;
}
for (int i = 0; i < _G(_wordsInInput); i++) {
if (_G(_unicodeWords)[i] != nullptr)
delete _G(_unicodeWords)[i];
if (_G(_charWords)[i] != nullptr)
delete _G(_charWords)[i];
}
delete _G(_unicodeWords);
_G(_unicodeWords) = nullptr;
delete _G(_charWords);
_G(_charWords) = nullptr;
_G(_wordsInInput) = 0;
}
void createErrorMessage(const char *fchar, glui32 *second, const char *tchar) {
if (_G(_firstErrorMessage) != nullptr)
return;
glui32 *first = toUnicode(fchar);
glui32 *third = toUnicode(tchar);
glui32 buffer[MAX_BUFFER];
int i, j = 0, k = 0;
for (i = 0; first[i] != 0 && i < MAX_BUFFER; i++)
buffer[i] = first[i];
if (second != nullptr) {
for (j = 0; second[j] != 0 && i + j < MAX_BUFFER; j++)
buffer[i + j] = second[j];
}
if (third != nullptr) {
for (k = 0; third[k] != 0 && i + j + k < MAX_BUFFER; k++)
buffer[i + j + k] = third[k];
delete[] third;
}
int length = i + j + k;
_G(_firstErrorMessage) = new glui32[(length + 1) * 4];
memcpy(_G(_firstErrorMessage), buffer, length * 4);
_G(_firstErrorMessage)[length] = 0;
delete[] first;
}
void printPendingError(void) {
if (_G(_firstErrorMessage)) {
g_scott->glk_put_string_stream_uni(g_scott->glk_window_get_stream(_G(_bottomWindow)), _G(_firstErrorMessage));
delete[] _G(_firstErrorMessage);
_G(_firstErrorMessage) = nullptr;
_G(_stopTime) = 1;
}
}
char **LineInput(void) {
event_t ev;
glui32 unibuf[512];
do {
g_scott->display(_G(_bottomWindow), "\n%s", _G(_sys)[WHAT_NOW].c_str());
g_scott->glk_request_line_event_uni(_G(_bottomWindow), unibuf, (glui32)511, 0);
while (ev.type != evtype_Quit) {
g_scott->glk_select(&ev);
if (ev.type == evtype_Quit)
return nullptr;
if (ev.type == evtype_LineInput)
break;
else
g_scott->updates(ev);
}
unibuf[ev.val1] = 0;
if (_G(_transcript)) {
g_scott->glk_put_string_stream_uni(_G(_transcript), unibuf);
g_scott->glk_put_char_stream_uni(_G(_transcript), 10);
}
_G(_charWords) = splitIntoWords(unibuf, ev.val1);
if (_G(_wordsInInput) == 0 || _G(_charWords) == nullptr)
g_scott->output(_G(_sys)[HUH]);
else {
return _G(_charWords);
}
} while (_G(_wordsInInput) == 0 || _G(_charWords) == nullptr);
return nullptr;
}
int matchYMCA(glui32 *string, int length, int index) {
const char *ymca = "y.m.c.a.";
int i;
for (i = 0; i < 8; i++) {
if (i + index > length || string[index + i] != static_cast(ymca[i]))
return i;
}
return i;
}
char **splitIntoWords(glui32 *string, int length) {
if (length < 1) {
return nullptr;
}
g_scott->glk_buffer_to_lower_case_uni(string, 256, length);
g_scott->glk_buffer_canon_normalize_uni(string, 256, length);
int startpos[MAX_WORDS];
int wordlength[MAX_WORDS];
int words_found = 0;
int word_index = 0;
int foundspace = 0;
int foundcomma = 0;
startpos[0] = 0;
wordlength[0] = 0;
int lastwasspace = 1;
for (int i = 0; string[i] != 0 && i < length && word_index < MAX_WORDS; i++) {
foundspace = 0;
switch (string[i]) {
case 'y': {
int ymca = matchYMCA(string, length, i);
if (ymca > 3) {
/* Start a new word */
startpos[words_found] = i;
wordlength[words_found] = ymca;
words_found++;
wordlength[words_found] = 0;
i += ymca;
if (i < length)
foundspace = 1;
lastwasspace = 0;
}
} break;
/* Unicode space and tab variants */
case ' ':
case '\t':
case '!':
case '?':
case '\"':
case 0x83: // ¿
case 0x80: // ¡
case 0xa0: // non-breaking space
case 0x2000: // en quad
case 0x2001: // em quad
case 0x2003: // em
case 0x2004: // three-per-em
case 0x2005: // four-per-em
case 0x2006: // six-per-em
case 0x2007: // figure space
case 0x2009: // thin space
case 0x200A: // hair space
case 0x202f: // narrow no-break space
case 0x205f: // medium mathematical space
case 0x3000: // ideographic space
foundspace = 1;
break;
case '.':
case ',':
foundcomma = 1;
break;
default:
break;
}
if (!foundspace) {
if (lastwasspace || foundcomma) {
/* Start a new word */
startpos[words_found] = i;
words_found++;
wordlength[words_found] = 0;
}
wordlength[words_found - 1]++;
lastwasspace = 0;
} else {
/* Check if the last character of previous word was a period or comma */
lastwasspace = 1;
foundcomma = 0;
}
}
if (words_found == 0) {
return nullptr;
}
wordlength[words_found]--; /* Don't count final newline character */
/* Now we've created two arrays, one for starting positions
and one for word length. Now we convert these into an array of strings */
glui32 **words = new glui32 *[words_found];
char **words8 = new char *[words_found];
for (int i = 0; i < words_found; i++) {
words[i] = new glui32[(wordlength[i] + 1) * 4];
memcpy(words[i], string + startpos[i], wordlength[i] * 4);
words[i][wordlength[i]] = 0;
words8[i] = fromUnicode(words[i], wordlength[i]);
}
_G(_unicodeWords) = words;
_G(_wordsInInput) = words_found;
return words8;
}
int findVerb(const char *string, Common::StringArray *list) {
*list = _G(_verbs);
int verb = whichWord(string, *list, _G(_gameHeader)->_wordLength);
if (verb) {
return verb;
}
*list = _G(_directions);
verb = whichWord(string, *list, _G(_gameHeader)->_wordLength);
if (verb) {
if (verb == 13)
verb = 4;
if (verb > 6)
verb -= 6;
return verb;
}
*list = _G(_abbreviations);
verb = whichWord(string, *list, _G(_gameHeader)->_wordLength);
if (verb) {
verb = whichWord(_G(_abbreviationsKey)[verb].c_str(), _G(_verbs), _G(_gameHeader)->_wordLength);
if (verb) {
list = &_G(_verbs);
return verb;
}
}
int stringlength = strlen(string);
*list = _G(_skipList);
verb = whichWord(string, *list, stringlength);
if (verb) {
return 0;
}
*list = _G(_nouns);
verb = whichWord(string, *list, _G(_gameHeader)->_wordLength);
if (verb) {
return verb;
}
*list = _G(_extraCommands);
verb = whichWord(string, *list, stringlength);
if (verb) {
verb = _G(_extraCommandsKey)[verb];
return verb + _G(_gameHeader)->_numWords;
}
*list = _G(_extraNouns);
verb = whichWord(string, *list, stringlength);
if (verb) {
verb = _G(_extraNounsKey)[verb];
return verb + _G(_gameHeader)->_numWords;
}
*list = _G(_delimiterList);
verb = whichWord(string, *list, stringlength);
if (!verb)
*list = Common::StringArray();
return verb;
}
int findExtraneousWords(int *index, int noun) {
/* Looking for extraneous words that should invalidate the command */
int originalIndex = *index;
if (*index >= _G(_wordsInInput)) {
return 0;
}
Common::StringArray list;
int verb = 0;
int stringlength = strlen(_G(_charWords)[*index]);
list = _G(_skipList);
do {
verb = whichWord(_G(_charWords)[*index], _G(_skipList), stringlength);
if (verb)
*index = *index + 1;
} while (verb && *index < _G(_wordsInInput));
if (*index >= _G(_wordsInInput))
return 0;
verb = findVerb(_G(_charWords)[*index], &list);
if (list == _G(_delimiterList)) {
if (*index > originalIndex)
*index = *index - 1;
return 0;
}
if (list == _G(_nouns) && noun) {
if (g_scott->mapSynonym(noun) == g_scott->mapSynonym(verb)) {
*index = *index + 1;
return 0;
}
}
if (list.empty()) {
if (*index >= _G(_wordsInInput))
*index = _G(_wordsInInput) - 1;
createErrorMessage(_G(_sys)[I_DONT_KNOW_WHAT_A].c_str(), _G(_unicodeWords)[*index], _G(_sys)[IS].c_str());
} else {
createErrorMessage(_G(_sys)[I_DONT_UNDERSTAND].c_str(), nullptr, nullptr);
}
return 1;
}
Command *commandFromStrings(int index, Command *previous);
Command *createCommandStruct(int verb, int noun, int verbIndex, int nounIndex, Command *previous) {
Command *command = new Command;
command->_verb = verb;
command->_noun = noun;
command->_allFlag = 0;
command->_item = 0;
command->_previous = previous;
command->_verbWordIndex = verbIndex;
if (noun && nounIndex > 0) {
command->_nounWordIndex = nounIndex - 1;
} else {
command->_nounWordIndex = 0;
}
command->_next = commandFromStrings(nounIndex, command);
return command;
}
int findNoun(const char *string, Common::StringArray *list) {
*list = _G(_nouns);
int noun = whichWord(string, *list, _G(_gameHeader)->_wordLength);
if (noun) {
return noun;
}
*list = _G(_directions);
noun = whichWord(string, *list, _G(_gameHeader)->_wordLength);
if (noun) {
if (noun > 6)
noun -= 6;
*list = _G(_nouns);
return noun;
}
int stringLength = strlen(string);
*list = _G(_extraNouns);
noun = whichWord(string, *list, stringLength);
if (noun) {
noun = _G(_extraNounsKey)[noun];
return noun + _G(_gameHeader)->_numWords;
}
*list = _G(_skipList);
noun = whichWord(string, *list, stringLength);
if (noun) {
return 0;
}
*list = _G(_verbs);
noun = whichWord(string, *list, _G(_gameHeader)->_wordLength);
if (noun) {
return noun;
}
*list = _G(_delimiterList);
noun = whichWord(string, *list, stringLength);
if (!noun)
*list = Common::StringArray();
return 0;
}
Command *commandFromStrings(int index, Command *previous) {
if (index < 0 || index >= _G(_wordsInInput)) {
return nullptr;
}
Common::StringArray list;
int verb = 0;
int i = index;
do {
/* Checking if it is a verb */
verb = findVerb(_G(_charWords)[i++], &list);
} while ((list == _G(_skipList) || list == _G(_delimiterList)) && i < _G(_wordsInInput));
int verbindex = i - 1;
if (list == _G(_directions)) {
/* It is a direction */
if (verb == 0 || findExtraneousWords(&i, 0) != 0)
return nullptr;
return createCommandStruct(GO, verb, 0, i, previous);
}
int found_noun_at_verb_position = 0;
int lastverb = 0;
if (list == _G(_nouns) || list == _G(_extraNouns)) {
/* It is a noun */
/* If we find no verb, we try copying the verb from the previous command */
if (previous) {
lastverb = previous->_verb;
}
/* Unless the game is German, where we allow the noun to come before the
* verb */
if (CURRENT_GAME != GREMLINS_GERMAN && CURRENT_GAME != GREMLINS_GERMAN_C64) {
if (!previous) {
createErrorMessage(_G(_sys)[I_DONT_KNOW_HOW_TO].c_str(), _G(_unicodeWords)[i - 1], _G(_sys)[SOMETHING].c_str());
return nullptr;
} else {
verbindex = previous->_verbWordIndex;
}
if (findExtraneousWords(&i, verb) != 0)
return nullptr;
return createCommandStruct(lastverb, verb, verbindex, i, previous);
} else {
found_noun_at_verb_position = 1;
}
}
if (list.empty() || list == _G(_skipList)) {
createErrorMessage(_G(_sys)[I_DONT_KNOW_HOW_TO].c_str(), _G(_unicodeWords)[i - 1], _G(_sys)[SOMETHING].c_str());
return nullptr;
}
if (i == _G(_wordsInInput)) {
if (lastverb) {
return createCommandStruct(lastverb, verb, previous->_verbWordIndex, i, previous);
} else if (found_noun_at_verb_position) {
createErrorMessage(_G(_sys)[I_DONT_KNOW_HOW_TO].c_str(), _G(_unicodeWords)[i - 1], _G(_sys)[SOMETHING].c_str());
return nullptr;
} else {
return createCommandStruct(verb, 0, i - 1, i, previous);
}
}
int noun = 0;
do {
/* Check if it is a noun */
noun = findNoun(_G(_charWords)[i++], &list);
} while (list == _G(_skipList) && i < _G(_wordsInInput));
if (list == _G(_nouns) || list == _G(_extraNouns)) {
/* It is a noun */
/* Check if it is an ALL followed by EXCEPT */
int except = 0;
if (list == _G(_extraNouns) && i < _G(_wordsInInput) && noun - _G(_gameHeader)->_numWords == ALL) {
int stringlength = strlen(_G(_charWords)[i]);
except = whichWord(_G(_charWords)[i], _G(_extraCommands), stringlength);
}
if (_G(_extraCommandsKey)[except] != EXCEPT && findExtraneousWords(&i, noun) != 0)
return nullptr;
if (found_noun_at_verb_position) {
int realverb = whichWord(_G(_charWords)[i - 1], _G(_verbs), _G(_gameHeader)->_wordLength);
if (realverb) {
noun = verb;
verb = realverb;
} else if (lastverb) {
noun = verb;
verb = lastverb;
}
}
return createCommandStruct(verb, noun, verbindex, i, previous);
}
if (list == _G(_delimiterList)) {
/* It is a delimiter */
return createCommandStruct(verb, 0, verbindex, i, previous);
}
if (list == _G(_verbs) && found_noun_at_verb_position) {
/* It is a verb */
/* Check if it is an ALL followed by EXCEPT */
int except = 0;
if (i < _G(_wordsInInput) && verb - _G(_gameHeader)->_numWords == ALL) {
int stringlength = strlen(_G(_charWords)[i]);
except = whichWord(_G(_charWords)[i], _G(_extraCommands), stringlength);
}
if (_G(_extraCommandsKey)[except] != EXCEPT && findExtraneousWords(&i, 0) != 0)
return nullptr;
return createCommandStruct(noun, verb, i - 1, i, previous);
}
createErrorMessage(_G(_sys)[I_DONT_KNOW_WHAT_A].c_str(), _G(_unicodeWords)[i - 1], _G(_sys)[IS].c_str());
return nullptr;
}
int createAllCommands(Command *command) {
Common::Array exceptions(_G(_gameHeader)->_numItems);
int exceptioncount = 0;
int location = CARRIED;
if (command->_verb == TAKE)
location = MY_LOC;
Command *next = command->_next;
/* Check if the ALL command is followed by EXCEPT */
/* and if it is, build an array of items to be excepted */
while (next && next->_verb == _G(_gameHeader)->_numWords + EXCEPT) {
for (int i = 0; i <= _G(_gameHeader)->_numItems; i++) {
if (!_G(_items)[i]._autoGet.empty() && scumm_strnicmp(_G(_items)[i]._autoGet.c_str(), _G(_charWords)[next->_nounWordIndex], _G(_gameHeader)->_wordLength) == 0) {
exceptions[exceptioncount++] = i;
}
}
/* Remove the EXCEPT command from the linked list of commands */
next = next->_next;
delete command->_next;
command->_next = next;
}
Command *c = command;
int found = 0;
for (int i = 0; i < _G(_gameHeader)->_numItems; i++) {
if (!_G(_items)[i]._autoGet.empty() && _G(_items)[i]._autoGet[0] != '*' && _G(_items)[i]._location == location) {
int exception = 0;
for (int j = 0; j < exceptioncount; j++) {
if (exceptions[j] == i) {
exception = 1;
break;
}
}
if (!exception) {
if (found) {
c->_next = new Command;
c->_next->_previous = c;
c = c->_next;
}
found = 1;
c->_verb = command->_verb;
c->_noun = whichWord(_G(_items)[i]._autoGet.c_str(), _G(_nouns), _G(_gameHeader)->_wordLength);
c->_item = i;
c->_next = nullptr;
c->_nounWordIndex = 0;
c->_allFlag = 1;
}
}
}
if (found == 0) {
if (command->_verb == TAKE)
createErrorMessage(_G(_sys)[NOTHING_HERE_TO_TAKE].c_str(), nullptr, nullptr);
else
createErrorMessage(_G(_sys)[YOU_HAVE_NOTHING].c_str(), nullptr, nullptr);
return 0;
} else {
c->_next = next;
c->_allFlag = 1 | LASTALL;
}
return 1;
}
int getInput(int *vb, int *no) {
if (_G(_currentCommand) && _G(_currentCommand)->_next) {
_G(_currentCommand) = _G(_currentCommand)->_next;
} else {
printPendingError();
if (_G(_currentCommand))
freeCommands();
_G(_charWords) = LineInput();
if (_G(_wordsInInput) == 0 || _G(_charWords) == nullptr)
return 0;
_G(_currentCommand) = commandFromStrings(0, nullptr);
}
if (_G(_currentCommand) == nullptr) {
printPendingError();
return 1;
}
/* We use NumWords + verb for our extra commands */
/* such as UNDO and TRANSCRIPT */
if (_G(_currentCommand)->_verb > _G(_gameHeader)->_numWords) {
if (!g_scott->performExtraCommand(0)) {
createErrorMessage(_G(_sys)[I_DONT_UNDERSTAND].c_str(), nullptr, nullptr);
}
return 1;
/* And NumWords + noun for our extra nouns */
/* such as ALL */
} else if (_G(_currentCommand)->_noun > _G(_gameHeader->_numWords)) {
_G(_currentCommand)->_noun -= _G(_gameHeader)->_numWords;
if (_G(_currentCommand)->_noun == ALL) {
if (_G(_currentCommand)->_verb != TAKE && _G(_currentCommand)->_verb != DROP) {
createErrorMessage(_G(_sys)[CANT_USE_ALL].c_str(), nullptr, nullptr);
return 1;
}
if (!createAllCommands(_G(_currentCommand)))
return 1;
} else if (_G(_currentCommand)->_noun == IT) {
_G(_currentCommand)->_noun = _G(_lastNoun);
}
}
*vb = _G(_currentCommand)->_verb;
*no = _G(_currentCommand)->_noun;
if (*no > 6) {
_G(_lastNoun) = *no;
}
return 0;
}
void freeCommands() {
while (_G(_currentCommand) && _G(_currentCommand)->_previous)
_G(_currentCommand) = _G(_currentCommand)->_previous;
while (_G(_currentCommand)) {
Command *temp = _G(_currentCommand);
_G(_currentCommand) = _G(_currentCommand)->_next;
delete temp;
}
_G(_currentCommand) = nullptr;
freeStrings();
if (_G(_firstErrorMessage))
delete[] _G(_firstErrorMessage);
_G(_firstErrorMessage) = nullptr;
}
glui32 *toUnicode(const char *string) {
if (string == nullptr)
return nullptr;
glui32 unicode[2048];
int i;
int dest = 0;
for (i = 0; string[i] != 0 && i < 2047; i++) {
char c = string[i];
if (c == '\n')
c = 10;
glui32 unichar = (glui32)c;
if (_G(_game) && (CURRENT_GAME == GREMLINS_GERMAN || CURRENT_GAME == GREMLINS_GERMAN_C64)) {
const char d = string[i + 1];
if (c == 'u' && d == 'e') { // ü
if (!(i > 2 && string[i - 1] == 'e')) {
unichar = 0xfc;
i++;
}
} else if (c == 'o' && d == 'e') {
unichar = 0xf6; // ö
i++;
} else if (c == 'a' && d == 'e') {
unichar = 0xe4; // ä
i++;
} else if (c == 's' && d == 's') {
if (string[i + 2] != 'c' && string[i - 2] != 'W' && !(string[i - 1] == 'a' && string[i - 2] == 'l') && string[i + 2] != '-' && string[i - 2] != 'b') {
unichar = 0xdf; // ß
i++;
}
} else if (c == 'U' && d == 'E') {
unichar = 0xdc; // Ü
i++;
}
if (c == '\"') {
unichar = 0x2019; // ’
}
} else if (_G(_game) && CURRENT_GAME == GREMLINS_SPANISH) {
switch (c) {
case '\x83':
unichar = 0xbf; // ¿
break;
case '\x80':
unichar = 0xa1; // ¡
break;
case '\x82':
unichar = 0xfc; // ü
break;
case '{':
unichar = 0xe1; // á
break;
case '}':
unichar = 0xed; // í
break;
case '|':
unichar = 0xf3; // ó
break;
case '~':
unichar = 0xf1; // ñ
break;
case '\x84':
unichar = 0xe9; // é
break;
case '\x85':
unichar = 0xfa; // ú
break;
}
} else if (_G(_game) && CURRENT_GAME == TI994A) {
switch (c) {
case '@':
unicode[dest++] = 0xa9;
unichar = ' ';
break;
case '}':
unichar = 0xfc;
break;
case 12:
unichar = 0xf6;
break;
case '{':
unichar = 0xe4;
break;
}
}
unicode[dest++] = unichar;
}
unicode[dest] = 0;
glui32 *result = new glui32[(dest + 1) * 4];
memcpy(result, unicode, (dest + 1) * 4);
return result;
}
char *fromUnicode(glui32 *unicodeString, int origLength) {
int sourcepos = 0;
int destpos = 0;
char dest[MAX_WORDLENGTH];
glui32 unichar = unicodeString[sourcepos];
while (unichar != 0 && destpos < MAX_WORDLENGTH && sourcepos < origLength) {
switch (unichar) {
case '.':
if (origLength == 1) {
dest[destpos++] = 'a';
dest[destpos++] = 'n';
dest[destpos++] = 'd';
} else {
dest[destpos] = (char)unichar;
}
break;
case 0xf6: // ö
dest[destpos++] = 'o';
dest[destpos] = 'e';
break;
case 0xe4: // ä
dest[destpos++] = 'a';
dest[destpos] = 'e';
break;
case 0xfc: // ü
dest[destpos] = 'u';
if (CURRENT_GAME == GREMLINS_GERMAN || CURRENT_GAME == GREMLINS_GERMAN_C64) {
destpos++;
dest[destpos] = 'e';
}
break;
case 0xdf: // ß
dest[destpos++] = 's';
dest[destpos] = 's';
break;
case 0xed: // í
dest[destpos] = 'i';
break;
case 0xe1: // á
dest[destpos] = 'a';
break;
case 0xf3: // ó
dest[destpos] = 'o';
break;
case 0xf1: // ñ
dest[destpos] = 'n';
break;
case 0xe9: // é
dest[destpos] = 'e';
break;
default:
dest[destpos] = (char)unichar;
break;
}
sourcepos++;
destpos++;
unichar = unicodeString[sourcepos];
}
if (destpos == 0)
return nullptr;
char *result = new char[destpos + 1];
memcpy(result, dest, destpos);
result[destpos] = 0;
return result;
}
int recheckForExtraCommand() {
const char *verbWord = _G(_charWords)[_G(_currentCommand)->_verbWordIndex];
int extraVerb = whichWord(verbWord, _G(_extraCommands), _G(_gameHeader)->_wordLength);
if (!extraVerb) {
return 0;
}
int ExtraNoun = 0;
if (_G(_currentCommand)->_noun) {
const char *nounWord = _G(_charWords)[_G(_currentCommand)->_nounWordIndex];
ExtraNoun = whichWord(nounWord, _G(_extraNouns), strlen(nounWord));
}
_G(_currentCommand)->_verb = _G(_extraCommandsKey)[extraVerb];
if (ExtraNoun)
_G(_currentCommand)->_noun = _G(_extraNounsKey)[ExtraNoun];
return g_scott->performExtraCommand(1);
}
int whichWord(const char *word, Common::StringArray list, int wordLength) {
int n = 1;
unsigned int ne = 1;
const char *tp;
while (ne < list.size()) {
tp = list[ne].c_str();
if (*tp == '*')
tp++;
else
n = ne;
if (scumm_strnicmp(word, tp, wordLength) == 0)
return (n);
ne++;
}
return (0);
}
} // End of namespace Scott
} // End of namespace Glk