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