1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /*
24  * This code is based on Labyrinth of Time code with assistance of
25  *
26  * Copyright (c) 1993 Terra Nova Development
27  * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
28  *
29  */
30 
31 #include "common/file.h"
32 
33 #include "lab/lab.h"
34 
35 #include "lab/anim.h"
36 #include "lab/dispman.h"
37 #include "lab/eventman.h"
38 #include "lab/image.h"
39 #include "lab/interface.h"
40 #include "lab/labsets.h"
41 #include "lab/music.h"
42 #include "lab/processroom.h"
43 #include "lab/resource.h"
44 #include "lab/utils.h"
45 
46 namespace Lab {
47 
doNotes()48 void LabEngine::doNotes() {
49 	TextFont *noteFont = _resource->getFont("F:Note.fon");
50 	Common::String noteText = _resource->getText("Lab:Rooms/Notes");
51 
52 	Common::Rect textRect = Common::Rect(_utils->vgaScaleX(25) + _utils->svgaCord(15), _utils->vgaScaleY(50), _utils->vgaScaleX(295) - _utils->svgaCord(15), _utils->vgaScaleY(148));
53 	_graphics->flowText(noteFont, -2 + _utils->svgaCord(1), 0, 0, false, false, true, true, textRect, noteText.c_str());
54 	_graphics->setPalette(_anim->_diffPalette, 256);
55 	_graphics->freeFont(&noteFont);
56 }
57 
doWestPaper()58 void LabEngine::doWestPaper() {
59 	TextFont *paperFont = _resource->getFont("F:News22.fon");
60 	Common::String paperText = _resource->getText("Lab:Rooms/Date");
61 
62 	Common::Rect textRect = Common::Rect(_utils->vgaScaleX(57), _utils->vgaScaleY(77) + _utils->svgaCord(2), _utils->vgaScaleX(262), _utils->vgaScaleY(91));
63 	_graphics->flowText(paperFont, 0, 0, 0, false, true, false, true, textRect, paperText.c_str());
64 	_graphics->freeFont(&paperFont);
65 
66 	paperFont = _resource->getFont("F:News32.fon");
67 	paperText = _resource->getText("Lab:Rooms/Headline");
68 
69 	int fileLen = paperText.size() - 1;
70 	textRect = Common::Rect(_utils->vgaScaleX(57), _utils->vgaScaleY(86) - _utils->svgaCord(2), _utils->vgaScaleX(262), _utils->vgaScaleY(118));
71 	int charsPrinted = _graphics->flowText(paperFont, -8, 0, 0, false, true, false, true, textRect, paperText.c_str());
72 
73 	uint16 y;
74 
75 	if (charsPrinted < fileLen) {
76 		y = 130 - _utils->svgaCord(5);
77 		textRect = Common::Rect(_utils->vgaScaleX(57), _utils->vgaScaleY(86) - _utils->svgaCord(2), _utils->vgaScaleX(262), _utils->vgaScaleY(132));
78 		_graphics->flowText(paperFont, -8 - _utils->svgaCord(1), 0, 0, false, true, false, true, textRect, paperText.c_str());
79 	} else
80 		y = 115 - _utils->svgaCord(5);
81 
82 	_graphics->freeFont(&paperFont);
83 
84 	paperFont = _resource->getFont("F:Note.fon");
85 	paperText = _resource->getText("Lab:Rooms/Col1");
86 	_graphics->flowText(paperFont, -4, 0, 0, false, false, false, true, _utils->vgaRectScale(45, y, 158, 148), paperText.c_str());
87 
88 	paperText = _resource->getText("Lab:Rooms/Col2");
89 	_graphics->flowText(paperFont, -4, 0, 0, false, false, false, true, _utils->vgaRectScale(162, y, 275, 148), paperText.c_str());
90 
91 	_graphics->freeFont(&paperFont);
92 	_graphics->setPalette(_anim->_diffPalette, 256);
93 }
94 
loadJournalData()95 void LabEngine::loadJournalData() {
96 	if (_journalFont)
97 		_graphics->freeFont(&_journalFont);
98 
99 	_journalFont = _resource->getFont("F:Journal.fon");
100 	updateEvents();
101 
102 	Common::String filename = "Lab:Rooms/j";
103 
104 	bool bridge = _conditions->in(kCondBridge0) || _conditions->in(kCondBridge1);
105 	bool dirty  = _conditions->in(kCondDirty);
106 	bool news   = !_conditions->in(kCondNoNews);
107 	bool clean  = !_conditions->in(kCondNoClean);
108 
109 	if (bridge && clean && news)
110 		filename += '8';
111 	else if (clean && news)
112 		filename += '9';
113 	else if (bridge && clean)
114 		filename += '6';
115 	else if (clean)
116 		filename += '7';
117 	else if (bridge && dirty && news)
118 		filename += '4';
119 	else if (dirty && news)
120 		filename += '5';
121 	else if (bridge && dirty)
122 		filename += '2';
123 	else if (dirty)
124 		filename += '3';
125 	else if (bridge)
126 		filename += '1';
127 	else
128 		filename += '0';
129 
130 	_journalText = _resource->getText(filename);
131 	_journalTextTitle = _resource->getText("Lab:Rooms/jt");
132 
133 	Common::File *journalFile = _resource->openDataFile("P:JImage");
134 	_journalButtonList.push_back(_interface->createButton( 80, _utils->vgaScaleY(162) + _utils->svgaCord(1), 0,  Common::KEYCODE_LEFT,  new Image(journalFile, this), new Image(journalFile, this)));	// back
135 	_journalButtonList.push_back(_interface->createButton(194, _utils->vgaScaleY(162) + _utils->svgaCord(1), 2,  Common::KEYCODE_RIGHT, new Image(journalFile, this), new Image(journalFile, this)));	// forward
136 	_journalButtonList.push_back(_interface->createButton(144, _utils->vgaScaleY(164) - _utils->svgaCord(1), 1, Common::KEYCODE_ESCAPE, new Image(journalFile, this), new Image(journalFile, this)));	// cancel
137 	delete journalFile;
138 
139 	_anim->_noPalChange = true;
140 	_journalBackImage->setData(new byte[_graphics->_screenBytesPerPage]);
141 	_graphics->readPict("P:Journal.pic", true, false, _journalBackImage->_imageData);
142 	_anim->_noPalChange = false;
143 
144 	// Keep a copy of the blank journal
145 	_blankJournal = new byte[_graphics->_screenBytesPerPage];
146 	memcpy(_blankJournal, _journalBackImage->_imageData, _graphics->_screenBytesPerPage);
147 }
148 
drawJournalText()149 void LabEngine::drawJournalText() {
150 	uint16 drawingToPage = 1;
151 	const char *curText = _journalText.c_str();
152 
153 	assert((_journalPage & 1) == 0);
154 
155 	while (drawingToPage < _journalPage) {
156 		updateEvents();
157 
158 		// flowText without output
159 		curText += _graphics->flowText(_journalFont, -2, 2, 0, false, false, false, false, _utils->vgaRectScale(52, 32, 152, 148), curText);
160 
161 		_lastPage = (*curText == 0);
162 
163 		if (_lastPage) {
164 			// Reset _journalPage to this page, in case it was set too high
165 			_journalPage = (drawingToPage / 2) * 2;
166 			break;
167 		}
168 
169 		drawingToPage++;
170 	}
171 
172 	if (_journalPage == 0) {
173 		// draw title page centered
174 		_graphics->flowText(_journalFont, -2, 2, 0, false, true, true, true, _utils->vgaRectScale(52, 32, 152, 148), _journalTextTitle.c_str(), _journalBackImage);
175 	} else {
176 		curText += _graphics->flowText(_journalFont, -2, 2, 0, false, false, false, true, _utils->vgaRectScale(52, 32, 152, 148), curText, _journalBackImage);
177 	}
178 
179 	updateEvents();
180 	curText += _graphics->flowText(_journalFont, -2, 2, 0, false, false, false, true, _utils->vgaRectScale(171, 32, 271, 148), curText, _journalBackImage);
181 
182 	_lastPage = (*curText == 0);
183 }
184 
turnPage(bool fromLeft)185 void LabEngine::turnPage(bool fromLeft) {
186 	if (fromLeft) {
187 		for (int i = 0; i < _graphics->_screenWidth; i += 8) {
188 			updateEvents();
189 			waitTOF();
190 			_journalBackImage->blitBitmap(i, 0, nullptr, i, 0, 8, _graphics->_screenHeight, false);
191 		}
192 	} else {
193 		for (int i = (_graphics->_screenWidth - 8); i > 0; i -= 8) {
194 			updateEvents();
195 			waitTOF();
196 			_journalBackImage->blitBitmap(i, 0, nullptr, i, 0, 8, _graphics->_screenHeight, false);
197 		}
198 	}
199 }
200 
drawJournal(uint16 wipenum,bool needFade)201 void LabEngine::drawJournal(uint16 wipenum, bool needFade) {
202 	_event->mouseHide();
203 	updateEvents();
204 	drawJournalText();
205 	_graphics->loadBackPict("P:Journal.pic", _highPalette);
206 
207 	if (wipenum == 0)
208 		_journalBackImage->blitBitmap(0, 0, nullptr, 0, 0, _graphics->_screenWidth, _graphics->_screenHeight, false);
209 	else
210 		turnPage((wipenum == 1));
211 
212 	_interface->toggleButton(_interface->getButton(0), 15, (_journalPage > 0));	// back button
213 	_interface->toggleButton(_interface->getButton(2), 15, (!_lastPage));	// forward button
214 
215 	if (needFade)
216 		_graphics->fade(true);
217 
218 	// Reset the journal background, so that all the text that has been blitted on it is erased
219 	memcpy(_journalBackImage->_imageData, _blankJournal, _graphics->_screenBytesPerPage);
220 
221 	eatMessages();
222 	_event->mouseShow();
223 }
224 
processJournal()225 void LabEngine::processJournal() {
226 	while (1) {
227 		IntuiMessage *msg = _event->getMsg();
228 		if (shouldQuit()) {
229 			_quitLab = true;
230 			return;
231 		}
232 
233 		updateEvents();
234 		_graphics->screenUpdate();
235 		_system->delayMillis(10);
236 
237 		if (!msg)
238 			continue;
239 
240 		MessageClass msgClass  = msg->_msgClass;
241 
242 		if ((msgClass == kMessageRightClick) ||
243 			((msgClass == kMessageRawKey) && (msg->_code == Common::KEYCODE_ESCAPE)))
244 			return;
245 		else if (msgClass == kMessageButtonUp) {
246 			uint16 buttonId  = msg->_code;
247 			if (buttonId == 0) {
248 				if (_journalPage >= 2) {
249 					_journalPage -= 2;
250 					drawJournal(1, false);
251 				}
252 			} else if (buttonId == 1) {
253 				return;
254 			} else if (buttonId == 2) {
255 				if (!_lastPage) {
256 					_journalPage += 2;
257 					drawJournal(2, false);
258 				}
259 			}
260 		}
261 	}	// while
262 }
263 
doJournal()264 void LabEngine::doJournal() {
265 	_graphics->blackAllScreen();
266 	_lastPage = false;
267 
268 	_journalBackImage->_width = _graphics->_screenWidth;
269 	_journalBackImage->_height = _graphics->_screenHeight;
270 	_journalBackImage->setData(nullptr, true);
271 
272 	updateEvents();
273 	loadJournalData();
274 	_interface->attachButtonList(&_journalButtonList);
275 	drawJournal(0, true);
276 	_event->mouseShow();
277 	processJournal();
278 	_interface->attachButtonList(nullptr);
279 	_graphics->fade(false);
280 	_event->mouseHide();
281 
282 	delete[] _blankJournal;
283 	_blankJournal = nullptr;
284 	_journalBackImage->setData(nullptr, true);
285 
286 	_interface->freeButtonList(&_journalButtonList);
287 	_graphics->freeFont(&_journalFont);
288 
289 	_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
290 	_graphics->blackScreen();
291 }
292 
drawMonText(const char * text,TextFont * monitorFont,Common::Rect textRect,bool isinteractive)293 void LabEngine::drawMonText(const char *text, TextFont *monitorFont, Common::Rect textRect, bool isinteractive) {
294 	uint16 drawingToPage = 0, yspacing = 0;
295 
296 	_event->mouseHide();
297 
298 	if (*text == '%') {
299 		text++;
300 		uint16 numlines = (*text - '0') * 10;
301 		text++;
302 		numlines += (*text - '0');
303 		text += 2;
304 
305 		uint16 fheight = _graphics->textHeight(monitorFont);
306 		textRect.left = _monitorButton->_width + _utils->vgaScaleX(3);
307 		_monitorButtonHeight = _monitorButton->_height + _utils->vgaScaleY(3);
308 
309 		if (_monitorButtonHeight > fheight)
310 			yspacing = _monitorButtonHeight - fheight;
311 		else
312 			_monitorButtonHeight = fheight;
313 
314 		_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, textRect.bottom, 0);
315 
316 		for (int i = 0; i < numlines; i++)
317 			_monitorButton->drawImage(0, i * _monitorButtonHeight);
318 	} else if (isinteractive) {
319 		_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, textRect.bottom, 0);
320 	} else {
321 		_graphics->rectFill(textRect, 0);
322 	}
323 
324 	const char *curText = text;
325 	while (drawingToPage < _monitorPage) {
326 		updateEvents();
327 		curText += _graphics->flowText(monitorFont, yspacing, 0, 0, false, false, false, false, textRect, curText);
328 		_lastPage = (*curText == 0);
329 
330 		if (_lastPage)
331 			_monitorPage = drawingToPage;
332 		else
333 			drawingToPage++;
334 	}
335 
336 	curText += _graphics->flowText(monitorFont, yspacing, 2, 0, false, false, false, true, textRect, curText);
337 	_lastPage = (*curText == 0);
338 	_event->mouseShow();
339 }
340 
processMonitor(const Common::String & ntext,TextFont * monitorFont,bool isInteractive,Common::Rect textRect)341 void LabEngine::processMonitor(const Common::String &ntext, TextFont *monitorFont, bool isInteractive, Common::Rect textRect) {
342 	Common::String startFileName = _monitorTextFilename;
343 	const CloseData *startClosePtr = _closeDataPtr, *lastClosePtr[10];
344 	uint16 depth = 0;
345 	Common::String text = ntext;
346 
347 	lastClosePtr[0] = _closeDataPtr;
348 
349 	while (1) {
350 		if (isInteractive) {
351 			if (!_closeDataPtr)
352 				_closeDataPtr = startClosePtr;
353 
354 			Common::String filename;
355 			if (_closeDataPtr == startClosePtr)
356 				filename = startFileName;
357 			else
358 				filename = _closeDataPtr->_graphicName;
359 
360 			if (filename != _monitorTextFilename) {
361 				_monitorPage = 0;
362 				_monitorTextFilename = filename;
363 
364 				text = _resource->getText(_monitorTextFilename);
365 				_graphics->fade(false);
366 				drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
367 				_graphics->fade(true);
368 			}
369 		}
370 
371 		IntuiMessage *msg = _event->getMsg();
372 		if (shouldQuit()) {
373 			_quitLab = true;
374 			return;
375 		}
376 
377 		updateEvents();
378 		_graphics->screenUpdate();
379 		_system->delayMillis(10);
380 
381 		if (!msg)
382 			continue;
383 
384 		MessageClass msgClass  = msg->_msgClass;
385 
386 		if ((msgClass == kMessageRightClick) ||
387 				((msgClass == kMessageRawKey) && (msg->_code == Common::KEYCODE_ESCAPE)))
388 			return;
389 
390 		if (msgClass == kMessageLeftClick) {
391 			int16 mouseX = msg->_mouse.x;
392 			int16 mouseY = msg->_mouse.y;
393 
394 			// Check if mouse was in button bar
395 			if ((mouseY >= _utils->vgaScaleY(171)) && (mouseY <= _utils->vgaScaleY(200))) {
396 				if (mouseX <= _utils->vgaScaleX(31)) {
397 					// Exit button
398 					return;
399 				}
400 
401 				if (mouseX <= _utils->vgaScaleX(59)) {
402 					// Back button
403 					if (isInteractive) {
404 						_monitorPage = 0;
405 
406 						if (depth) {
407 							depth--;
408 							_closeDataPtr = lastClosePtr[depth];
409 						}
410 					} else if (_monitorPage > 0) {
411 						_monitorPage = 0;
412 						drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
413 					}
414 				} else if (mouseX < _utils->vgaScaleX(259)) {
415 					// empty region; ignore
416 				} else if (mouseX <= _utils->vgaScaleX(289)) {
417 					// Page down button
418 					if (!_lastPage) {
419 						_monitorPage += 1;
420 						drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
421 					}
422 				} else if (_monitorPage >= 1) {
423 					// Page up button
424 					_monitorPage -= 1;
425 					drawMonText(text.c_str(), monitorFont, textRect, isInteractive);
426 				}
427 			} else if (isInteractive) {
428 				const CloseData *tmpClosePtr = _closeDataPtr;
429 				mouseY = 64 + (mouseY / _monitorButtonHeight) * 42;
430 				mouseX = 101;
431 				setCurrentClose(Common::Point(mouseX, mouseY), &_closeDataPtr, false);
432 
433 				if (tmpClosePtr != _closeDataPtr) {
434 					lastClosePtr[depth] = tmpClosePtr;
435 					depth++;
436 				}
437 			}
438 		}
439 	}	// while
440 }
441 
doMonitor(const Common::String background,const Common::String textfile,bool isinteractive,Common::Rect textRect)442 void LabEngine::doMonitor(const Common::String background, const Common::String textfile, bool isinteractive, Common::Rect textRect) {
443 	Common::Rect scaledRect = _utils->vgaRectScale(textRect.left, textRect.top, textRect.right, textRect.bottom);
444 	_monitorTextFilename = textfile;
445 
446 	_graphics->blackAllScreen();
447 	_graphics->readPict("P:Mon/Monitor.1");
448 	_graphics->readPict("P:Mon/NWD1");
449 	_graphics->readPict("P:Mon/NWD2");
450 	_graphics->readPict("P:Mon/NWD3");
451 	_graphics->blackAllScreen();
452 
453 	_monitorPage = 0;
454 	_lastPage = false;
455 	_graphics->_fadePalette = _highPalette;
456 
457 	TextFont *monitorFont = _resource->getFont("F:Map.fon");
458 	Common::File *buttonFile = _resource->openDataFile("P:MonImage");
459 	_monitorButton = new Image(buttonFile, this);
460 	delete buttonFile;
461 
462 	Common::String ntext = _resource->getText(textfile);
463 	_graphics->loadBackPict(background, _highPalette);
464 	drawMonText(ntext.c_str(), monitorFont, scaledRect, isinteractive);
465 	_event->mouseShow();
466 	_graphics->fade(true);
467 	processMonitor(ntext, monitorFont, isinteractive, scaledRect);
468 	_graphics->fade(false);
469 	_event->mouseHide();
470 	_graphics->freeFont(&monitorFont);
471 
472 	_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
473 	_graphics->blackAllScreen();
474 	_graphics->freePict();
475 }
476 
477 } // End of namespace Lab
478