aboutsummaryrefslogtreecommitdiff
path: root/engines/hugo/parser.cpp
diff options
context:
space:
mode:
authorArnaud Boutonné2010-10-10 07:43:42 +0000
committerArnaud Boutonné2010-10-10 07:43:42 +0000
commitced1aba1eac0e8e7891ad44f09ff0877a4fbb3da (patch)
tree08bcecac119f950b978408f7f14ae757f81da251 /engines/hugo/parser.cpp
parent582bd9a395e13881d96ea7c7cc54d3469d696565 (diff)
downloadscummvm-rg350-ced1aba1eac0e8e7891ad44f09ff0877a4fbb3da.tar.gz
scummvm-rg350-ced1aba1eac0e8e7891ad44f09ff0877a4fbb3da.tar.bz2
scummvm-rg350-ced1aba1eac0e8e7891ad44f09ff0877a4fbb3da.zip
HUGO: New parser for H1 Dos and H2 Dos.
Add specific parser functions for H1 Dos and H2 Dos svn-id: r53106
Diffstat (limited to 'engines/hugo/parser.cpp')
-rw-r--r--engines/hugo/parser.cpp764
1 files changed, 572 insertions, 192 deletions
diff --git a/engines/hugo/parser.cpp b/engines/hugo/parser.cpp
index 59fe023788..a232e9df96 100644
--- a/engines/hugo/parser.cpp
+++ b/engines/hugo/parser.cpp
@@ -56,6 +56,9 @@ Parser::Parser(HugoEngine &vm) :
_vm(vm), _putIndex(0), _getIndex(0), _checkDoubleF1Fl(false) {
}
+Parser::~Parser() {
+}
+
void Parser::keyHandler(uint16 nChar, uint16 nFlags) {
debugC(1, kDebugParser, "keyHandler(%d, %d)", nChar, nFlags);
@@ -202,8 +205,218 @@ void Parser::command(const char *format, ...) {
lineHandler();
}
+Parser_v1w::Parser_v1w(HugoEngine &vm) : Parser(vm) {
+}
+
+Parser_v1w::~Parser_v1w() {
+}
+
+// Test whether command line contains a verb allowed by this object.
+// If it does, and the object is near and passes the tests in the command
+// list then carry out the actions in the action list and return TRUE
+bool Parser_v1w::isObjectVerb(object_t *obj, char *comment) {
+ debugC(1, kDebugParser, "isObjectVerb(object_t *obj, %s)", comment);
+
+ // First, find matching verb in cmd list
+ uint16 cmdIndex = obj->cmdIndex; // ptr to list of commands
+ if (cmdIndex == 0) // No commands for this obj
+ return false;
+
+ int i;
+ for (i = 0; _vm._cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd
+ if (isWordPresent(_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex])) // Was this verb used?
+ break;
+ }
+
+ if (_vm._cmdList[cmdIndex][i].verbIndex == 0) // No verbs used.
+ return false;
+
+ // Verb match found. Check if object is Near
+ char *verb = *_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex];
+ if (!isNear(obj, verb, comment))
+ return false;
+
+ // Check all required objects are being carried
+ cmd *cmnd = &_vm._cmdList[cmdIndex][i]; // ptr to struct cmd
+ if (cmnd->reqIndex) { // At least 1 thing in list
+ uint16 *reqs = _vm._arrayReqs[cmnd->reqIndex]; // ptr to list of required objects
+ for (i = 0; reqs[i]; i++) { // for each obj
+ if (!isCarrying(reqs[i])) {
+ Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataNoCarryIndex]);
+ return true;
+ }
+ }
+ }
+
+ // Required objects are present, now check state is correct
+ if ((obj->state != cmnd->reqState) && (cmnd->reqState != DONT_CARE)) {
+ Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataWrongIndex]);
+ return true;
+ }
+
+ // Everything checked. Change the state and carry out any actions
+ if (cmnd->reqState != DONT_CARE) // Don't change new state if required state didn't care
+ obj->state = cmnd->newState;
+ Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataDoneIndex]);
+ _vm.scheduler().insertActionList(cmnd->actIndex);
+
+ // See if any additional generic actions
+ if ((verb == _vm._arrayVerbs[_vm._look][0]) || (verb == _vm._arrayVerbs[_vm._take][0]) || (verb == _vm._arrayVerbs[_vm._drop][0]))
+ isGenericVerb(obj, comment);
+ return true;
+}
+
+// Test whether command line contains one of the generic actions
+bool Parser_v1w::isGenericVerb(object_t *obj, char *comment) {
+ debugC(1, kDebugParser, "isGenericVerb(object_t *obj, %s)", comment);
+
+ if (!obj->genericCmd)
+ return false;
+
+ // Following is equivalent to switch, but couldn't do one
+ if (isWordPresent(_vm._arrayVerbs[_vm._look]) && isNear(obj, _vm._arrayVerbs[_vm._look][0], comment)) {
+ // Test state-dependent look before general look
+ if ((obj->genericCmd & LOOK_S) == LOOK_S) {
+ Utils::Box(BOX_ANY, "%s", _vm._textData[obj->stateDataIndex[obj->state]]);
+ warning("isGenericVerb: use of state dependant look - To be validated");
+ } else {
+ if ((LOOK & obj->genericCmd) == LOOK) {
+ if (_vm._textData[obj->dataIndex])
+ Utils::Box(BOX_ANY, "%s", _vm._textData[obj->dataIndex]);
+ else
+ return false;
+ } else {
+ Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBUnusual]);
+ }
+ }
+ } else if (isWordPresent(_vm._arrayVerbs[_vm._take]) && isNear(obj, _vm._arrayVerbs[_vm._take][0], comment)) {
+ if (obj->carriedFl)
+ Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBHave]);
+ else if ((TAKE & obj->genericCmd) == TAKE)
+ takeObject(obj);
+ else if (obj->cmdIndex != 0) // No comment if possible commands
+ return false;
+ else if (!obj->verbOnlyFl && (TAKE & obj->genericCmd) == TAKE) // Make sure not taking object in context!
+ Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoUse]);
+ else
+ return false;
+ } else if (isWordPresent(_vm._arrayVerbs[_vm._drop])) {
+ if (!obj->carriedFl && ((DROP & obj->genericCmd) == DROP))
+ Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBDontHave]);
+ else if (obj->carriedFl && ((DROP & obj->genericCmd) == DROP))
+ dropObject(obj);
+ else if (obj->cmdIndex == 0)
+ Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNeed]);
+ else
+ return false;
+ } else { // It was not a generic cmd
+ return false;
+ }
+
+ return true;
+}
+
+// Test whether hero is close to object. Return TRUE or FALSE
+// If object not near, return suitable comment; may be another object close
+// If radius is -1, treat radius as infinity
+// Verb is included to determine correct comment if not near
+bool Parser_v1w::isNear(object_t *obj, char *verb, char *comment) {
+ debugC(1, kDebugParser, "isNear(object_t *obj, %s, %s)", verb, comment);
+
+ if (obj->carriedFl) // Object is being carried
+ return true;
+
+ if (obj->screenIndex != *_vm._screen_p) {
+ // Not in same screen
+ if (obj->objValue)
+ strcpy(comment, _vm._textParser[kCmtAny1]);
+ else
+ strcpy(comment, _vm._textParser[kCmtAny2]);
+ return false;
+ }
+
+ if (obj->cycling == INVISIBLE) {
+ if (obj->seqNumb) {
+ // There is an image
+ strcpy(comment, _vm._textParser[kCmtAny3]);
+ return false;
+ } else {
+ // No image, assume visible
+ if ((obj->radius < 0) ||
+ ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
+ (abs(obj->y - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
+ return true;
+ } else {
+ // User is not close enough
+ if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
+ strcpy(comment, _vm._textParser[kCmtAny1]);
+ else
+ strcpy(comment, _vm._textParser[kCmtClose]);
+ return false;
+ }
+ }
+ }
+
+ if ((obj->radius < 0) ||
+ ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
+ (abs(obj->y + obj->currImagePtr->y2 - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
+ return true;
+ } else {
+ // User is not close enough
+ if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
+ strcpy(comment, _vm._textParser[kCmtAny1]);
+ else
+ strcpy(comment, _vm._textParser[kCmtClose]);
+ return false;
+ }
+ return true;
+}
+
+// Search for matching verbs in background command list.
+// Noun is not required. Return TRUE if match found
+// Note that if the background command list has match set TRUE then do not
+// print text if there are any recognizable nouns in the command line
+bool Parser_v1w::isCatchallVerb(objectList_t obj) {
+ debugC(1, kDebugParser, "isCatchallVerb(object_list_t obj)");
+
+ for (int i = 0; obj[i].verbIndex != 0; i++) {
+ if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) && obj[i].nounIndex == 0 &&
+ (!obj[i].matchFl || !findNoun()) &&
+ ((obj[i].roomState == DONT_CARE) ||
+ (obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) {
+ Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
+ _vm.scheduler().processBonus(obj[i].bonusIndex);
+
+ // If this is LOOK (without a noun), show any takeable objects
+ if (*(_vm._arrayVerbs[obj[i].verbIndex]) == _vm._arrayVerbs[_vm._look][0])
+ showTakeables();
+
+ return true;
+ }
+ }
+ return false;
+}
+
+// Search for matching verb/noun pairs in background command list
+// Print text for possible background object. Return TRUE if match found
+bool Parser_v1w::isBackgroundWord(objectList_t obj) {
+ debugC(1, kDebugParser, "isBackgroundWord(object_list_t obj)");
+
+ for (int i = 0; obj[i].verbIndex != 0; i++) {
+ if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) &&
+ isWordPresent(_vm._arrayNouns[obj[i].nounIndex]) &&
+ ((obj[i].roomState == DONT_CARE) ||
+ (obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) {
+ Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
+ _vm.scheduler().processBonus(obj[i].bonusIndex);
+ return true;
+ }
+ }
+ return false;
+}
+
// Parse the user's line of text input. Generate events as necessary
-void Parser::lineHandler() {
+void Parser_v1w::lineHandler() {
debugC(1, kDebugParser, "lineHandler");
status_t &gameStatus = _vm.getGameStatus();
@@ -349,105 +562,6 @@ void Parser::lineHandler() {
}
}
-// Search for matching verb/noun pairs in background command list
-// Print text for possible background object. Return TRUE if match found
-bool Parser::isBackgroundWord(objectList_t obj) {
- debugC(1, kDebugParser, "isBackgroundWord(object_list_t obj)");
-
- for (int i = 0; obj[i].verbIndex != 0; i++) {
- if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) &&
- isWordPresent(_vm._arrayNouns[obj[i].nounIndex]) &&
- ((obj[i].roomState == DONT_CARE) ||
- (obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) {
- Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
- _vm.scheduler().processBonus(obj[i].bonusIndex);
- return true;
- }
- }
- return false;
-}
-
-// Search for matching verbs in background command list.
-// Noun is not required. Return TRUE if match found
-// Note that if the background command list has match set TRUE then do not
-// print text if there are any recognizable nouns in the command line
-bool Parser::isCatchallVerb(objectList_t obj) {
- debugC(1, kDebugParser, "isCatchallVerb(object_list_t obj)");
-
- for (int i = 0; obj[i].verbIndex != 0; i++) {
- if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) && obj[i].nounIndex == 0 &&
- (!obj[i].matchFl || !findNoun()) &&
- ((obj[i].roomState == DONT_CARE) ||
- (obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) {
- Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
- _vm.scheduler().processBonus(obj[i].bonusIndex);
-
- // If this is LOOK (without a noun), show any takeable objects
- if (*(_vm._arrayVerbs[obj[i].verbIndex]) == _vm._arrayVerbs[_vm._look][0])
- showTakeables();
-
- return true;
- }
- }
- return false;
-}
-
-// Test whether hero is close to object. Return TRUE or FALSE
-// If object not near, return suitable comment; may be another object close
-// If radius is -1, treat radius as infinity
-// Verb is included to determine correct comment if not near
-bool Parser::isNear(object_t *obj, char *verb, char *comment) {
- debugC(1, kDebugParser, "isNear(object_t *obj, %s, %s)", verb, comment);
-
- if (obj->carriedFl) // Object is being carried
- return true;
-
- if (obj->screenIndex != *_vm._screen_p) {
- // Not in same screen
- if (obj->objValue)
- strcpy(comment, _vm._textParser[kCmtAny1]);
- else
- strcpy(comment, _vm._textParser[kCmtAny2]);
- return false;
- }
-
- if (obj->cycling == INVISIBLE) {
- if (obj->seqNumb) {
- // There is an image
- strcpy(comment, _vm._textParser[kCmtAny3]);
- return false;
- } else {
- // No image, assume visible
- if ((obj->radius < 0) ||
- ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
- (abs(obj->y - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
- return true;
- } else {
- // User is not close enough
- if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
- strcpy(comment, _vm._textParser[kCmtAny1]);
- else
- strcpy(comment, _vm._textParser[kCmtClose]);
- return false;
- }
- }
- }
-
- if ((obj->radius < 0) ||
- ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
- (abs(obj->y + obj->currImagePtr->y2 - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
- return true;
- } else {
- // User is not close enough
- if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
- strcpy(comment, _vm._textParser[kCmtAny1]);
- else
- strcpy(comment, _vm._textParser[kCmtClose]);
- return false;
- }
- return true;
-}
-
// Locate any member of object name list appearing in command line
bool Parser::isWordPresent(char **wordArr) {
debugC(1, kDebugParser, "isWordPresent(%s)", wordArr[0]);
@@ -494,8 +608,8 @@ void Parser::showTakeables() {
for (int j = 0; j < _vm._numObj; j++) {
object_t *obj = &_vm._objects[j];
if ((obj->cycling != INVISIBLE) &&
- (obj->screenIndex == *_vm._screen_p) &&
- (((TAKE & obj->genericCmd) == TAKE) || obj->objValue)) {
+ (obj->screenIndex == *_vm._screen_p) &&
+ (((TAKE & obj->genericCmd) == TAKE) || obj->objValue)) {
Utils::Box(BOX_ANY, "You can also see:\n%s.", _vm._arrayNouns[obj->nounIndex][LOOK_NAME]);
}
}
@@ -535,49 +649,168 @@ void Parser::dropObject(object_t *obj) {
Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBOk]);
}
-// Test whether command line contains one of the generic actions
-bool Parser::isGenericVerb(object_t *obj, char *comment) {
- debugC(1, kDebugParser, "isGenericVerb(object_t *obj, %s)", comment);
+// Return TRUE if object being carried by hero
+bool Parser::isCarrying(uint16 wordIndex) {
+ debugC(1, kDebugParser, "isCarrying(%d)", wordIndex);
- if (!obj->genericCmd)
+ for (int i = 0; i < _vm._numObj; i++) {
+ if ((wordIndex == _vm._objects[i].nounIndex) && _vm._objects[i].carriedFl)
+ return true;
+ }
+ return false;
+}
+
+void Parser::showDosInventory() {
+// Show user all objects being carried in a variable width 2 column format
+ static const char *blanks = " ";
+ uint16 index = 0, len1 = 0, len2 = 0;
+
+ for (int i = 0; i < _vm._numObj; i++) { // Find widths of 2 columns
+ if (_vm._objects[i].carriedFl) {
+ uint16 len = strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1]);
+ if (index++ & 1) // Right hand column
+ len2 = (len > len2) ? len : len2;
+ else
+ len1 = (len > len1) ? len : len1;
+ }
+ }
+ len1 += 1; // For gap between columns
+
+ if (len1 + len2 < (uint16)strlen(_vm._textParser[kTBOutro]))
+ len1 = strlen(_vm._textParser[kTBOutro]);
+
+ char buffer[XBYTES *NUM_ROWS] = "\0";
+ strncat(buffer, blanks, (len1 + len2 - strlen(_vm._textParser[kTBIntro])) / 2);
+ strcat(strcat(buffer, _vm._textParser[kTBIntro]), "\n");
+ index = 0;
+ for (int i = 0; i < _vm._numObj; i++) { // Assign strings
+ if (_vm._objects[i].carriedFl) {
+ if (index++ & 1)
+ strcat(strcat(buffer, _vm._arrayNouns[_vm._objects[i].nounIndex][1]), "\n");
+ else
+ strncat(strcat(buffer, _vm._arrayNouns[_vm._objects[i].nounIndex][1]), blanks, len1 - strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1]));
+ }
+ }
+ if (index & 1)
+ strcat(buffer, "\n");
+ strcat(buffer, _vm._textParser[kTBOutro]);
+
+ Utils::Box(BOX_ANY, "%s", buffer);
+}
+
+Parser_v1d::Parser_v1d(HugoEngine &vm) : Parser(vm) {
+}
+
+Parser_v1d::~Parser_v1d() {
+}
+
+// Locate word in list of nouns and return ptr to string in noun list
+// If n is NULL, start at beginning of list, else with n
+char *Parser_v1d::findNextNoun(char *n) {
+ int k = -1;
+ if (n) { // If n not NULL, find index
+ for (k = 0; _vm._arrayNouns[k]; k++) {
+ if (n == _vm._arrayNouns[k][0])
+ break;
+ }
+ }
+ for (int i = k + 1; _vm._arrayNouns[i]; i++) {
+ for (int j = 0; strlen(_vm._arrayNouns[i][j]); j++) {
+ if (strstr(_line, _vm._arrayNouns[i][j]))
+ return _vm._arrayNouns[i][0];
+ }
+ }
+ return 0;
+}
+
+// Test whether hero is close to object. Return TRUE or FALSE
+// If no noun specified, check context flag in object before other tests.
+// If object not near, return suitable string; may be similar object closer
+// If radius is -1, treat radius as infinity
+bool Parser_v1d::isNear(char *verb, char *noun, object_t *obj, char *comment) {
+ if (!noun && !obj->verbOnlyFl) { // No noun specified & object not context senesitive
+ return false;
+ } else if (noun && (noun != _vm._arrayNouns[obj->nounIndex][0])) { // Noun specified & not same as object
+ return false;
+ } else if (obj->carriedFl) { // Object is being carried
+ return true;
+ } else if (obj->screenIndex != *_vm._screen_p) { // Not in same screen
+ if (obj->objValue)
+ strcpy (comment, "You don't have it!");
return false;
+ }
- // Following is equivalent to switch, but couldn't do one
- if (isWordPresent(_vm._arrayVerbs[_vm._look]) && isNear(obj, _vm._arrayVerbs[_vm._look][0], comment)) {
- // Test state-dependent look before general look
- if ((obj->genericCmd & LOOK_S) == LOOK_S) {
- Utils::Box(BOX_ANY, "%s", _vm._textData[obj->stateDataIndex[obj->state]]);
- warning("isGenericVerb: use of state dependant look - To be validated");
- } else {
- if ((LOOK & obj->genericCmd) == LOOK) {
- if (_vm._textData[obj->dataIndex])
- Utils::Box(BOX_ANY, "%s", _vm._textData[obj->dataIndex]);
- else
- return false;
+ if (obj->cycling == INVISIBLE) {
+ if (obj->seqNumb) { // There is an image
+ strcpy(comment, "I don't see it anywhere");
+ return false;
+ } else { // No image, assume visible
+ if ((obj->radius < 0) ||
+ ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
+ (abs(obj->y - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
+ return true;
} else {
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBUnusual]);
+ // User is either not close enough (stationary, valueless objects)
+ // or is not carrying it (small, portable objects of value)
+ if (noun) { // Don't say unless object specified
+ if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
+ strcpy(comment, "You don't have it!");
+ else
+ strcpy(comment, "You're not close enough!");
+ }
+ return false;
}
}
- } else if (isWordPresent(_vm._arrayVerbs[_vm._take]) && isNear(obj, _vm._arrayVerbs[_vm._take][0], comment)) {
+ }
+
+ if ((obj->radius < 0) ||
+ ((abs(obj->x - _vm._hero->x) <= obj->radius) &&
+ (abs(obj->y + obj->currImagePtr->y2 - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius))) {
+ return true;
+ } else {
+ // User is either not close enough (stationary, valueless objects)
+ // or is not carrying it (small, portable objects of value)
+ if (noun) { // Don't say unless object specified
+ if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
+ strcpy(comment, "You don't have it!");
+ else
+ strcpy(comment, "You're not close enough!");
+ }
+ return false;
+ }
+
+ return true;
+}
+
+// Test whether supplied verb is one of the common variety for this object
+// say_ok needed for special case of take/drop which may be handled not only
+// here but also in a cmd_list with a donestr string simultaneously
+bool Parser_v1d::isGenericVerb(char *word, object_t *obj) {
+ if (!obj->genericCmd)
+ return false;
+
+ // Following is equivalent to switch, but couldn't do one
+ if (word == _vm._arrayVerbs[_vm._look][0]) {
+ if ((LOOK & obj->genericCmd) == LOOK)
+ Utils::Box(BOX_ANY, "%s", _vm._textData[obj->dataIndex]);
+ else
+ Utils::Box(BOX_ANY, "I see nothing special about it");
+ } else if (word == _vm._arrayVerbs[_vm._take][0]) {
if (obj->carriedFl)
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBHave]);
+ Utils::Box(BOX_ANY, "You already have it");
else if ((TAKE & obj->genericCmd) == TAKE)
takeObject(obj);
- else if (obj->cmdIndex != 0) // No comment if possible commands
- return false;
- else if (!obj->verbOnlyFl && (TAKE & obj->genericCmd) == TAKE) // Make sure not taking object in context!
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoUse]);
+ else if (!obj->verbOnlyFl) // Make sure not taking object in context!
+ Utils::Box(BOX_ANY, "It is of no use to you");
else
return false;
- } else if (isWordPresent(_vm._arrayVerbs[_vm._drop])) {
- if (!obj->carriedFl && ((DROP & obj->genericCmd) == DROP))
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBDontHave]);
- else if (obj->carriedFl && ((DROP & obj->genericCmd) == DROP))
+ } else if (word == _vm._arrayVerbs[_vm._drop][0]) {
+ if (!obj->carriedFl)
+ Utils::Box(BOX_ANY, "You don't have it");
+ else if ((DROP & obj->genericCmd) == DROP)
dropObject(obj);
- else if (obj->cmdIndex == 0)
- Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNeed]);
else
- return false;
+ Utils::Box(BOX_ANY, "No! You'll be needing it");
} else { // It was not a generic cmd
return false;
}
@@ -585,46 +818,31 @@ bool Parser::isGenericVerb(object_t *obj, char *comment) {
return true;
}
-// Return TRUE if object being carried by hero
-bool Parser::isCarrying(uint16 wordIndex) {
- debugC(1, kDebugParser, "isCarrying(%d)", wordIndex);
-
- for (int i = 0; i < _vm._numObj; i++) {
- if ((wordIndex == _vm._objects[i].nounIndex) && _vm._objects[i].carriedFl)
- return true;
- }
- return false;
-}
-
-// Test whether command line contains a verb allowed by this object.
-// If it does, and the object is near and passes the tests in the command
-// list then carry out the actions in the action list and return TRUE
-bool Parser::isObjectVerb(object_t *obj, char *comment) {
- debugC(1, kDebugParser, "isObjectVerb(object_t *obj, %s)", comment);
+// Test whether supplied verb is included in the list of allowed verbs for
+// this object. If it is, then perform the tests on it from the cmd list
+// and if it passes, perform the actions in the action list. If the verb
+// is catered for, return TRUE
+bool Parser_v1d::isObjectVerb(char *word, object_t *obj) {
+//actlist *actions;
// First, find matching verb in cmd list
uint16 cmdIndex = obj->cmdIndex; // ptr to list of commands
- if (cmdIndex == 0) // No commands for this obj
+ if (!cmdIndex) // No commands for this obj
return false;
int i;
- for (i = 0; _vm._cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd
- if (isWordPresent(_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex])) // Was this verb used?
+ for (i = 0; _vm._cmdList[cmdIndex][i].verbIndex != 0; i++) { // For each cmd
+ if (!strcmp(word, _vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex][0])) // Is this verb catered for?
break;
}
- if (_vm._cmdList[cmdIndex][i].verbIndex == 0) // No verbs used.
- return false;
-
- // Verb match found. Check if object is Near
- char *verb = *_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex];
- if (!isNear(obj, verb, comment))
+ if (_vm._cmdList[cmdIndex][i].verbIndex == 0) // No
return false;
- // Check all required objects are being carried
+ // Verb match found, check all required objects are being carried
cmd *cmnd = &_vm._cmdList[cmdIndex][i]; // ptr to struct cmd
if (cmnd->reqIndex) { // At least 1 thing in list
- uint16 *reqs = _vm._arrayReqs[cmnd->reqIndex]; // ptr to list of required objects
+ uint16 *reqs = _vm._arrayReqs[cmnd->reqIndex]; // ptr to list of required objects
for (i = 0; reqs[i]; i++) { // for each obj
if (!isCarrying(reqs[i])) {
Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataNoCarryIndex]);
@@ -634,7 +852,7 @@ bool Parser::isObjectVerb(object_t *obj, char *comment) {
}
// Required objects are present, now check state is correct
- if ((obj->state != cmnd->reqState) && (cmnd->reqState != DONT_CARE)) {
+ if ((obj->state != cmnd->reqState) && (cmnd->reqState != DONT_CARE)){
Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataWrongIndex]);
return true;
}
@@ -644,49 +862,211 @@ bool Parser::isObjectVerb(object_t *obj, char *comment) {
obj->state = cmnd->newState;
Utils::Box(BOX_ANY, "%s", _vm._textData[cmnd->textDataDoneIndex]);
_vm.scheduler().insertActionList(cmnd->actIndex);
-
- // See if any additional generic actions
- if ((verb == _vm._arrayVerbs[_vm._look][0]) || (verb == _vm._arrayVerbs[_vm._take][0]) || (verb == _vm._arrayVerbs[_vm._drop][0]))
- isGenericVerb(obj, comment);
+ // Special case if verb is Take or Drop. Assume additional generic actions
+ if ((word == _vm._arrayVerbs[_vm._take][0]) || (word == _vm._arrayVerbs[_vm._drop][0]))
+ isGenericVerb(word, obj);
return true;
}
-void Parser::showDosInventory() {
-// Show user all objects being carried in a variable width 2 column format
- static const char *blanks = " ";
- uint16 index = 0, len1 = 0, len2 = 0;
+// Print text for possible background object. Return TRUE if match found
+// Only match if both verb and noun found. Test_ca will match verb-only
+bool Parser_v1d::isBackgroundWord(char *noun, char *verb, objectList_t obj) {
+ if (!noun)
+ return false;
- for (int i = 0; i < _vm._numObj; i++) { // Find widths of 2 columns
- if (_vm._objects[i].carriedFl) {
- uint16 len = strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1]);
- if (index++ & 1) // Right hand column
- len2 = (len > len2) ? len : len2;
- else
- len1 = (len > len1) ? len : len1;
+ for (int i = 0; obj[i].verbIndex; i++) {
+ if ((verb == _vm._arrayVerbs[obj[i].verbIndex][0]) && (noun == _vm._arrayNouns[obj[i].nounIndex][0])) {
+ Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
+ return true;
}
}
- len1 += 1; // For gap between columns
+ return false;
+}
- if (len1 + len2 < (uint16)strlen(_vm._textParser[kTBOutro]))
- len1 = strlen(_vm._textParser[kTBOutro]);
+// Print text for possible background object. Return TRUE if match found
+// If test_noun TRUE, must have a noun given
+bool Parser_v1d::isCatchallVerb(bool test_noun, char *noun, char *verb, objectList_t obj) {
+ if (test_noun && !noun)
+ return false;
- char buffer[XBYTES *NUM_ROWS] = "\0";
- strncat(buffer, blanks, (len1 + len2 - strlen(_vm._textParser[kTBIntro])) / 2);
- strcat(strcat(buffer, _vm._textParser[kTBIntro]), "\n");
- index = 0;
- for (int i = 0; i < _vm._numObj; i++) { // Assign strings
- if (_vm._objects[i].carriedFl) {
- if (index++ & 1)
- strcat(strcat(buffer, _vm._arrayNouns[_vm._objects[i].nounIndex][1]), "\n");
- else
- strncat(strcat(buffer, _vm._arrayNouns[_vm._objects[i].nounIndex][1]), blanks, len1 - strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1]));
+ for (int i = 0; obj[i].verbIndex; i++) {
+ if ((verb == _vm._arrayVerbs[obj[i].verbIndex][0]) && ((noun == _vm._arrayNouns[obj[i].nounIndex][0]) || (obj[i].nounIndex == 0))) {
+ Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
+ return true;
}
}
- if (index & 1)
- strcat(buffer, "\n");
- strcat(buffer, _vm._textParser[kTBOutro]);
+ return false;
+}
- Utils::Box(BOX_ANY, "%s", buffer);
+// Parse the user's line of text input. Generate events as necessary
+void Parser_v1d::lineHandler() {
+ object_t *obj;
+ status_t &gameStatus = _vm.getGameStatus();
+ char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby
+
+// Reset_prompt_line ();
+ Utils::strlwr(_line); // Convert to lower case
+
+ if (!strcmp("exit", _line) || strstr(_line, "quit")) {
+ if (Utils::Box(BOX_YESNO, "Are you sure you want to QUIT?") != 0)
+ _vm.endGame();
+ else
+ return;
+ }
+
+ // SAVE/RESTORE
+ if (!strcmp("save", _line)) {
+ _config.soundFl = false;
+ if (gameStatus.gameOverFl)
+ Utils::gameOverMsg();
+ else
+// _vm.file().saveOrRestore(true);
+ warning("STUB: saveOrRestore()");
+ return;
+ }
+
+ if (!strcmp("restore", _line)) {
+ _config.soundFl = false;
+// _vm.file().saveOrRestore(false);
+ warning("STUB: saveOrRestore()");
+ return;
+ }
+
+ if (*_line == '\0') // Empty line
+ return;
+
+ if (strspn(_line, " ") == strlen(_line)) // Nothing but spaces!
+ return;
+
+ if (gameStatus.gameOverFl) { // No commands allowed!
+ Utils::gameOverMsg();
+ return;
+ }
+
+ // Find the first verb in the line
+ char *verb = findVerb();
+ char *noun = 0; // Noun not found yet
+
+ if (verb) { // OK, verb found. Try to match with object
+ do {
+ noun = findNextNoun(noun); // Find a noun in the line
+ // Must try at least once for objects allowing verb-context
+ for (int i = 0; i < _vm._numObj; i++) {
+ obj = &_vm._objects[i];
+ if (isNear(verb, noun, obj, farComment)) {
+ if (isObjectVerb(verb, obj) // Foreground object
+ || isGenericVerb(verb, obj)) // Common action type
+ return;
+ }
+ }
+ if ((*farComment == '\0') && isBackgroundWord(noun, verb, _vm._backgroundObjects[*_vm._screen_p]))
+ return;
+ } while (noun);
+ }
+ noun = findNextNoun(noun);
+ if (*farComment != '\0') // An object matched but not near enough
+ Utils::Box(BOX_ANY, "%s", farComment);
+ else if (!isCatchallVerb(true, noun, verb, _vm._catchallList) &&
+ !isCatchallVerb(false, noun, verb, _vm._backgroundObjects[*_vm._screen_p]) &&
+ !isCatchallVerb(false, noun, verb, _vm._catchallList))
+ Utils::Box(BOX_ANY, "Apparently our hero either doesn't\n"
+ "understand what you mean or doesn't\n"
+ "think that would be very useful!");
+}
+
+Parser_v2d::Parser_v2d(HugoEngine &vm) : Parser_v1d(vm) {
+}
+
+Parser_v2d::~Parser_v2d() {
+}
+
+// Parse the user's line of text input. Generate events as necessary
+void Parser_v2d::lineHandler() {
+ object_t *obj;
+ status_t &gameStatus = _vm.getGameStatus();
+ char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby
+
+// Reset_prompt_line ();
+ Utils::strlwr(_line); // Convert to lower case
+
+ if (!strcmp("exit", _line) || strstr(_line, "quit")) {
+ if (Utils::Box(BOX_YESNO, "Are you sure you want to QUIT?") != 0)
+ _vm.endGame();
+ else
+ return;
+ }
+
+ // SAVE/RESTORE
+ if (!strcmp("save", _line)) {
+ _config.soundFl = false;
+ if (gameStatus.gameOverFl)
+ Utils::gameOverMsg();
+ else
+// _vm.file().saveOrRestore(true);
+ warning("STUB: saveOrRestore()");
+ return;
+ }
+
+ if (!strcmp("restore", _line)) {
+ _config.soundFl = false;
+// _vm.file().saveOrRestore(false);
+ warning("STUB: saveOrRestore()");
+ return;
+ }
+
+ if (!strlen(_line)) // Empty line
+ return;
+
+ if (strspn(_line, " ") == strlen(_line)) // Nothing but spaces!
+ return;
+
+ if (gameStatus.gameOverFl) { // No commands allowed!
+ Utils::gameOverMsg();
+ return;
+ }
+
+ // Find the first verb in the line
+ char *verb = findVerb();
+ char *noun = 0; // Noun not found yet
+
+ if (verb) { // OK, verb found. Try to match with object
+ do {
+ noun = findNextNoun(noun); // Find a noun in the line
+ // Must try at least once for objects allowing verb-context
+ for (int i = 0; i < _vm._numObj; i++) {
+ obj = &_vm._objects[i];
+ if (isNear(verb, noun, obj, farComment)) {
+ if (isObjectVerb(verb, obj) // Foreground object
+ || isGenericVerb(verb, obj)) // Common action type
+ return;
+ }
+ }
+ if ((*farComment != '\0') && isBackgroundWord(noun, verb, _vm._backgroundObjects[*_vm._screen_p]))
+ return;
+ } while (noun);
+ }
+
+ noun = findNextNoun(noun);
+ if ( !isCatchallVerb(true, noun, verb, _vm._backgroundObjects[*_vm._screen_p])
+ && !isCatchallVerb(true, noun, verb, _vm._catchallList)
+ && !isCatchallVerb(false, noun, verb, _vm._backgroundObjects[*_vm._screen_p])
+ && !isCatchallVerb(false, noun, verb, _vm._catchallList)) {
+ if (*farComment != '\0') { // An object matched but not near enough
+ Utils::Box(BOX_ANY, "%s", farComment);
+ } else if (_maze.enabledFl && (verb == _vm._arrayVerbs[_vm._look][0])) {
+ Utils::Box(BOX_ANY, "You are in a maze of\n"
+ "twisty little paths,\n"
+ "which are all alike!");
+ showTakeables();
+ } else if (verb && noun) { // A combination I didn't think of
+ Utils::Box(BOX_ANY, "I don't think that would\n"
+ "accomplish much, somehow!");
+ } else if (verb || noun) {
+ Utils::Box(BOX_ANY, "I don't fully understand!");
+ } else {
+ Utils::Box(BOX_ANY, "I find that befuddling!");
+ }
+ }
}
} // End of namespace Hugo