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 #include "common/system.h"
24 
25 #include "agos/agos.h"
26 #include "agos/intern.h"
27 
28 #include "graphics/surface.h"
29 
30 namespace AGOS {
31 
32 #ifdef ENABLE_AGOS2
doOutput(const byte * src,uint len)33 void AGOSEngine_Feeble::doOutput(const byte *src, uint len) {
34 	if (_textWindow == NULL)
35 		return;
36 
37 	while (len-- != 0 && !shouldQuit()) {
38 		if (getBitFlag(93)) {
39 			if (_curWindow == 3) {
40 				if ((_newLines >= _textWindow->scrollY) && (_newLines < (_textWindow->scrollY + 3)))
41 					sendWindow(*src);
42 				if (*src == '\n')		// Do two top lines of text only
43 					_newLines++;
44 				src++;
45 			}
46 		} else {
47 			if (getBitFlag(94)) {
48 				if (_curWindow == 3) {
49 					if (_newLines == (_textWindow->scrollY + 7))
50 						sendWindow(*src);
51 					if (*src == '\n')	// Do two top lines of text only
52 						_newLines++;
53 					src++;
54 				}
55 			} else {
56 				if (getBitFlag(92))
57 					delay(50);
58 				sendWindow(*src++);
59 			}
60 		}
61 	}
62 }
63 #endif
64 
doOutput(const byte * src,uint len)65 void AGOSEngine::doOutput(const byte *src, uint len) {
66 	uint idx;
67 
68 	if (_textWindow == NULL)
69 		return;
70 
71 	while (len-- != 0) {
72 		if (*src != 12 && _textWindow->iconPtr != NULL &&
73 				_fcsData1[idx = getWindowNum(_textWindow)] != 2) {
74 
75 			_fcsData1[idx] = 2;
76 			_fcsData2[idx] = 1;
77 		}
78 
79 		sendWindow(*src++);
80 	}
81 }
82 
clsCheck(WindowBlock * window)83 void AGOSEngine::clsCheck(WindowBlock *window) {
84 	uint index = getWindowNum(window);
85 	tidyIconArray(index);
86 	_fcsData1[index] = 0;
87 }
88 
tidyIconArray(uint i)89 void AGOSEngine::tidyIconArray(uint i) {
90 	WindowBlock *window;
91 
92 	if (_fcsData2[i]) {
93 		mouseOff();
94 		window = _windowArray[i];
95 		drawIconArray(i, window->iconPtr->itemRef, window->iconPtr->line, window->iconPtr->classMask);
96 		_fcsData2[i] = 0;
97 		mouseOn();
98 	}
99 }
100 
showMessageFormat(const char * s,...)101 void AGOSEngine::showMessageFormat(const char *s, ...) {
102 	char buf[STRINGBUFLEN];
103 	char *str;
104 	va_list va;
105 
106 	va_start(va, s);
107 	vsnprintf(buf, STRINGBUFLEN, s, va);
108 	va_end(va);
109 
110 	if (!_fcsData1[_curWindow]) {
111 		if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
112 			if (_showMessageFlag) {
113 				if (_windowArray[_curWindow]->flags & 128) {
114 					haltAnimation();
115 				}
116 			}
117 		}
118 		openTextWindow();
119 		if (!_showMessageFlag) {
120 			_windowArray[0] = _textWindow;
121 			justifyStart();
122 		}
123 		_showMessageFlag = true;
124 		_fcsData1[_curWindow] = 1;
125 	}
126 
127 	for (str = buf; *str; str++)
128 		justifyOutPut(*str);
129 }
130 
justifyStart()131 void AGOSEngine::justifyStart() {
132 	if (getGameType() == GType_FF || getGameType() == GType_PP) {
133 		_printCharCurPos = _textWindow->textColumn;
134 		_printCharMaxPos = _textWindow->width;
135 	} else {
136 		_printCharCurPos = _textWindow->textLength;
137 		_printCharMaxPos = _textWindow->textMaxLength;
138 	}
139 	_printCharPixelCount = 0;
140 	_numLettersToPrint = 0;
141 	_newLines = 0;
142 }
143 
justifyOutPut(byte chr)144 void AGOSEngine::justifyOutPut(byte chr) {
145 	if (chr == 12) {
146 		_numLettersToPrint = 0;
147 		_printCharCurPos = 0;
148 		_printCharPixelCount = 0;
149 		doOutput(&chr, 1);
150 		clsCheck(_textWindow);
151 	} else if (getLanguage() == Common::JA_JPN && !_forceAscii) {
152 		// Japanese has no word wrapping
153 		_lettersToPrintBuf[0] = chr;
154 		_lettersToPrintBuf[1] = '\0';
155 		doOutput(_lettersToPrintBuf, 1);
156 	} else if (chr == 0 || chr == ' ' || chr == 10) {
157 		bool fit;
158 
159 		if (getGameType() == GType_FF || getGameType() == GType_PP) {
160 			fit = _printCharMaxPos - _printCharCurPos > _printCharPixelCount;
161 		} else {
162 			fit = _printCharMaxPos - _printCharCurPos >= _printCharPixelCount;
163 		}
164 
165 		if (fit) {
166 			_printCharCurPos += _printCharPixelCount;
167 			doOutput(_lettersToPrintBuf, _numLettersToPrint);
168 
169 			if (_printCharCurPos == _printCharMaxPos) {
170 				_printCharCurPos = 0;
171 			} else {
172 				if (chr)
173 					doOutput(&chr, 1);
174 				if (chr == 10)
175 					_printCharCurPos = 0;
176 				else if (chr != 0)
177 					_printCharCurPos += (getGameType() == GType_FF || getGameType() == GType_PP) ? getFeebleFontSize(chr) : 1;
178 			}
179 		} else {
180 			const byte newline_character = 10;
181 			_printCharCurPos = _printCharPixelCount;
182 			doOutput(&newline_character, 1);
183 			doOutput(_lettersToPrintBuf, _numLettersToPrint);
184 			if (chr == ' ') {
185 				doOutput(&chr, 1);
186 				_printCharCurPos += (getGameType() == GType_FF || getGameType() == GType_PP) ? getFeebleFontSize(chr) : 1;
187 			} else {
188 				doOutput(&chr, 1);
189 				_printCharCurPos = 0;
190 			}
191 		}
192 		_numLettersToPrint = 0;
193 		_printCharPixelCount = 0;
194 	} else {
195 		_lettersToPrintBuf[_numLettersToPrint++] = chr;
196 		_printCharPixelCount += (getGameType() == GType_FF || getGameType() == GType_PP) ? getFeebleFontSize(chr) : 1;
197 	}
198 }
199 
openTextWindow()200 void AGOSEngine::openTextWindow() {
201 	if (_textWindow) {
202 		if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
203 			if (_textWindow->flags & 0x80)
204 				clearWindow(_textWindow);
205 		}
206 		return;
207 	}
208 
209 	if (getGameType() == GType_FF || getGameType() == GType_PP)
210 		_textWindow = openWindow(64, 96, 384, 172, 1, 0, 15);
211 	else
212 		_textWindow = openWindow(8, 144, 24, 6, 1, 0, 15);
213 }
214 
windowPutChar(WindowBlock * window,byte c,byte b)215 void AGOSEngine_PN::windowPutChar(WindowBlock *window, byte c, byte b) {
216 	if (_mousePrintFG || _wiped)
217 		return;
218 	AGOSEngine::windowPutChar(window, c, b);
219 }
220 
windowPutChar(WindowBlock * window,byte c,byte b)221 void AGOSEngine::windowPutChar(WindowBlock *window, byte c, byte b) {
222 	byte width = 6;
223 	byte textColumnWidth = 8;
224 
225 	if (c == 12) {
226 		clearWindow(window);
227 	} else if (c == 13 || c == 10) {
228 		windowNewLine(window);
229 	} else if ((c == 1 && _language != Common::HE_ISR) || (c == 8)) {
230 		if (_language == Common::HE_ISR) {
231 			if (b >= 64 && b < 91)
232 				width = _hebrewCharWidths [b - 64];
233 
234 			if (window->textLength != 0) {
235 				window->textLength--;
236 				window->textColumnOffset += width;
237 				if (window->textColumnOffset >= 8) {
238 					window->textColumnOffset -= 8;
239 					window->textColumn--;
240 				}
241 			}
242 		} else {
243 			int8 val = (c == 8) ? 6 : 4;
244 
245 			if (window->textLength != 0) {
246 				window->textLength--;
247 				window->textColumnOffset -= val;
248 				if ((int8)window->textColumnOffset < val) {
249 					window->textColumnOffset += 8;
250 					window->textColumn--;
251 				}
252 			}
253 		}
254 	} else if (c >= 32) {
255 		if (getGameType() == GType_FF || getGameType() == GType_PP) {
256 			// Ignore invalid characters
257 			if (c - 32 > 195)
258 				return;
259 
260 			windowDrawChar(window, window->textColumn + window->x, window->textRow + window->y, c);
261 			window->textColumn += getFeebleFontSize(c);
262 			return;
263 		}
264 
265 		if (_language == Common::JA_JPN && !_forceAscii)
266 			textColumnWidth = width = 4;
267 		else if (c - 32 > 98) // Ignore invalid characters
268 			return;
269 
270 		if (window->textLength == window->textMaxLength) {
271 			windowNewLine(window);
272 		} else if (window->textRow == window->height) {
273 			windowNewLine(window);
274 			window->textRow--;
275 		}
276 
277 		if (_language == Common::HE_ISR) {
278 			if (c >= 64 && c < 91)
279 				width = _hebrewCharWidths [c - 64];
280 			window->textColumnOffset -= width;
281 			if (window->textColumnOffset >= width) {
282 				window->textColumnOffset += 8;
283 				window->textColumn++;
284 			}
285 			windowDrawChar(window, (window->width + window->x - window->textColumn) * 8, window->textRow * 8 + window->y, c);
286 			window->textLength++;
287 		} else {
288 			windowDrawChar(window, window->x * 8 + window->textColumn * textColumnWidth, window->textRow * 8 + window->y, c);
289 			window->textLength++;
290 			window->textColumnOffset += width;
291 			if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
292 				if (c == 'i' || c == 'l')
293 					window->textColumnOffset -= 2;
294 			}
295 			if (window->textColumnOffset >= textColumnWidth) {
296 				window->textColumnOffset -= textColumnWidth;
297 				window->textColumn++;
298 			}
299 		}
300 	}
301 }
302 
303 #ifdef ENABLE_AGOS2
windowNewLine(WindowBlock * window)304 void AGOSEngine_Feeble::windowNewLine(WindowBlock *window) {
305 	if (_noOracleScroll == 0) {
306 		if (window->height < window->textRow + 30) {
307 			if (!getBitFlag(94)) {
308 				_noOracleScroll = 1;
309 				if (getBitFlag(92)) {
310 					_noOracleScroll = 0;
311 					checkLinkBox();
312 					scrollOracle();
313 					linksUp();
314 					window->scrollY++;
315 					_oracleMaxScrollY++;
316 				} else {
317 					_oracleMaxScrollY++;
318 					checkLinkBox();
319 				}
320 			}
321 		} else {
322 			window->textRow += 15;
323 			checkLinkBox();
324 		}
325 	} else {
326 		_oracleMaxScrollY++;
327 		checkLinkBox();
328 	}
329 
330 	window->textColumn = 0;
331 	window->textColumnOffset = 0;
332 	window->textLength = 0;
333 }
334 #endif
335 
windowNewLine(WindowBlock * window)336 void AGOSEngine::windowNewLine(WindowBlock *window) {
337 	window->textColumn = 0;
338 	window->textColumnOffset = (getGameType() == GType_ELVIRA2) ? 4 : 0;
339 	window->textLength = 0;
340 
341 	if (getGameType() == GType_PN) {
342 		window->textRow++;
343 		if (window->textRow == window->height) {
344 			windowScroll(window);
345 			window->textRow--;
346 		}
347 	} else {
348 		if (window->textRow == window->height) {
349 			if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 ||
350 				getGameType() == GType_WW) {
351 				windowScroll(window);
352 			}
353 		} else {
354 			window->textRow++;
355 		}
356 	}
357 }
358 
windowScroll(WindowBlock * window)359 void AGOSEngine::windowScroll(WindowBlock *window) {
360 	_videoLockOut |= 0x8000;
361 
362 	if (window->height != 1) {
363 		Graphics::Surface *screen = getBackendSurface();
364 
365 		byte *src, *dst;
366 		uint16 w1, h1, w2, h2;
367 
368 		w1 = w2 = window->width * 8;
369 		h1 = h2 = (window->height -1) * 8;
370 
371 		dst = (byte *)screen->getBasePtr(window->x * 8, window->y);
372 		src = dst + 8 * screen->pitch;
373 
374 		do {
375 			memcpy(dst, src, w1);
376 			src += screen->pitch;
377 			dst += screen->pitch;
378 		} while (--h1);
379 
380 		if (getGameId() == GID_ELVIRA1 && getPlatform() == Common::kPlatformPC98) {
381 			w1 = w2 << 1;
382 			h1 = h2 << 1;
383 			dst = (byte *)_scaleBuf->getBasePtr(window->x * 16, window->y * 2);
384 			src = dst + 16 * screen->pitch;
385 			do {
386 				memcpy(dst, src, w1);
387 				src += screen->pitch;
388 				dst += screen->pitch;
389 			} while (--h1);
390 		}
391 
392 		Common::Rect dirtyRect(window->x * 8, window->y, window->x * 8 + w2, window->y + h2);
393 		updateBackendSurface(&dirtyRect);
394 	}
395 
396 	colorBlock(window, window->x * 8, (window->height - 1) * 8 + window->y, window->width * 8, 8);
397 
398 	_videoLockOut &= ~0x8000;
399 }
400 } // End of namespace AGOS
401