[Scummvm-cvs-logs] SF.net SVN: scummvm:[53106] scummvm/trunk/engines/hugo

strangerke at users.sourceforge.net strangerke at users.sourceforge.net
Sun Oct 10 09:43:43 CEST 2010


Revision: 53106
          http://scummvm.svn.sourceforge.net/scummvm/?rev=53106&view=rev
Author:   strangerke
Date:     2010-10-10 07:43:42 +0000 (Sun, 10 Oct 2010)

Log Message:
-----------
HUGO: New parser for H1 Dos and H2 Dos.

Add specific parser functions for H1 Dos and H2 Dos

Modified Paths:
--------------
    scummvm/trunk/engines/hugo/hugo.cpp
    scummvm/trunk/engines/hugo/hugo.h
    scummvm/trunk/engines/hugo/parser.cpp
    scummvm/trunk/engines/hugo/parser.h

Modified: scummvm/trunk/engines/hugo/hugo.cpp
===================================================================
--- scummvm/trunk/engines/hugo/hugo.cpp	2010-10-10 07:43:12 UTC (rev 53105)
+++ scummvm/trunk/engines/hugo/hugo.cpp	2010-10-10 07:43:42 UTC (rev 53106)
@@ -154,7 +154,6 @@
 
 	_mouseHandler = new MouseHandler(*this);
 	_inventoryHandler = new InventoryHandler(*this);
-	_parser = new Parser(*this);
 	_route = new Route(*this);
 	_soundHandler = new SoundHandler(*this);
 
@@ -164,36 +163,42 @@
 		_scheduler = new Scheduler_v3d(*this);
 		_introHandler = new intro_v1w(*this);
 		_screen = new Screen_v1w(*this);
+		_parser = new Parser_v1w(*this);
 		break;
 	case 1:
 		_fileManager = new FileManager_v2d(*this);
 		_scheduler = new Scheduler_v3d(*this);
 		_introHandler = new intro_v2w(*this);
 		_screen = new Screen_v1w(*this);
+		_parser = new Parser_v1w(*this);
 		break;
 	case 2:
 		_fileManager = new FileManager_v2d(*this);
 		_scheduler = new Scheduler_v3d(*this);
 		_introHandler = new intro_v3w(*this);
 		_screen = new Screen_v1w(*this);
+		_parser = new Parser_v1w(*this);
 		break;
 	case 3: // H1 DOS
 		_fileManager = new FileManager_v1d(*this);
 		_scheduler = new Scheduler_v1d(*this);
 		_introHandler = new intro_v1d(*this);
 		_screen = new Screen_v1d(*this);
+		_parser = new Parser_v1d(*this);
 		break;
 	case 4:
 		_fileManager = new FileManager_v2d(*this);
 		_scheduler = new Scheduler_v1d(*this);
 		_introHandler = new intro_v2d(*this);
 		_screen = new Screen_v1d(*this);
+		_parser = new Parser_v2d(*this);
 		break;
 	case 5:
 		_fileManager = new FileManager_v3d(*this);
 		_scheduler = new Scheduler_v3d(*this);
 		_introHandler = new intro_v3d(*this);
 		_screen = new Screen_v1d(*this);
+		_parser = new Parser_v1w(*this);
 		break;
 	}
 

Modified: scummvm/trunk/engines/hugo/hugo.h
===================================================================
--- scummvm/trunk/engines/hugo/hugo.h	2010-10-10 07:43:12 UTC (rev 53105)
+++ scummvm/trunk/engines/hugo/hugo.h	2010-10-10 07:43:42 UTC (rev 53106)
@@ -33,7 +33,7 @@
 #include "hugo/game.h"
 
 #define HUGO_DAT_VER_MAJ 0  // 1 byte
