diff options
| -rw-r--r-- | engines/sherlock/journal.cpp | 638 | ||||
| -rw-r--r-- | engines/sherlock/journal.h | 43 | ||||
| -rw-r--r-- | engines/sherlock/scalpel/scalpel_journal.cpp | 697 | ||||
| -rw-r--r-- | engines/sherlock/scalpel/scalpel_journal.h | 47 | ||||
| -rw-r--r-- | engines/sherlock/tattoo/tattoo_journal.cpp | 100 | ||||
| -rw-r--r-- | engines/sherlock/tattoo/tattoo_journal.h | 16 | ||||
| -rw-r--r-- | engines/sherlock/tattoo/tattoo_scene.cpp | 1 | 
7 files changed, 808 insertions, 734 deletions
diff --git a/engines/sherlock/journal.cpp b/engines/sherlock/journal.cpp index c7c6569205..665f0e59c5 100644 --- a/engines/sherlock/journal.cpp +++ b/engines/sherlock/journal.cpp @@ -37,4 +37,642 @@ Journal *Journal::init(SherlockEngine *vm) {  Journal::Journal(SherlockEngine *vm) : _vm(vm) {  } +bool Journal::drawJournal(int direction, int howFar) { +	Events &events = *_vm->_events; +	FixedText &fixedText = *_vm->_fixedText; +	Screen &screen = *_vm->_screen; +	Talk &talk = *_vm->_talk; +	int yp = 37; +	int startPage = _page; +	bool endJournal = false; +	bool firstOccurance = true; +	bool searchSuccessful = false; +	bool endFlag = false; +	int lineNum = 0; +	int savedIndex; +	int temp; +	const char *matchP; +	int width; + +	talk._converseNum = -1; +	_down = true; + +	do { +		// Get the number of lines for the current journal entry +		loadJournalFile(false); +		if (_lines.empty()) { +			// Entry has no text, so it must be a stealth eny. Move onto further journal entries +			// until an entry with text is found +			if (++_index == (int)_journal.size()) { +				endJournal = true; +			} else { +				_sub = 0; +				loadJournalFile(false); +			} +		} +	} while (!endJournal && _lines.empty()); + +	// Check if there no further pages with text until the end of the journal +	if (endJournal) { +		// If moving forward or backwards, clear the page before printing +		if (direction) +			drawJournalFrame(); + +		screen.gPrint(Common::Point(235, 21), PEN_COLOR, "Page %d", _page); +		return false; +	} + +	// If the journal page is being changed, set the wait cursor +	if (direction) +		events.setCursor(WAIT); + +	switch (direction) { +	case 1: +	case 4: +		// Move backwards howFar number of lines unless either the start of the journal is reached, +		// or a searched for keyword is found +		do { +			// Move backwards through the journal file a line at a time +			if (--_sub < 0) { +				do { +					if (--_index < 0) { +						_index = 0; +						_sub = 0; +						endJournal = true; +					} +					else { +						loadJournalFile(false); +						_sub = _lines.size() - 1; +					} +				} while (!endJournal && _lines.empty()); +			} + +			// If it's search mode, check each line for the given keyword +			if (direction >= 3 && !_lines.empty() && !endJournal && !searchSuccessful) { +				Common::String line = _lines[_sub]; +				line.toUppercase(); +				if (strstr(line.c_str(), _find.c_str()) != nullptr) { +					// Found a match. Reset howFar so that the start of page that the match +					// was found on will be displayed +					searchSuccessful = true; +					howFar = ((lineNum / LINES_PER_PAGE) + 1) * LINES_PER_PAGE; +				} +			} + +			++lineNum; +		} while (lineNum < howFar && !endJournal); + +		if (!_index && !_sub) +			_page = 1; +		else +			_page -= howFar / LINES_PER_PAGE; +		break; + +	case 2: +	case 3: +		// Move howFar lines ahead unless the end of the journal is reached, +		// or a searched for keyword is found +		for (temp = 0; (temp < (howFar / LINES_PER_PAGE)) && !endJournal && !searchSuccessful; ++temp) { +			// Handle animating mouse cursor +			int cursorNum = (int)events.getCursor() + 1; +			if (cursorNum >(WAIT + 2)) +				cursorNum = WAIT; +			events.setCursor((CursorId)cursorNum); + +			lineNum = 0; +			savedIndex = _index; +			int savedSub = _sub; + +			// Move a single page ahead +			do { +				// If in search mode, check for keyword +				if (direction >= 3 && _page != startPage) { +					Common::String line = _lines[_sub]; +					line.toUppercase(); +					if (strstr(line.c_str(), _find.c_str()) != nullptr) +						searchSuccessful = true; +				} + +				// Move forwards a line at a time, unless search word was found +				if (!searchSuccessful) { +					if (++_sub == (int)_lines.size()) { +						// Reached end of page +						do { +							if (++_index == (int)_journal.size()) { +								_index = savedIndex; +								_sub = savedSub; +								loadJournalFile(false); +								endJournal = true; +							} else { +								_sub = 0; +								loadJournalFile(false); +							} +						} while (!endJournal && _lines.empty()); +					} + +					++lineNum; +				} +			} while ((lineNum < LINES_PER_PAGE) && !endJournal && !searchSuccessful); + +			if (!endJournal && !searchSuccessful) +				// Move to next page +				++_page; + +			if (searchSuccessful) { +				// Search found, so show top of the page it was found on +				_index = savedIndex; +				_sub = savedSub; +				loadJournalFile(false); +			} +		} +		break; + +	default: +		break; +	} + +	if (direction) { +		events.setCursor(ARROW); +		drawJournalFrame(); +	} + +	Common::String fixedText_Page = fixedText.getText(kFixedText_Journal_Page); + +	screen.gPrint(Common::Point(235, 21), PEN_COLOR, fixedText_Page.c_str(), _page); + +	temp = _sub; +	savedIndex = _index; +	lineNum = 0; + +	do { +		bool inc = true; + +		// If there wasn't any line to print at the top of the page, we won't need to +		// increment the y position +		if (_lines[temp].empty() && yp == 37) +			inc = false; + +		// If there's a searched for keyword in the line, it will need to be highlighted +		if (searchSuccessful && firstOccurance) { +			// Check if line has the keyword +			Common::String line = _lines[temp]; +			line.toUppercase(); +			if ((matchP = strstr(line.c_str(), _find.c_str())) != nullptr) { +				matchP = _lines[temp].c_str() + (matchP - line.c_str()); +				firstOccurance = false; + +				// Print out the start of the line before the matching keyword +				Common::String lineStart(_lines[temp].c_str(), matchP); +				if (lineStart.hasPrefix("@")) { +					width = screen.stringWidth(lineStart.c_str() + 1); +					screen.gPrint(Common::Point(53, yp), 15, "%s", lineStart.c_str() + 1); +				} else { +					width = screen.stringWidth(lineStart.c_str()); +					screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", lineStart.c_str()); +				 } + +				// Print out the found keyword +				Common::String lineMatch(matchP, matchP + _find.size()); +				screen.gPrint(Common::Point(53 + width, yp), INV_FOREGROUND, "%s", lineMatch.c_str()); +				width += screen.stringWidth(lineMatch.c_str()); + +				// Print remainder of line +				screen.gPrint(Common::Point(53 + width, yp), PEN_COLOR, "%s", matchP + _find.size()); +			} else if (_lines[temp].hasPrefix("@")) { +				screen.gPrint(Common::Point(53, yp), 15, "%s", _lines[temp].c_str() + 1); +			} else { +				screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", _lines[temp].c_str()); +			} +		} else { +			if (_lines[temp].hasPrefix("@")) { +				screen.gPrint(Common::Point(53, yp), 15, "%s", _lines[temp].c_str() + 1); +			} else { +				screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", _lines[temp].c_str()); +			} +		} + +		if (++temp == (int)_lines.size()) { +			// Move to next page +			do { +				if (_index < ((int)_journal.size() - 1) && lineNum < (LINES_PER_PAGE - 1)) { +					++_index; +					loadJournalFile(false); +					temp = 0; +				} else { +					if (_index == ((int)_journal.size() - 1)) +						_down = false; +					endFlag = true; +				} +			} while (!endFlag && _lines.empty()); +		} + +		if (inc) { +			// Move to next line +			++lineNum; +			yp += 13; +		} +	} while (lineNum < LINES_PER_PAGE && !endFlag); + +	_index = savedIndex; +	_up = _index || _sub; + +	return direction >= 3 && searchSuccessful; +} + +void Journal::loadJournalFile(bool alreadyLoaded) { +	People &people = *_vm->_people; +	Screen &screen = *_vm->_screen; +	Talk &talk = *_vm->_talk; +	JournalEntry &journalEntry = _journal[_index]; +	const byte *opcodes = talk._opcodes; + +	Common::String dirFilename = _directory[journalEntry._converseNum]; +	bool replyOnly = journalEntry._replyOnly; + +	// Get the location number from within the filename +	Common::String locStr(dirFilename.c_str() + 4, dirFilename.c_str() + 6); +	int newLocation = atoi(locStr.c_str()); + +	// If not flagged as already loaded, load the conversation into script variables +	if (!alreadyLoaded) { +		// See if the file to be used is already loaded +		if (journalEntry._converseNum != talk._converseNum) { +			// Nope. Free any previously loaded talk +			talk.freeTalkVars(); + +			// Find the person being referred to +			talk._talkTo = -1; +			for (int idx = 0; idx < (int)people._characters.size(); ++idx) { +				Common::String portrait = people._characters[idx]._portrait; +				Common::String numStr(portrait.c_str(), portrait.c_str() + 4); + +				if (locStr == numStr) { +					talk._talkTo = idx; +					break; +				} +			} + +			// Load their talk file +			talk.loadTalkFile(dirFilename); +		} +	} + +	if (talk[0]._statement.hasPrefix("*") || talk[0]._statement.hasPrefix("^")) +		replyOnly = true; + +	// If this isn't the first journal entry, see if the previous journal entry +	// was in the same scene to see if we need to include the scene header +	int oldLocation = -1; +	if (_index != 0) { +		// Get the scene number of the prior journal entry +		Common::String priorEntry = _directory[_journal[_index - 1]._converseNum]; +		oldLocation = atoi(Common::String(priorEntry.c_str() + 4, priorEntry.c_str() + 6).c_str()); +	} + +	// Start building journal string +	Statement &statement = talk[journalEntry._statementNum]; +	Common::String journalString; + +	if (newLocation != oldLocation) { +		// Add in scene title +		journalString = "@"; +		if (IS_SERRATED_SCALPEL || newLocation - 1 < 100) +			journalString += _locations[newLocation - 1]; +		journalString += ":"; + +		// See if title can fit into a single line, or requires splitting on 2 lines +		int width = screen.stringWidth(journalString.c_str() + 1); +		if (width > JOURNAL_MAX_WIDTH) { +			// Scan backwards from end of title to find a space between a word +			// where the width is less than the maximum allowed for the line +			const char *lineP = journalString.c_str() + journalString.size() - 1; +			while (width > JOURNAL_MAX_WIDTH || *lineP != ' ') +				width -= screen.charWidth(*lineP--); + +			// Split the header into two lines, and add a '@' prefix +			// to the second line as well +			journalString = Common::String(journalString.c_str(), lineP) + "\n@" + +				Common::String(lineP + 1); +		} + +		// Add a newline at the end of the title +		journalString += '\n'; +	} + +	// If Holmes has something to say first, then take care of it +	if (!replyOnly) { +		// Handle the grammar +		journalString += "Holmes "; +		if (talk[journalEntry._statementNum]._statement.hasSuffix("?")) +			journalString += "asked "; +		else +			journalString += "said to "; + +		if (talk._talkTo == 1) { +			journalString += "me"; +		} else if ((talk._talkTo == 2 && IS_SERRATED_SCALPEL) || (talk._talkTo == 18 && IS_ROSE_TATTOO)) { +			journalString += "the Inspector"; +		} else { +			journalString += people._characters[talk._talkTo]._name; +		} +		journalString += ", \""; + +		// Add the statement +		journalString += statement._statement; +	} + +	// Handle including the reply +	bool startOfReply = true; +	bool ctrlSpace = false; +	bool commentFlag = false; +	bool commentJustPrinted = false; +	const byte *replyP = (const byte *)statement._reply.c_str(); +	const int inspectorId = (IS_SERRATED_SCALPEL) ? 2 : 18; + +	while (*replyP) { +		byte c = *replyP++; + +		if (IS_ROSE_TATTOO) { +			// Ignore commented out data +			if (c == '/' && *(replyP + 1) == '*') { +				replyP++;	// skip * +				while (*replyP++ != '*') {}	// empty loop on purpose +				replyP++;	// skip / +				c = *replyP; +			} +		} + +		// Is it a control character? +		if (c < opcodes[0]) { +			// Nope. Set flag for allowing control codes to insert spaces +			ctrlSpace = true; +			assert(c >= ' '); + +			// Check for embedded comments +			if (c == '{' || c == '}') { + +				// TODO: Rose Tattoo checks if no text was added for the last +				// comment here. In such a case, the last "XXX said" string is +				// removed here. + +				// Comment characters. If we're starting a comment and there's +				// already text displayed, add a closing quote +				if (c == '{' && !startOfReply && !commentJustPrinted) +					journalString += '"'; + +				// If a reply isn't just being started, and we didn't just end +				// a comment (which would have added a line), add a carriage return +				if (!startOfReply && ((!commentJustPrinted && c == '{') || c == '}')) +					journalString += '\n'; +				startOfReply = false; + +				// Handle setting or clearing comment state +				if (c == '{') { +					commentFlag = true; +					commentJustPrinted = false; +				} else { +					commentFlag = false; +					commentJustPrinted = true; +				} +			} else { +				if (startOfReply) { +					if (!replyOnly) { +						journalString += "\"\n"; + +						if (talk._talkTo == 1) +							journalString += "I replied, \""; +						else +							journalString += "The reply was, \""; +					} else { +						if (talk._talkTo == 1) +							journalString += "I"; +						else if (talk._talkTo == inspectorId) +							journalString += "The Inspector"; +						else +							journalString += people._characters[talk._talkTo]._name; + +						const byte *strP = replyP + 1; +						byte v; +						do { +							v = *strP++; +						} while (v && (v < opcodes[0]) && (v != '.') && (v != '!') && (v != '?')); + +						if (v == '?') +							journalString += " asked, \""; +						else +							journalString += " said, \""; +					} + +					startOfReply = false; +				} + +				// Copy text from the place until either the reply ends, a comment +				// {} block is started, or a control character is encountered +				journalString += c; +				do { +					journalString += *replyP++; +				} while (*replyP && *replyP < opcodes[0] && *replyP != '{' && *replyP != '}'); + +				commentJustPrinted = false; +			} +		} else if (c == opcodes[OP_SWITCH_SPEAKER]) { +			if (!startOfReply) { +				if (!commentFlag && !commentJustPrinted) +					journalString += "\"\n"; + +				journalString += "Then "; +				commentFlag = false; +			} else if (!replyOnly) { +				journalString += "\"\n"; +			} + +			startOfReply = false; +			c = *replyP++ - 1; +			if (IS_ROSE_TATTOO) +				replyP++; + +			if (c == 0) +				journalString += "Holmes"; +			else if (c == 1) +				journalString += "I"; +			else if (c == inspectorId) +				journalString += "the Inspector"; +			else +				journalString += people._characters[c]._name; + +			const byte *strP = replyP; +			byte v; +			do { +				v = *strP++; +			} while (v && v < opcodes[0] && v != '.' && v != '!' && v != '?'); + +			if (v == '?') +				journalString += " asked, \""; +			else +				journalString += " said, \""; +		} else { +			if (IS_SERRATED_SCALPEL) { +				// Control code, so move past it and any parameters +				if (c == opcodes[OP_RUN_CANIMATION] || +					c == opcodes[OP_ASSIGN_PORTRAIT_LOCATION] || +					c == opcodes[OP_PAUSE] || +					c == opcodes[OP_PAUSE_WITHOUT_CONTROL] || +					c == opcodes[OP_WALK_TO_CANIMATION]) { +					// These commands have a single parameter +					++replyP; +				} else if (c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) { +					replyP += (replyP[0] & 127) + replyP[1] + 2; +				} else if (c == opcodes[OP_WALK_TO_COORDS] || c == opcodes[OP_MOVE_MOUSE]) { +					replyP += 4; +				} else if (c == opcodes[OP_SET_FLAG] || c == opcodes[OP_IF_STATEMENT]) { +					replyP += 2; +				} else if (c == opcodes[OP_SFX_COMMAND] || c == opcodes[OP_PLAY_PROLOGUE] || +					c == opcodes[OP_CALL_TALK_FILE]) { +					replyP += 8; +					break; +				} else if ( +					c == opcodes[OP_TOGGLE_OBJECT] || +					c == opcodes[OP_ADD_ITEM_TO_INVENTORY] || +					c == opcodes[OP_SET_OBJECT] || +					c == opcodes[OP_DISPLAY_INFO_LINE] || +					c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) { +					replyP += (*replyP & 127) + 1; +				} else if (c == opcodes[OP_GOTO_SCENE]) { +					replyP += 5; +				} else if (c == opcodes[OP_CARRIAGE_RETURN]) { +					journalString += "\n"; +				} +			} else { +				if (c == opcodes[OP_RUN_CANIMATION] || +					c == opcodes[OP_PAUSE] || +					c == opcodes[OP_MOUSE_OFF_ON] || +					c == opcodes[OP_SET_WALK_CONTROL] || +					c == opcodes[OP_PAUSE_WITHOUT_CONTROL] || +					c == opcodes[OP_WALK_TO_CANIMATION] || +					c == opcodes[OP_TURN_NPC_OFF] || +					c == opcodes[OP_TURN_NPC_ON] || +					c == opcodes[OP_RESTORE_PEOPLE_SEQUENCE]) +					++replyP; +				else if ( +					c == opcodes[OP_SET_TALK_SEQUENCE] || +					c == opcodes[OP_SET_FLAG] || +					c == opcodes[OP_WALK_NPC_TO_CANIM] || +					c == opcodes[OP_WALK_HOLMES_AND_NPC_TO_CANIM] || +					c == opcodes[OP_NPC_PATH_LABEL] || +					c == opcodes[OP_PATH_GOTO_LABEL]) +					replyP += 2; +				else if ( +					c == opcodes[OP_SET_NPC_PATH_PAUSE] || +					c == opcodes[OP_NPC_PATH_PAUSE_TAKING_NOTES] || +					c == opcodes[OP_NPC_PATH_PAUSE_LOOKING_HOLMES] || +					c == opcodes[OP_NPC_VERB_CANIM]) +					replyP += 3; +				else if ( +					c == opcodes[OP_SET_SCENE_ENTRY_FLAG] || +					c == opcodes[OP_PATH_IF_FLAG_GOTO_LABEL]) +					replyP += 4; +				else if ( +					c == opcodes[OP_WALK_TO_COORDS]) +					replyP += 5; +				else if ( +					c == opcodes[OP_WALK_NPC_TO_COORDS] || +					c == opcodes[OP_GOTO_SCENE] || +					c == opcodes[OP_SET_NPC_PATH_DEST] || +					c == opcodes[OP_SET_NPC_POSITION]) +					replyP += 6; +				else if ( +					c == opcodes[OP_PLAY_SONG] || +					c == opcodes[OP_NEXT_SONG]) +					replyP += 8; +				else if ( +					c == opcodes[OP_CALL_TALK_FILE] || +					c == opcodes[OP_SET_NPC_TALK_FILE] || +					c == opcodes[OP_NPC_WALK_GRAPHICS]) +					replyP += 9; +				else if ( +					c == opcodes[OP_NPC_VERB_SCRIPT]) +					replyP += 10; +				else if ( +					c == opcodes[OP_WALK_HOLMES_AND_NPC_TO_COORDS]) +					replyP += 11; +				else if ( +					c == opcodes[OP_NPC_VERB] || +					c == opcodes[OP_NPC_VERB_TARGET]) +					replyP += 14; +				else if ( +					c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) +					replyP += (replyP[0] & 127) + replyP[1] + 2; +				else if ( +					c == opcodes[OP_TOGGLE_OBJECT] || +					c == opcodes[OP_ADD_ITEM_TO_INVENTORY] || +					c == opcodes[OP_SET_OBJECT] || +					c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) +					replyP += (*replyP & 127) + 1; +				else if ( +					c == opcodes[OP_END_TEXT_WINDOW]) { +					journalString += '\n'; +				} else if ( +					c == opcodes[OP_NPC_DESC_ON_OFF]) { +					replyP++; +					while (replyP[0] && replyP[0] != opcodes[OP_NPC_DESC_ON_OFF]) +						replyP++; +					replyP++; +				} else if ( +					c == opcodes[OP_SET_NPC_INFO_LINE]) +					replyP += replyP[1] + 2; +			} + +			// Put a space in the output for a control character, unless it's +			// immediately coming after another control character +			if (ctrlSpace && c != opcodes[OP_ASSIGN_PORTRAIT_LOCATION] && c != opcodes[OP_CARRIAGE_RETURN] &&  +					!commentJustPrinted) { +				journalString += " "; +				ctrlSpace = false; +			} +		} +	} + +	if (!startOfReply && !commentJustPrinted) +		journalString += '"'; + +	// Finally finished building the journal text. Need to process the text to +	// word wrap it to fit on-screen. The resulting lines are stored in the +	// _lines array +	_lines.clear(); + +	while (!journalString.empty()) { +		const char *startP = journalString.c_str(); + +		// If the first character is a '@' flagging a title line, then move +		// past it, so the @ won't be included in the line width calculation +		if (*startP == '@') +			++startP; + +		// Build up chacters until a full line is found +		int width = 0; +		const char *endP = startP; +		while (width < JOURNAL_MAX_WIDTH && *endP && *endP != '\n' && (endP - startP) < (JOURNAL_MAX_CHARS - 1)) +			width += screen.charWidth(*endP++); + +		// If word wrapping, move back to end of prior word +		if (width >= JOURNAL_MAX_WIDTH || (endP - startP) >= (JOURNAL_MAX_CHARS - 1)) { +			while (*--endP != ' ') +				; +		} + +		// Add in the line +		_lines.push_back(Common::String(journalString.c_str(), endP)); + +		// Strip line off from string being processed +		journalString = *endP ? Common::String(endP + 1) : ""; +	} + +	// Add a blank line at the end of the text as long as text was present +	if (!startOfReply) { +		_lines.push_back(""); +	} else { +		_lines.clear(); +	} +} +  } // End of namespace Sherlock diff --git a/engines/sherlock/journal.h b/engines/sherlock/journal.h index de07368c56..18bc54173f 100644 --- a/engines/sherlock/journal.h +++ b/engines/sherlock/journal.h @@ -32,18 +32,61 @@  namespace Sherlock { +#define LINES_PER_PAGE (IS_SERRATED_SCALPEL ? 11 : 17) +  class SherlockEngine; +struct JournalEntry { +	int _converseNum; +	bool _replyOnly; +	int _statementNum; + +	JournalEntry() : _converseNum(0), _replyOnly(false), _statementNum(0) {} +	JournalEntry(int converseNum, int statementNum, bool replyOnly = false) : +		_converseNum(converseNum), _statementNum(statementNum), _replyOnly(replyOnly) {} +}; +  class Journal { +private: +  protected:  	SherlockEngine *_vm; +	Common::StringArray _directory; +	Common::StringArray _locations; +	Common::Array<JournalEntry> _journal; +	Common::StringArray _lines; +	bool _up, _down; +	int _index; +	int _page; +	int _maxPage; +	int _sub; +	Common::String _find; +  	Journal(SherlockEngine *vm); + +	/** +	 * Loads the description for the current display index in the journal, and then +	 * word wraps the result to prepare it for being displayed +	 * @param alreadyLoaded		Indicates whether the journal file is being loaded for the +	 *		first time, or being reloaded +	 */ +	void loadJournalFile(bool alreadyLoaded);  public:  	static Journal *init(SherlockEngine *vm);  	virtual ~Journal() {}  	/** +	* Displays a page of the journal at the current index +	*/ +	bool drawJournal(int direction, int howFar); +public: +	/** +	 * Draw the journal background, frame, and interface buttons +	 */ +	virtual void drawJournalFrame() = 0; + +	/**  	 * Records statements that are said, in the order which they are said. The player  	 * can then read the journal to review them  	 */ diff --git a/engines/sherlock/scalpel/scalpel_journal.cpp b/engines/sherlock/scalpel/scalpel_journal.cpp index f7ef1e2272..fc517dcd72 100644 --- a/engines/sherlock/scalpel/scalpel_journal.cpp +++ b/engines/sherlock/scalpel/scalpel_journal.cpp @@ -30,7 +30,6 @@ namespace Sherlock {  namespace Scalpel {  #define JOURNAL_BUTTONS_Y 178 -#define LINES_PER_PAGE 11  #define JOURNAL_SEARCH_LEFT 15  #define JOURNAL_SEARCH_TOP 186  #define JOURNAL_SEARCH_RIGHT 296 @@ -105,14 +104,14 @@ void ScalpelJournal::loadJournalLocations() {  	Resources &res = *_vm->_res;  	_directory.clear(); +	_locations.clear(); +  	Common::SeekableReadStream *dir = res.load("talk.lib");  	dir->skip(4);		// Skip header  	// Get the numer of entries  	_directory.resize(dir->readUint16LE()); -	if (IS_ROSE_TATTOO) -		dir->seek((_directory.size() + 1) * 8, SEEK_CUR);  	// Read in each entry  	char buffer[17]; @@ -125,8 +124,6 @@ void ScalpelJournal::loadJournalLocations() {  	delete dir; -	_locations.clear(); -  	if (IS_3DO) {  		// 3DO: storage of locations is currently unknown TODO  		return; @@ -135,454 +132,18 @@ void ScalpelJournal::loadJournalLocations() {  	// Load in the locations stored in journal.txt  	Common::SeekableReadStream *loc = res.load("journal.txt"); -	if (IS_SERRATED_SCALPEL) { -		while (loc->pos() < loc->size()) { -			Common::String line; -			char c; -			while ((c = loc->readByte()) != 0) -				line += c; - -			_locations.push_back(line); -		} -	} else { -		// Initialize locations -		_locations.resize(100); -		for (int i = 0; i < 100; i++) -			_locations[i] = "No Description"; - -		while (loc->pos() < loc->size()) { -			// In Rose Tattoo, each location line starts with the location -			// number, followed by a dot, some spaces and its description -			// in quotes -			Common::String line = loc->readLine(); -			Common::String locNumStr; -			int locNum = 0; -			int i = 0; -			Common::String locDesc; - -			// Get the location -			while (Common::isDigit(line[i])) { -				locNumStr += line[i]; -				i++; -			} -			locNum = atoi(locNumStr.c_str()); - -			// Skip the dot, spaces and initial quotation mark -			while (line[i] == ' ' || line[i] == '.' || line[i] == '\"') -				i++; - -			do { -				locDesc += line[i]; -				i++; -			} while (line[i] != '\"'); +	while (loc->pos() < loc->size()) { +		Common::String line; +		char c; +		while ((c = loc->readByte()) != 0) +			line += c; -			_locations[locNum] = locDesc; -		} +		_locations.push_back(line);  	}  	delete loc;  } -void ScalpelJournal::loadJournalFile(bool alreadyLoaded) { -	People &people = *_vm->_people; -	Screen &screen = *_vm->_screen; -	Talk &talk = *_vm->_talk; -	JournalEntry &journalEntry = _journal[_index]; -	const byte *opcodes = talk._opcodes; - -	Common::String dirFilename = _directory[journalEntry._converseNum]; -	bool replyOnly = journalEntry._replyOnly; - -	// Get the location number from within the filename -	Common::String locStr(dirFilename.c_str() + 4, dirFilename.c_str() + 6); -	int newLocation = atoi(locStr.c_str()); - -	// If not flagged as already loaded, load the conversation into script variables -	if (!alreadyLoaded) { -		// See if the file to be used is already loaded -		if (journalEntry._converseNum != talk._converseNum) { -			// Nope. Free any previously loaded talk -			talk.freeTalkVars(); - -			// Find the person being referred to -			talk._talkTo = -1; -			for (int idx = 0; idx < (int)people._characters.size(); ++idx) { -				Common::String portrait = people._characters[idx]._portrait; -				Common::String numStr(portrait.c_str(), portrait.c_str() + 4); - -				if (locStr == numStr) { -					talk._talkTo = idx; -					break; -				} -			} - -			// Load their talk file -			talk.loadTalkFile(dirFilename); -		} -	} - -	if (talk[0]._statement.hasPrefix("*") || talk[0]._statement.hasPrefix("^")) -		replyOnly = true; - -	// If this isn't the first journal entry, see if the previous journal entry -	// was in the same scene to see if we need to include the scene header -	int oldLocation = -1; -	if (_index != 0) { -		// Get the scene number of the prior journal entry -		Common::String priorEntry = _directory[_journal[_index - 1]._converseNum]; -		oldLocation = atoi(Common::String(priorEntry.c_str() + 4, priorEntry.c_str() + 6).c_str()); -	} - -	// Start building journal string -	Statement &statement = talk[journalEntry._statementNum]; -	Common::String journalString; - -	if (newLocation != oldLocation) { -		// Add in scene title -		journalString = "@"; -		if (IS_SERRATED_SCALPEL || newLocation - 1 < 100) -			journalString += _locations[newLocation - 1]; -		journalString += ":"; - -		// See if title can fit into a single line, or requires splitting on 2 lines -		int width = screen.stringWidth(journalString.c_str() + 1); -		if (width > JOURNAL_MAX_WIDTH) { -			// Scan backwards from end of title to find a space between a word -			// where the width is less than the maximum allowed for the line -			const char *lineP = journalString.c_str() + journalString.size() - 1; -			while (width > JOURNAL_MAX_WIDTH || *lineP != ' ') -				width -= screen.charWidth(*lineP--); - -			// Split the header into two lines, and add a '@' prefix -			// to the second line as well -			journalString = Common::String(journalString.c_str(), lineP) + "\n@" + -				Common::String(lineP + 1); -		} - -		// Add a newline at the end of the title -		journalString += '\n'; -	} - -	// If Holmes has something to say first, then take care of it -	if (!replyOnly) { -		// Handle the grammar -		journalString += "Holmes "; -		if (talk[journalEntry._statementNum]._statement.hasSuffix("?")) -			journalString += "asked "; -		else -			journalString += "said to "; - -		switch (talk._talkTo) { -		case 1: -			journalString += "me"; -			break; -		case 2: -			journalString += "the Inspector"; -			break; -		default: -			journalString += people._characters[talk._talkTo]._name; -			break; -		} -		journalString += ", \""; - -		// Add the statement -		journalString += statement._statement; -	} - -	// Handle including the reply -	bool startOfReply = true; -	bool ctrlSpace = false; -	bool commentFlag = false; -	bool commentJustPrinted = false; -	const byte *replyP = (const byte *)statement._reply.c_str(); -	const int inspectorId = (IS_SERRATED_SCALPEL) ? 2 : 18; - -	while (*replyP) { -		byte c = *replyP++; - -		if (IS_ROSE_TATTOO) { -			// Ignore commented out data -			if (c == '/' && *(replyP + 1) == '*') { -				replyP++;	// skip * -				while (*replyP++ != '*') {}	// empty loop on purpose -				replyP++;	// skip / -				c = *replyP; -			} -		} - -		// Is it a control character? -		if (c < opcodes[0]) { -			// Nope. Set flag for allowing control codes to insert spaces -			ctrlSpace = true; -			assert(c >= ' '); - -			// Check for embedded comments -			if (c == '{' || c == '}') { - -				// TODO: Rose Tattoo checks if no text was added for the last -				// comment here. In such a case, the last "XXX said" string is -				// removed here. - -				// Comment characters. If we're starting a comment and there's -				// already text displayed, add a closing quote -				if (c == '{' && !startOfReply && !commentJustPrinted) -					journalString += '"'; - -				// If a reply isn't just being started, and we didn't just end -				// a comment (which would have added a line), add a carriage return -				if (!startOfReply && ((!commentJustPrinted && c == '{') || c == '}')) -					journalString += '\n'; -				startOfReply = false; - -				// Handle setting or clearing comment state -				if (c == '{') { -					commentFlag = true; -					commentJustPrinted = false; -				} else { -					commentFlag = false; -					commentJustPrinted = true; -				} -			} else { -				if (startOfReply) { -					if (!replyOnly) { -						journalString += "\"\n"; - -						if (talk._talkTo == 1) -							journalString += "I replied, \""; -						else -							journalString += "The reply was, \""; -					} else { -						if (talk._talkTo == 1) -							journalString += "I"; -						else if (talk._talkTo == inspectorId) -							journalString += "The Inspector"; -						else -							journalString += people._characters[talk._talkTo]._name; - -						const byte *strP = replyP + 1; -						byte v; -						do { -							v = *strP++; -						} while (v && (v < opcodes[0]) && (v != '.') && (v != '!') && (v != '?')); - -						if (v == '?') -							journalString += " asked, \""; -						else -							journalString += " said, \""; -					} - -					startOfReply = false; -				} - -				// Copy text from the place until either the reply ends, a comment -				// {} block is started, or a control character is encountered -				journalString += c; -				do { -					journalString += *replyP++; -				} while (*replyP && *replyP < opcodes[0] && *replyP != '{' && *replyP != '}'); - -				commentJustPrinted = false; -			} -		} else if (c == opcodes[OP_SWITCH_SPEAKER]) { -			if (!startOfReply) { -				if (!commentFlag && !commentJustPrinted) -					journalString += "\"\n"; - -				journalString += "Then "; -				commentFlag = false; -			} else if (!replyOnly) { -				journalString += "\"\n"; -			} - -			startOfReply = false; -			c = *replyP++ - 1; -			if (IS_ROSE_TATTOO) -				replyP++; - -			if (c == 0) -				journalString += "Holmes"; -			else if (c == 1) -				journalString += "I"; -			else if (c == inspectorId) -				journalString += "the Inspector"; -			else -				journalString += people._characters[c]._name; - -			const byte *strP = replyP; -			byte v; -			do { -				v = *strP++; -			} while (v && v < opcodes[0] && v != '.' && v != '!' && v != '?'); - -			if (v == '?') -				journalString += " asked, \""; -			else -				journalString += " said, \""; -		} else { -			if (IS_SERRATED_SCALPEL) { -				// Control code, so move past it and any parameters -				if (c == opcodes[OP_RUN_CANIMATION] || -					c == opcodes[OP_ASSIGN_PORTRAIT_LOCATION] || -					c == opcodes[OP_PAUSE] || -					c == opcodes[OP_PAUSE_WITHOUT_CONTROL] || -					c == opcodes[OP_WALK_TO_CANIMATION]) { -					// These commands have a single parameter -					++replyP; -				} else if (c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) { -					replyP += (replyP[0] & 127) + replyP[1] + 2; -				} else if (c == opcodes[OP_WALK_TO_COORDS] || c == opcodes[OP_MOVE_MOUSE]) { -					replyP += 4; -				} else if (c == opcodes[OP_SET_FLAG] || c == opcodes[OP_IF_STATEMENT]) { -					replyP += 2; -				} else if (c == opcodes[OP_SFX_COMMAND] || c == opcodes[OP_PLAY_PROLOGUE] || -					c == opcodes[OP_CALL_TALK_FILE]) { -					replyP += 8; -					break; -				} else if ( -					c == opcodes[OP_TOGGLE_OBJECT] || -					c == opcodes[OP_ADD_ITEM_TO_INVENTORY] || -					c == opcodes[OP_SET_OBJECT] || -					c == opcodes[OP_DISPLAY_INFO_LINE] || -					c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) { -					replyP += (*replyP & 127) + 1; -				} else if (c == opcodes[OP_GOTO_SCENE]) { -					replyP += 5; -				} else if (c == opcodes[OP_CARRIAGE_RETURN]) { -					journalString += "\n"; -				} -			} else { -				if (c == opcodes[OP_RUN_CANIMATION] || -					c == opcodes[OP_PAUSE] || -					c == opcodes[OP_MOUSE_OFF_ON] || -					c == opcodes[OP_SET_WALK_CONTROL] || -					c == opcodes[OP_PAUSE_WITHOUT_CONTROL] || -					c == opcodes[OP_WALK_TO_CANIMATION] || -					c == opcodes[OP_TURN_NPC_OFF] || -					c == opcodes[OP_TURN_NPC_ON] || -					c == opcodes[OP_RESTORE_PEOPLE_SEQUENCE]) -					++replyP; -				else if ( -					c == opcodes[OP_SET_TALK_SEQUENCE] || -					c == opcodes[OP_SET_FLAG] || -					c == opcodes[OP_WALK_NPC_TO_CANIM] || -					c == opcodes[OP_WALK_HOLMES_AND_NPC_TO_CANIM] || -					c == opcodes[OP_NPC_PATH_LABEL] || -					c == opcodes[OP_PATH_GOTO_LABEL]) -					replyP += 2; -				else if ( -					c == opcodes[OP_SET_NPC_PATH_PAUSE] || -					c == opcodes[OP_NPC_PATH_PAUSE_TAKING_NOTES] || -					c == opcodes[OP_NPC_PATH_PAUSE_LOOKING_HOLMES] || -					c == opcodes[OP_NPC_VERB_CANIM]) -					replyP += 3; -				else if ( -					c == opcodes[OP_SET_SCENE_ENTRY_FLAG] || -					c == opcodes[OP_PATH_IF_FLAG_GOTO_LABEL]) -					replyP += 4; -				else if ( -					c == opcodes[OP_WALK_TO_COORDS]) -					replyP += 5; -				else if ( -					c == opcodes[OP_WALK_NPC_TO_COORDS] || -					c == opcodes[OP_GOTO_SCENE] || -					c == opcodes[OP_SET_NPC_PATH_DEST] || -					c == opcodes[OP_SET_NPC_POSITION]) -					replyP += 6; -				else if ( -					c == opcodes[OP_PLAY_SONG] || -					c == opcodes[OP_NEXT_SONG]) -					replyP += 8; -				else if ( -					c == opcodes[OP_CALL_TALK_FILE] || -					c == opcodes[OP_SET_NPC_TALK_FILE] || -					c == opcodes[OP_NPC_WALK_GRAPHICS]) -					replyP += 9; -				else if ( -					c == opcodes[OP_NPC_VERB_SCRIPT]) -					replyP += 10; -				else if ( -					c == opcodes[OP_WALK_HOLMES_AND_NPC_TO_COORDS]) -					replyP += 11; -				else if ( -					c == opcodes[OP_NPC_VERB] || -					c == opcodes[OP_NPC_VERB_TARGET]) -					replyP += 14; -				else if ( -					c == opcodes[OP_ADJUST_OBJ_SEQUENCE]) -					replyP += (replyP[0] & 127) + replyP[1] + 2; -				else if ( -					c == opcodes[OP_TOGGLE_OBJECT] || -					c == opcodes[OP_ADD_ITEM_TO_INVENTORY] || -					c == opcodes[OP_SET_OBJECT] || -					c == opcodes[OP_REMOVE_ITEM_FROM_INVENTORY]) -					replyP += (*replyP & 127) + 1; -				else if ( -					c == opcodes[OP_END_TEXT_WINDOW]) { -					journalString += '\n'; -				} else if ( -					c == opcodes[OP_NPC_DESC_ON_OFF]) { -					replyP++; -					while (replyP[0] && replyP[0] != opcodes[OP_NPC_DESC_ON_OFF]) -						replyP++; -					replyP++; -				} else if ( -					c == opcodes[OP_SET_NPC_INFO_LINE]) -					replyP += replyP[1] + 2; -			} - -			// Put a space in the output for a control character, unless it's -			// immediately coming after another control character -			if (ctrlSpace && c != opcodes[OP_ASSIGN_PORTRAIT_LOCATION] && c != opcodes[OP_CARRIAGE_RETURN] &&  -					!commentJustPrinted) { -				journalString += " "; -				ctrlSpace = false; -			} -		} -	} - -	if (!startOfReply && !commentJustPrinted) -		journalString += '"'; - -	// Finally finished building the journal text. Need to process the text to -	// word wrap it to fit on-screen. The resulting lines are stored in the -	// _lines array -	_lines.clear(); - -	while (!journalString.empty()) { -		const char *startP = journalString.c_str(); - -		// If the first character is a '@' flagging a title line, then move -		// past it, so the @ won't be included in the line width calculation -		if (*startP == '@') -			++startP; - -		// Build up chacters until a full line is found -		int width = 0; -		const char *endP = startP; -		while (width < JOURNAL_MAX_WIDTH && *endP && *endP != '\n' && (endP - startP) < (JOURNAL_MAX_CHARS - 1)) -			width += screen.charWidth(*endP++); - -		// If word wrapping, move back to end of prior word -		if (width >= JOURNAL_MAX_WIDTH || (endP - startP) >= (JOURNAL_MAX_CHARS - 1)) { -			while (*--endP != ' ') -				; -		} - -		// Add in the line -		_lines.push_back(Common::String(journalString.c_str(), endP)); - -		// Strip line off from string being processed -		journalString = *endP ? Common::String(endP + 1) : ""; -	} - -	// Add a blank line at the end of the text as long as text was present -	if (!startOfReply) { -		_lines.push_back(""); -	} else { -		_lines.clear(); -	} -} -  void ScalpelJournal::drawJournalFrame() {  	FixedText &fixedText = *_vm->_fixedText;  	Resources &res = *_vm->_res; @@ -697,248 +258,6 @@ void ScalpelJournal::doArrows() {  	screen.buttonPrint(Common::Point(JOURNAL_POINTS[6][2], JOURNAL_BUTTONS_Y + 11), color, false, fixedText_FirstPage);  } -bool ScalpelJournal::drawJournal(int direction, int howFar) { -	Events &events = *_vm->_events; -	FixedText &fixedText = *_vm->_fixedText; -	Screen &screen = *_vm->_screen; -	Talk &talk = *_vm->_talk; -	int yp = 37; -	int startPage = _page; -	bool endJournal = false; -	bool firstOccurance = true; -	bool searchSuccessful = false; -	bool endFlag = false; -	int lineNum = 0; -	int savedIndex; -	int temp; -	const char *matchP; -	int width; - -	talk._converseNum = -1; -	_down = true; - -	do { -		// Get the number of lines for the current journal entry -		loadJournalFile(false); -		if (_lines.empty()) { -			// Entry has no text, so it must be a stealth eny. Move onto further journal entries -			// until an entry with text is found -			if (++_index == (int)_journal.size()) { -				endJournal = true; -			} else { -				_sub = 0; -				loadJournalFile(false); -			} -		} -	} while (!endJournal && _lines.empty()); - -	// Check if there no further pages with text until the end of the journal -	if (endJournal) { -		// If moving forward or backwards, clear the page before printing -		if (direction) -			drawJournalFrame(); - -		screen.gPrint(Common::Point(235, 21), PEN_COLOR, "Page %d", _page); -		return false; -	} - -	// If the journal page is being changed, set the wait cursor -	if (direction) -		events.setCursor(WAIT); - -	switch (direction) { -	case 1: -	case 4: -		// Move backwards howFar number of lines unless either the start of the journal is reached, -		// or a searched for keyword is found -		do { -			// Move backwards through the journal file a line at a time -			if (--_sub < 0) { -				do { -					if (--_index < 0) { -						_index = 0; -						_sub = 0; -						endJournal = true; -					} -					else { -						loadJournalFile(false); -						_sub = _lines.size() - 1; -					} -				} while (!endJournal && _lines.empty()); -			} - -			// If it's search mode, check each line for the given keyword -			if (direction >= 3 && !_lines.empty() && !endJournal && !searchSuccessful) { -				Common::String line = _lines[_sub]; -				line.toUppercase(); -				if (strstr(line.c_str(), _find.c_str()) != nullptr) { -					// Found a match. Reset howFar so that the start of page that the match -					// was found on will be displayed -					searchSuccessful = true; -					howFar = ((lineNum / LINES_PER_PAGE) + 1) * LINES_PER_PAGE; -				} -			} - -			++lineNum; -		} while (lineNum < howFar && !endJournal); - -		if (!_index && !_sub) -			_page = 1; -		else -			_page -= howFar / LINES_PER_PAGE; -		break; - -	case 2: -	case 3: -		// Move howFar lines ahead unless the end of the journal is reached, -		// or a searched for keyword is found -		for (temp = 0; (temp < (howFar / LINES_PER_PAGE)) && !endJournal && !searchSuccessful; ++temp) { -			// Handle animating mouse cursor -			int cursorNum = (int)events.getCursor() + 1; -			if (cursorNum >(WAIT + 2)) -				cursorNum = WAIT; -			events.setCursor((CursorId)cursorNum); - -			lineNum = 0; -			savedIndex = _index; -			int savedSub = _sub; - -			// Move a single page ahead -			do { -				// If in search mode, check for keyword -				if (direction >= 3 && _page != startPage) { -					Common::String line = _lines[_sub]; -					line.toUppercase(); -					if (strstr(line.c_str(), _find.c_str()) != nullptr) -						searchSuccessful = true; -				} - -				// Move forwards a line at a time, unless search word was found -				if (!searchSuccessful) { -					if (++_sub == (int)_lines.size()) { -						// Reached end of page -						do { -							if (++_index == (int)_journal.size()) { -								_index = savedIndex; -								_sub = savedSub; -								loadJournalFile(false); -								endJournal = true; -							} else { -								_sub = 0; -								loadJournalFile(false); -							} -						} while (!endJournal && _lines.empty()); -					} - -					++lineNum; -				} -			} while ((lineNum < LINES_PER_PAGE) && !endJournal && !searchSuccessful); - -			if (!endJournal && !searchSuccessful) -				// Move to next page -				++_page; - -			if (searchSuccessful) { -				// Search found, so show top of the page it was found on -				_index = savedIndex; -				_sub = savedSub; -				loadJournalFile(false); -			} -		} -		break; - -	default: -		break; -	} - -	if (direction) { -		events.setCursor(ARROW); -		drawJournalFrame(); -	} - -	Common::String fixedText_Page = fixedText.getText(kFixedText_Journal_Page); - -	screen.gPrint(Common::Point(235, 21), PEN_COLOR, fixedText_Page.c_str(), _page); - -	temp = _sub; -	savedIndex = _index; -	lineNum = 0; - -	do { -		bool inc = true; - -		// If there wasn't any line to print at the top of the page, we won't need to -		// increment the y position -		if (_lines[temp].empty() && yp == 37) -			inc = false; - -		// If there's a searched for keyword in the line, it will need to be highlighted -		if (searchSuccessful && firstOccurance) { -			// Check if line has the keyword -			Common::String line = _lines[temp]; -			line.toUppercase(); -			if ((matchP = strstr(line.c_str(), _find.c_str())) != nullptr) { -				matchP = _lines[temp].c_str() + (matchP - line.c_str()); -				firstOccurance = false; - -				// Print out the start of the line before the matching keyword -				Common::String lineStart(_lines[temp].c_str(), matchP); -				if (lineStart.hasPrefix("@")) { -					width = screen.stringWidth(lineStart.c_str() + 1); -					screen.gPrint(Common::Point(53, yp), 15, "%s", lineStart.c_str() + 1); -				} else { -					width = screen.stringWidth(lineStart.c_str()); -					screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", lineStart.c_str()); -				 } - -				// Print out the found keyword -				Common::String lineMatch(matchP, matchP + _find.size()); -				screen.gPrint(Common::Point(53 + width, yp), INV_FOREGROUND, "%s", lineMatch.c_str()); -				width += screen.stringWidth(lineMatch.c_str()); - -				// Print remainder of line -				screen.gPrint(Common::Point(53 + width, yp), PEN_COLOR, "%s", matchP + _find.size()); -			} else if (_lines[temp].hasPrefix("@")) { -				screen.gPrint(Common::Point(53, yp), 15, "%s", _lines[temp].c_str() + 1); -			} else { -				screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", _lines[temp].c_str()); -			} -		} else { -			if (_lines[temp].hasPrefix("@")) { -				screen.gPrint(Common::Point(53, yp), 15, "%s", _lines[temp].c_str() + 1); -			} else { -				screen.gPrint(Common::Point(53, yp), PEN_COLOR, "%s", _lines[temp].c_str()); -			} -		} - -		if (++temp == (int)_lines.size()) { -			// Move to next page -			do { -				if (_index < ((int)_journal.size() - 1) && lineNum < (LINES_PER_PAGE - 1)) { -					++_index; -					loadJournalFile(false); -					temp = 0; -				} else { -					if (_index == ((int)_journal.size() - 1)) -						_down = false; -					endFlag = true; -				} -			} while (!endFlag && _lines.empty()); -		} - -		if (inc) { -			// Move to next line -			++lineNum; -			yp += 13; -		} -	} while (lineNum < LINES_PER_PAGE && !endFlag); - -	_index = savedIndex; -	_up = _index || _sub; - -	return direction >= 3 && searchSuccessful; -} -  JournalButton ScalpelJournal::getHighlightedButton(const Common::Point &pt) {  	if (pt.x > JOURNAL_POINTS[0][0] && pt.x < JOURNAL_POINTS[0][1] && pt.y >= JOURNAL_BUTTONS_Y &&  			pt.y < (JOURNAL_BUTTONS_Y + 10)) diff --git a/engines/sherlock/scalpel/scalpel_journal.h b/engines/sherlock/scalpel/scalpel_journal.h index ba2c828e3f..fdf92819e7 100644 --- a/engines/sherlock/scalpel/scalpel_journal.h +++ b/engines/sherlock/scalpel/scalpel_journal.h @@ -43,64 +43,24 @@ enum JournalButton {  	BTN_FIRST_PAGE, BTN_LAST_PAGE, BTN_PRINT_TEXT  }; - -struct JournalEntry { -	int _converseNum; -	bool _replyOnly; -	int _statementNum; - -	JournalEntry() : _converseNum(0), _replyOnly(false), _statementNum(0) {} -	JournalEntry(int converseNum, int statementNum, bool replyOnly = false) : -		_converseNum(converseNum), _statementNum(statementNum), _replyOnly(replyOnly) {} -}; -  class ScalpelJournal: public Journal {  private: -	Common::Array<JournalEntry> _journal; -	Common::StringArray _directory; -	Common::StringArray _locations; -	Common::StringArray _lines; -	int _maxPage; -	int _index; -	int _sub; -	bool _up, _down; -	int _page; -	Common::String _find; -  	/** -	 * Load the list of location names that the journal will make reference to +	 * Load the list of journal locations  	 */  	void loadJournalLocations();  	/** -	 * Loads the description for the current display index in the journal, and then -	 * word wraps the result to prepare it for being displayed -	 * @param alreadyLoaded		Indicates whether the journal file is being loaded for the -	 *		first time, or being reloaded -	 */ -	void loadJournalFile(bool alreadyLoaded); - -	/**  	 * Display the arrows that can be used to scroll up and down pages  	 */  	void doArrows();  	/** -	 * Displays a page of the journal at the current index -	 */ -	bool drawJournal(int direction, int howFar); - -	/**  	 * Show the search submenu and allow the player to enter a search string  	 */  	int getSearchString(bool printError);  	/** -	 * Draw the journal background, frame, and interface buttons -	 */ -	void drawJournalFrame(); - -	/**  	 * Returns the button, if any, that is under the specified position  	 */  	JournalButton getHighlightedButton(const Common::Point &pt); @@ -117,6 +77,11 @@ public:  	 * Handle events whilst the journal is being displayed  	 */  	bool handleEvents(int key); +public: +	/** +	 * Draw the journal background, frame, and interface buttons +	 */ +	virtual void drawJournalFrame();  	/**  	 * Records statements that are said, in the order which they are said. The player diff --git a/engines/sherlock/tattoo/tattoo_journal.cpp b/engines/sherlock/tattoo/tattoo_journal.cpp index 380f6efc54..104e2a8bfe 100644 --- a/engines/sherlock/tattoo/tattoo_journal.cpp +++ b/engines/sherlock/tattoo/tattoo_journal.cpp @@ -29,32 +29,126 @@ namespace Sherlock {  namespace Tattoo { +#define JOURNAL_BAR_WIDTH	450 +  TattooJournal::TattooJournal(SherlockEngine *vm) : Journal(vm) {  	_journalImages = nullptr; + +	loadJournalLocations();  }  void TattooJournal::show() {  	Resources &res = *_vm->_res;  	Screen &screen = *_vm->_screen;  	TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui; +	byte palette[PALETTE_SIZE];  	// Load journal images  	_journalImages = new ImageFile("journal.vgs");  	// Load palette  	Common::SeekableReadStream *stream = res.load("journal.pal"); -	stream->read(screen._tMap, PALETTE_SIZE); -	screen.translatePalette(screen._tMap); -	ui.setupBGArea(screen._tMap); +	stream->read(palette, PALETTE_SIZE); +	screen.translatePalette(palette); +	ui.setupBGArea(palette); + +	// Set screen to black, and set background +	screen._backBuffer1.blitFrom((*_journalImages)[0], Common::Point(0, 0)); +	screen.empty(); +	screen.setPalette(palette); + +	if (_journal.empty()) { +		_up = _down = false; +	} else { +		drawJournal(0, 0); +	} +	// TODO +	// Free the images  	delete _journalImages;  } +void TattooJournal::loadJournalLocations() { +	Resources &res = *_vm->_res; + +	_directory.clear(); +	_locations.clear(); + +	Common::SeekableReadStream *dir = res.load("talk.lib"); +	dir->skip(4);		// Skip header + +	// Get the numer of entries +	_directory.resize(dir->readUint16LE()); +	dir->seek((_directory.size() + 1) * 8, SEEK_CUR); + +	// Read in each entry +	char buffer[17]; +	for (uint idx = 0; idx < _directory.size(); ++idx) { +		dir->read(buffer, 17); +		buffer[16] = '\0'; + +		_directory[idx] = Common::String(buffer); +	} + +	delete dir; + +	// Load in the locations stored in journal.txt +	Common::SeekableReadStream *loc = res.load("journal.txt"); + +	// Initialize locations +	_locations.resize(100); +	for (int idx = 0; idx < 100; ++idx) +		_locations[idx] = "No Description"; + +	while (loc->pos() < loc->size()) { +		// In Rose Tattoo, each location line starts with the location +		// number, followed by a dot, some spaces and its description +		// in quotes +		Common::String line = loc->readLine(); +		Common::String locNumStr; +		int locNum = 0; +		int i = 0; +		Common::String locDesc; + +		// Get the location +		while (Common::isDigit(line[i])) { +			locNumStr += line[i]; +			i++; +		} +		locNum = atoi(locNumStr.c_str()); + +		// Skip the dot, spaces and initial quotation mark +		while (line[i] == ' ' || line[i] == '.' || line[i] == '\"') +			i++; + +		do { +			locDesc += line[i]; +			i++; +		} while (line[i] != '\"'); + +		_locations[locNum] = locDesc; +	} + +	delete loc; +} + +void TattooJournal::drawJournalFrame() { +	Screen &screen = *_vm->_screen; + +	screen._backBuffer1.blitFrom((*_journalImages)[0], Common::Point(0, 0)); +	drawJournalControls(0); + +} +  void TattooJournal::synchronize(Serializer &s) {  	// TODO  } +void TattooJournal::drawJournalControls(int mode) { +	// TODO +} +  } // End of namespace Tattoo  } // End of namespace Sherlock diff --git a/engines/sherlock/tattoo/tattoo_journal.h b/engines/sherlock/tattoo/tattoo_journal.h index db70c290fc..b0898bcfd1 100644 --- a/engines/sherlock/tattoo/tattoo_journal.h +++ b/engines/sherlock/tattoo/tattoo_journal.h @@ -33,6 +33,17 @@ namespace Tattoo {  class TattooJournal : public Journal {  private:  	ImageFile *_journalImages; + +	/** +	 * Load the list of journal locations +	 */ +	void loadJournalLocations(); + +	/** +	 * Displays the controls used by the journal +	 * @param mode	0: Normal journal buttons, 1: Search interface +	 */ +	void drawJournalControls(int mode);  public:  	TattooJournal(SherlockEngine *vm);  	virtual ~TattooJournal() {} @@ -41,6 +52,11 @@ public:  	 * Show the journal  	 */  	void show(); +public: +	/** +	 * Draw the journal background, frame, and interface buttons +	 */ +	virtual void drawJournalFrame();  	/**  	 * Synchronize the data for a savegame diff --git a/engines/sherlock/tattoo/tattoo_scene.cpp b/engines/sherlock/tattoo/tattoo_scene.cpp index 4dabc178ab..1c6f9263e9 100644 --- a/engines/sherlock/tattoo/tattoo_scene.cpp +++ b/engines/sherlock/tattoo/tattoo_scene.cpp @@ -368,7 +368,6 @@ void TattooScene::doBgAnim() {  void TattooScene::doBgAnimUpdateBgObjectsAndAnim() {  	People &people = *_vm->_people; -	Screen &screen = *_vm->_screen;  	TattooUserInterface &ui = *(TattooUserInterface *)_vm->_ui;  	for (uint idx = 0; idx < _bgShapes.size(); ++idx) {  | 
