aboutsummaryrefslogtreecommitdiff
path: root/engines/hugo/parser_v3d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/hugo/parser_v3d.cpp')
-rw-r--r--engines/hugo/parser_v3d.cpp251
1 files changed, 250 insertions, 1 deletions
diff --git a/engines/hugo/parser_v3d.cpp b/engines/hugo/parser_v3d.cpp
index ca78307a44..c78af20ef3 100644
--- a/engines/hugo/parser_v3d.cpp
+++ b/engines/hugo/parser_v3d.cpp
@@ -44,7 +44,7 @@
namespace Hugo {
-Parser_v3d::Parser_v3d(HugoEngine *vm) : Parser_v1w(vm) {
+Parser_v3d::Parser_v3d(HugoEngine *vm) : Parser(vm) {
}
Parser_v3d::~Parser_v3d() {
@@ -204,4 +204,253 @@ void Parser_v3d::lineHandler() {
}
}
+/**
+* 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_v3d::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 (!_vm->_object->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_v3d::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]]);
+ } 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_v3d::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;
+}
+
+/**
+* Do all things necessary to carry an object
+*/
+void Parser_v3d::takeObject(object_t *obj) {
+ debugC(1, kDebugParser, "takeObject(object_t *obj)");
+
+ obj->carriedFl = true;
+ if (obj->seqNumb) { // Don't change if no image to display
+ obj->cycling = INVISIBLE;
+ }
+ _vm->adjustScore(obj->objValue);
+
+ if (obj->seqNumb > 0) // If object has an image, force walk to dropped
+ obj->viewx = -1; // (possibly moved) object next time taken!
+ Utils::Box(BOX_ANY, TAKE_TEXT, _vm->_arrayNouns[obj->nounIndex][TAKE_NAME]);
+}
+
+/**
+* Do all necessary things to drop an object
+*/
+void Parser_v3d::dropObject(object_t *obj) {
+ debugC(1, kDebugParser, "dropObject(object_t *obj)");
+
+ obj->carriedFl = false;
+ obj->screenIndex = *_vm->_screen_p;
+ if ((obj->seqNumb > 1) || (obj->seqList[0].imageNbr > 1))
+ obj->cycling = CYCLE_FORWARD;
+ else
+ obj->cycling = NOT_CYCLING;
+ obj->x = _vm->_hero->x - 1;
+ obj->y = _vm->_hero->y + _vm->_hero->currImagePtr->y2 - 1;
+ obj->y = (obj->y + obj->currImagePtr->y2 < YPIX) ? obj->y : YPIX - obj->currImagePtr->y2 - 10;
+ _vm->adjustScore(-obj->objValue);
+ Utils::Box(BOX_ANY, "%s", _vm->_textParser[kTBOk]);
+}
+
+/**
+* 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_v3d::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])
+ _vm->_object->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_v3d::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;
+}
+
} // End of namespace Hugo