-#define HUGO_DAT_VER_MIN 23 // 1 byte
+#define HUGO_DAT_VER_MIN 24 // 1 byte
 #define DATAALIGNMENT 4
 
 namespace Common {

Modified: scummvm/trunk/engines/hugo/parser.cpp
===================================================================
--- scummvm/trunk/engines/hugo/parser.cpp	2010-10-10 07:43:12 UTC (rev 53105)
+++ scummvm/trunk/engines/hugo/parser.cpp	2010-10-10 07:43:42 UTC (rev 53106)
@@ -56,6 +56,9 @@
 	_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 @@
 	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 @@
 	}
 }
 
-// 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 @@
 	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 @@
 	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 @@
 	return true;
 }
 
-// Return TRUE if object being carried by hero
-bool Parser::isCarrying(uint16 wordIndex) {
-	debugC(1, kDebugParser, "isCarrying(%d)", wordIndex);
+// 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;
 
-	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);
-
 	// 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.
+	if (_vm._cmdList[cmdIndex][i].verbIndex == 0)   // No
 		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
+	// 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 @@
 	}
 
 	// 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 @@
 		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

Modified: scummvm/trunk/engines/hugo/parser.h
===================================================================
--- scummvm/trunk/engines/hugo/parser.h	2010-10-10 07:43:12 UTC (rev 53105)
+++ scummvm/trunk/engines/hugo/parser.h	2010-10-10 07:43:42 UTC (rev 53106)
@@ -44,39 +44,77 @@
 class Parser {
 public:
 	Parser(HugoEngine &vm);
+	virtual ~Parser();
 
 	bool  isWordPresent(char **wordArr);
 
 	void  charHandler();
 	void  command(const char *format, ...);
 	void  keyHandler(uint16 nChar, uint16 nFlags);
-	void  lineHandler();
+	virtual void lineHandler() = 0;
 
 protected:
 	HugoEngine &_vm;
 
+protected:
+	bool  isCarrying(uint16 wordIndex);
+
+	char *findNoun();
+	char *findVerb();
+
+	void  dropObject(object_t *obj);
+	void  takeObject(object_t *obj);
+	void  showTakeables();
+
 private:
 	char   _ringBuffer[32];                         // Ring buffer
 	uint16 _putIndex;
 	uint16 _getIndex;                               // Index into ring buffer
 	bool   _checkDoubleF1Fl;                        // Flag used to display user help or instructions
 
+	void  showDosInventory();
+};
+
+class Parser_v1w : public Parser {
+public:
+	Parser_v1w(HugoEngine &vm);
+	~Parser_v1w();
+
+	virtual void  lineHandler();
+
+private:
 	bool  isBackgroundWord(objectList_t obj);
-	bool  isCarrying(uint16 wordIndex);
 	bool  isCatchallVerb(objectList_t obj);
 	bool  isGenericVerb(object_t *obj, char *comment);
 	bool  isNear(object_t *obj, char *verb, char *comment);
 	bool  isObjectVerb(object_t *obj, char *comment);
+};
 
-	char *findNoun();
-	char *findVerb();
+class Parser_v1d : public Parser {
+public:
+	Parser_v1d(HugoEngine &vm);
+	~Parser_v1d();
 
-	void  dropObject(object_t *obj);
-	void  showDosInventory();
-	void  showTakeables();
-	void  takeObject(object_t *obj);
+	void lineHandler();
+
+protected:
+	char *findNextNoun(char *noun);
+	bool isNear(char *verb, char *noun, object_t *obj, char *comment);
+	bool isGenericVerb(char *word, object_t *obj);
+	bool isObjectVerb(char *word, object_t *obj);
+	bool isBackgroundWord(char *noun, char *verb, objectList_t obj);
+	bool isCatchallVerb(bool test_noun, char *noun, char *verb, objectList_t obj);
+
 };
 
+class Parser_v2d : public Parser_v1d {
+public:
+	Parser_v2d(HugoEngine &vm);
+	~Parser_v2d();
+
+	void lineHandler();
+};
+	
 } // End of namespace Hugo
 
 #endif //HUGO_PARSER_H


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list