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
25 #include "common/file.h"
26 #include "common/textconsole.h"
27
28 #include "gui/message.h"
29
30 #include "agos/agos.h"
31 #include "agos/intern.h"
32
33 namespace AGOS {
34
uncompressText(byte * ptr)35 void AGOSEngine::uncompressText(byte *ptr) {
36 byte a;
37 while (1) {
38 if (_awaitTwoByteToken != 0)
39 a = _awaitTwoByteToken;
40 else
41 a = *ptr++;
42 if (a == 0)
43 return;
44 ptr = uncompressToken(a, ptr);
45 if (ptr == 0)
46 return;
47 }
48 }
49
uncompressToken(byte a,byte * ptr)50 byte *AGOSEngine::uncompressToken(byte a, byte *ptr) {
51 byte *ptr1 = 0;
52 byte *ptr2 = 0;
53 byte b;
54 int count1 = 0;
55
56 if (a == 0xFF || a == 0xFE || a == 0xFD) {
57 if (a == 0xFF)
58 ptr2 = _twoByteTokenStrings;
59 if (a == 0xFE)
60 ptr2 = _secondTwoByteTokenStrings;
61 if (a == 0xFD)
62 ptr2 = _thirdTwoByteTokenStrings;
63 _awaitTwoByteToken = a;
64 b = a;
65 a = *ptr++;
66 if (a == 0) /* Need to return such that next byte */
67 return 0; /* is used as two byte token */
68
69 _awaitTwoByteToken = 0;
70 ptr1 = _twoByteTokens;
71 while (*ptr1 != a) {
72 ptr1++;
73 count1++;
74 if (*ptr1 == 0) { /* If was not a two byte token */
75 count1 = 0; /* then was a byte token. */
76 ptr1 = _byteTokens;
77 while (*ptr1 != a) {
78 ptr1++;
79 count1++;
80 }
81 ptr1 = _byteTokenStrings; /* Find it */
82 while (count1--) {
83 while (*ptr1++)
84 ;
85 }
86 ptr1 = uncompressToken(b, ptr1); /* Try this one as a two byte token */
87 uncompressText(ptr1); /* Uncompress rest of this token */
88 return ptr;
89 }
90 }
91 while (count1--) {
92 while (*ptr2++)
93 ;
94 }
95 uncompressText(ptr2);
96 } else {
97 ptr1 = _byteTokens;
98 while (*ptr1 != a) {
99 ptr1++;
100 count1++;
101 if (*ptr1 == 0) {
102 _textBuffer[_textCount++] = a; /* Not a byte token */
103 return ptr; /* must be real character */
104 }
105 }
106 ptr1 = _byteTokenStrings;
107 while (count1--) { /* Is a byte token so count */
108 while (*ptr1++) /* to start of token */
109 ;
110 }
111 uncompressText(ptr1); /* and do it */
112 }
113 return ptr;
114 }
115
getStringPtrByID(uint16 stringId,bool upperCase)116 const byte *AGOSEngine::getStringPtrByID(uint16 stringId, bool upperCase) {
117 const byte *stringPtr;
118 byte *dst;
119
120 _freeStringSlot ^= 1;
121 dst = _stringReturnBuffer[_freeStringSlot];
122
123 if (getGameType() == GType_ELVIRA1 && getPlatform() == Common::kPlatformAtariST) {
124 byte *ptr = _stringTabPtr[stringId];
125 _textCount = 0;
126 _awaitTwoByteToken = 0;
127 uncompressText(ptr);
128 _textBuffer[_textCount] = 0;
129 Common::strlcpy((char *)dst, (const char *)_textBuffer, 180);
130 } else {
131 if (stringId < 0x8000) {
132 stringPtr = _stringTabPtr[stringId];
133 } else {
134 stringPtr = getLocalStringByID(stringId);
135 }
136 Common::strlcpy((char *)dst, (const char *)stringPtr, 180);
137 }
138
139 // WORKAROUND bug #1538873: The French version of Simon 1 and the
140 // Polish version of Simon 2 used excess spaces, at the end of many
141 // messages, so we strip off those excess spaces.
142 if ((getGameType() == GType_SIMON1 && _language == Common::FR_FRA) ||
143 (getGameType() == GType_SIMON2 && _language == Common::PL_POL)) {
144 uint16 len = strlen((const char *)dst) - 1;
145
146 while (len && dst[len] == 32) {
147 dst[len] = 0;
148 len--;
149 }
150
151 }
152
153 if (upperCase && *dst) {
154 if (Common::isLower(*dst))
155 *dst = toupper(*dst);
156 }
157
158 return dst;
159 }
160
getLocalStringByID(uint16 stringId)161 const byte *AGOSEngine::getLocalStringByID(uint16 stringId) {
162 if (stringId < _stringIdLocalMin || stringId >= _stringIdLocalMax) {
163 loadTextIntoMem(stringId);
164 }
165 return _localStringtable[stringId - _stringIdLocalMin];
166 }
167
getTextLocation(uint a)168 TextLocation *AGOSEngine::getTextLocation(uint a) {
169 switch (a) {
170 case 1:
171 return &_textLocation1;
172 case 2:
173 return &_textLocation2;
174 case 101:
175 return &_textLocation3;
176 case 102:
177 return &_textLocation4;
178 default:
179 error("getTextLocation: Invalid text location %d", a);
180 }
181 return NULL; // for compilers that don't support NORETURN
182 }
183
allocateStringTable(int num)184 void AGOSEngine::allocateStringTable(int num) {
185 _stringTabPtr = (byte **)calloc(num, sizeof(byte *));
186 _stringTabPos = 0;
187 _stringTabSize = num;
188 }
189
setupStringTable(byte * mem,int num)190 void AGOSEngine::setupStringTable(byte *mem, int num) {
191 int i = 0;
192
193 if (getGameType() == GType_ELVIRA1 && getPlatform() == Common::kPlatformAtariST) {
194 int ct1;
195
196 _twoByteTokens = mem;
197 while (*mem++) {
198 i++;
199 }
200 _twoByteTokenStrings = mem;
201 ct1 = i;
202 while (*mem++) {
203 while (*mem++)
204 ;
205 i--;
206 if ((i == 0) && (ct1 != 0)) {
207 _secondTwoByteTokenStrings = mem;
208 i = ct1;
209 ct1 = 0;
210 }
211 if (i == 0)
212 _thirdTwoByteTokenStrings = mem;
213 }
214 _byteTokens = mem;
215 while (*mem++)
216 ;
217 _byteTokenStrings = mem;
218 while (*mem++) {
219 while (*mem++)
220 ;
221 }
222 i = 0;
223 l1: _stringTabPtr[i++] = mem;
224 num--;
225 if (!num) {
226 _stringTabPos = i;
227 return;
228 }
229 while (*mem++)
230 ;
231 goto l1;
232 } else {
233 for (;;) {
234 _stringTabPtr[i++] = mem;
235 if (--num == 0)
236 break;
237 for (; *mem; mem++)
238 ;
239 mem++;
240 }
241
242 _stringTabPos = i;
243 }
244 }
245
setupLocalStringTable(byte * mem,int num)246 void AGOSEngine::setupLocalStringTable(byte *mem, int num) {
247 int i = 0;
248 for (;;) {
249 _localStringtable[i++] = mem;
250 if (--num == 0)
251 break;
252 for (; *mem; mem++)
253 ;
254 mem++;
255 }
256 }
257
loadTextFile(const char * filename,byte * dst)258 uint AGOSEngine::loadTextFile(const char *filename, byte *dst) {
259 if (getFeatures() & GF_OLD_BUNDLE)
260 return loadTextFile_simon1(filename, dst);
261 else
262 return loadTextFile_gme(filename, dst);
263 }
264
loadTextFile_simon1(const char * filename,byte * dst)265 uint AGOSEngine::loadTextFile_simon1(const char *filename, byte *dst) {
266 Common::File fo;
267 fo.open(filename);
268 uint32 size;
269
270 if (fo.isOpen() == false)
271 error("loadTextFile: Can't open '%s'", filename);
272
273 size = fo.size();
274
275 if (fo.read(dst, size) != size)
276 error("loadTextFile: fread failed");
277 fo.close();
278
279 return size;
280 }
281
loadTextFile_gme(const char * filename,byte * dst)282 uint AGOSEngine::loadTextFile_gme(const char *filename, byte *dst) {
283 uint res;
284 uint32 offs;
285 uint32 size;
286
287 res = atoi(filename + 4) + _textIndexBase - 1;
288 offs = _gameOffsetsPtr[res];
289 size = _gameOffsetsPtr[res + 1] - offs;
290
291 readGameFile(dst, offs, size);
292
293 return size;
294 }
295
loadTextIntoMem(uint16 stringId)296 void AGOSEngine::loadTextIntoMem(uint16 stringId) {
297 byte *p;
298 uint16 baseMin = 0x8000, baseMax, size;
299
300 _tablesHeapPtr = _tablesheapPtrNew;
301 _tablesHeapCurPos = _tablesHeapCurPosNew;
302
303 p = _strippedTxtMem;
304
305 // get filename
306 while (*p) {
307 Common::String filename;
308 while (*p)
309 filename += *p++;
310 p++;
311
312 if (getPlatform() == Common::kPlatformAcorn) {
313 filename += ".DAT";
314 }
315
316 baseMax = (p[0] * 256) | p[1];
317 p += 2;
318
319 if (stringId < baseMax) {
320 _stringIdLocalMin = baseMin;
321 _stringIdLocalMax = baseMax;
322
323 _localStringtable = (byte **)_tablesHeapPtr;
324
325 size = (baseMax - baseMin + 1) * sizeof(byte *);
326 _tablesHeapPtr += size;
327 _tablesHeapCurPos += size;
328
329 size = loadTextFile(filename.c_str(), _tablesHeapPtr);
330
331 setupLocalStringTable(_tablesHeapPtr, baseMax - baseMin + 1);
332
333 _tablesHeapPtr += size;
334 _tablesHeapCurPos += size;
335
336 if (_tablesHeapCurPos > _tablesHeapSize) {
337 error("loadTextIntoMem: Out of table memory");
338 }
339 return;
340 }
341
342 baseMin = baseMax;
343 }
344
345 error("loadTextIntoMem: didn't find %d", stringId);
346 }
347
348 static const byte polish_charWidth[226] = {
349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
352 0, 0, 6, 2, 8, 7, 6,10, 8, 2,
353 4, 4, 7, 6, 3, 4, 2, 3, 6, 4,
354 6, 6, 7, 6, 6, 6, 6, 6, 2, 8,
355 6, 9, 7, 6, 6, 8, 7, 8, 8, 7,
356 6, 9, 8, 2, 6, 7, 6,10, 8, 9,
357 7, 9, 7, 7, 8, 8, 8,12, 8, 8,
358 7, 6, 7, 6, 4, 7, 7, 7, 7, 6,
359 7, 7, 4, 7, 6, 2, 3, 6, 2,10,
360 6, 7, 7, 7, 5, 6, 4, 6, 6,10,
361 6, 6, 6, 0, 0, 0, 0, 0, 8, 6,
362 7, 7, 7, 7, 7, 6, 7, 7, 7, 4,
363 4, 3, 8, 8, 7, 0, 0, 7, 7, 7,
364 6, 6, 6, 9, 8, 0, 0, 0, 0, 0,
365 7, 3, 7, 6, 6, 8, 0, 0, 6, 0,
366 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
371 0, 0, 0, 0, 0, 7
372 };
373
374 static const byte charWidth[226] = {
375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
378 0, 0, 6, 2, 4, 8, 6,10, 9, 2,
379 4, 4, 6, 6, 3, 4, 2, 3, 6, 4,
380 6, 6, 7, 6, 6, 6, 6, 6, 2, 3,
381 7, 7, 7, 6,11, 8, 7, 8, 8, 7,
382 6, 9, 8, 2, 6, 7, 6,10, 8, 9,
383 7, 9, 7, 7, 8, 8, 8,12, 8, 8,
384 7, 3, 3, 3, 6, 8, 3, 7, 7, 6,
385 7, 7, 4, 7, 6, 2, 3, 6, 2,10,
386 6, 7, 7, 7, 5, 6, 4, 7, 7,10,
387 6, 6, 6, 0, 0, 0, 0, 0, 8, 6,
388 7, 7, 7, 7, 7, 6, 7, 7, 7, 4,
389 4, 3, 8, 8, 7, 0, 0, 7, 7, 7,
390 6, 6, 6, 9, 8, 0, 0, 0, 0, 0,
391 7, 3, 7, 6, 6, 8, 0, 6, 0, 0,
392 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
393 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
394 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397 0, 0, 0, 0, 0, 7
398 };
399
getPixelLength(const char * string,uint16 maxWidth,uint16 & pixels)400 const char *AGOSEngine::getPixelLength(const char *string, uint16 maxWidth, uint16 &pixels) {
401 pixels = 0;
402
403 while (*string != 0) {
404 byte chr = *string;
405 uint8 len = (_language == Common::PL_POL) ? polish_charWidth[chr] : charWidth[chr];
406 if ((pixels + len) > maxWidth)
407 break;
408 pixels += len;
409 string++;
410 }
411
412 return string;
413 }
414
printTextOf(uint a,uint x,uint y)415 bool AGOSEngine::printTextOf(uint a, uint x, uint y) {
416 const byte *stringPtr;
417 uint16 pixels, w;
418
419 if (getGameType() == GType_SIMON2) {
420 if (getBitFlag(79)) {
421 Subroutine *sub;
422 _variableArray[84] = a;
423 sub = getSubroutineByID(5003);
424 if (sub != NULL)
425 startSubroutineEx(sub);
426 return true;
427 }
428 }
429
430 if (a >= _numTextBoxes)
431 return false;
432
433
434 stringPtr = getStringPtrByID(_shortText[a]);
435 if (getGameType() == GType_FF) {
436 getPixelLength((const char *)stringPtr, 400, pixels);
437 w = pixels + 1;
438 x -= w / 2;
439 printScreenText(6, 0, (const char *)stringPtr, x, y, w);
440 } else {
441 showActionString(stringPtr);
442 }
443
444 return true;
445 }
446
printNameOf(Item * item,uint x,uint y)447 bool AGOSEngine::printNameOf(Item *item, uint x, uint y) {
448 SubObject *subObject;
449 const byte *stringPtr;
450 uint16 pixels, w;
451
452 if (item == 0 || item == _dummyItem2 || item == _dummyItem3)
453 return false;
454
455 subObject = (SubObject *)findChildOfType(item, kObjectType);
456 if (subObject == NULL)
457 return false;
458
459 stringPtr = getStringPtrByID(subObject->objectName);
460 if (getGameType() == GType_FF) {
461 getPixelLength((const char *)stringPtr, 400, pixels);
462 w = pixels + 1;
463 x -= w / 2;
464 printScreenText(6, 0, (const char *)stringPtr, x, y, w);
465 } else {
466 showActionString(stringPtr);
467 }
468
469 return true;
470 }
471
printScreenText(uint vgaSpriteId,uint color,const char * string,int16 x,int16 y,int16 width)472 void AGOSEngine::printScreenText(uint vgaSpriteId, uint color, const char *string, int16 x, int16 y, int16 width) {
473 char convertedString[320];
474 char *convertedString2 = convertedString;
475 int16 height, talkDelay;
476 int stringLength = strlen(string);
477 int padding, lettersPerRow, lettersPerRowJustified;
478 const int textHeight = 10;
479
480 height = textHeight;
481 lettersPerRow = width / 6;
482 lettersPerRowJustified = stringLength / (stringLength / lettersPerRow + 1) + 1;
483
484 talkDelay = (stringLength + 3) / 3;
485 if (getGameType() == GType_SIMON1 && (getFeatures() & GF_TALKIE)) {
486 if (_variableArray[141] == 0)
487 _variableArray[141] = 9;
488 _variableArray[85] = _variableArray[141] * talkDelay;
489
490 if (_language == Common::HE_ISR)
491 _variableArray[85] += talkDelay * 2;
492 } else {
493 if (_variableArray[86] == 0)
494 talkDelay /= 2;
495 if (_variableArray[86] == 2)
496 talkDelay *= 2;
497 _variableArray[85] = talkDelay * 5;
498 }
499
500 assert(stringLength > 0);
501
502 while (stringLength > 0) {
503 int pos = 0;
504 if (stringLength > lettersPerRow) {
505 int removeLastWord = 0;
506 if (lettersPerRow > lettersPerRowJustified) {
507 pos = lettersPerRowJustified;
508 while (string[pos] != ' ')
509 pos++;
510 if (pos > lettersPerRow)
511 removeLastWord = 1;
512 }
513 if (lettersPerRow <= lettersPerRowJustified || removeLastWord) {
514 pos = lettersPerRow;
515 while (string[pos] != ' ' && pos > 0)
516 pos--;
517 }
518 height += textHeight;
519 y -= textHeight;
520 } else
521 pos = stringLength;
522 padding = ((lettersPerRow - pos) % 2) ? (lettersPerRow - pos) / 2 + 1 : (lettersPerRow - pos) / 2;
523 while (padding--)
524 *convertedString2++ = ' ';
525 stringLength -= pos;
526 while (pos--)
527 *convertedString2++ = *string++;
528 *convertedString2++ = '\n';
529 string++; // skip space
530 stringLength--; // skip space
531 }
532 *(convertedString2 - 1) = '\0';
533
534 if (getGameType() == GType_SIMON1)
535 stopAnimate(vgaSpriteId + 199);
536 else
537 stopAnimateSimon2(2, vgaSpriteId);
538
539 if (getPlatform() == Common::kPlatformAmiga) {
540 color = color * 3 + 1;
541 renderStringAmiga(vgaSpriteId, color, width, height, convertedString);
542 } else {
543 color = color * 3 + 192;
544 renderString(vgaSpriteId, color, width, height, convertedString);
545 }
546
547 uint16 windowNum = (!getBitFlag(133)) ? 3 : 4;
548 if (getGameType() == GType_SIMON1 && (getFeatures() & GF_DEMO))
549 windowNum = 4;
550
551 x /= 8;
552 if (y < 2)
553 y = 2;
554
555 if (getGameType() == GType_SIMON1) {
556 uint16 id = 199 + vgaSpriteId;
557 animate(windowNum, id / 100, id, x, y, 12);
558 } else {
559 animate(windowNum, 2, vgaSpriteId, x, y, 12);
560 }
561 }
562
563 #ifdef ENABLE_AGOS2
564 // Swampy Adventures specific
printInfoText(const char * itemText)565 void AGOSEngine_PuzzlePack::printInfoText(const char *itemText) {
566 const char *itemName = NULL;
567 int flag = (_mouse.y / 32) * 20 + (_mouse.x / 32) + 1300;
568
569 switch (_variableArray[999]) {
570 case 80:
571 if (_variableArray[flag]) {
572 if (_variableArray[flag] == 201)
573 itemName = " Bridge: ";
574 if (_variableArray[flag] == 231 || _variableArray[flag] == 241)
575 itemName = " Log: ";
576 if (_variableArray[flag] == 281)
577 itemName = " Rubble: ";
578 if (_variableArray[flag] == 291)
579 itemName = " Boulder: ";
580 if (_variableArray[flag] == 311)
581 itemName = " Key: ";
582 if (_variableArray[flag] == 312)
583 itemName = " Spanner: ";
584 if (_variableArray[flag] == 321)
585 itemName = " Gate: ";
586 if (_variableArray[flag] == 331)
587 itemName = " Crate: ";
588 } else {
589 flag -= 300;
590 if (_variableArray[flag] == 2)
591 itemName = " Water: ";
592 if (_variableArray[flag] == 5)
593 itemName = " Exit: ";
594 if ((_variableArray[flag] == 5) && (_variableArray[81] == 10))
595 itemName = " Gem: ";
596 if (_variableArray[flag] == 236 || _variableArray[flag] == 246)
597 itemName = " Floating Log: ";
598 if (_variableArray[flag] == 400)
599 itemName = " Valve: ";
600 }
601 break;
602
603 case 81:
604 if (_variableArray[flag]) {
605 if (_variableArray[flag] == 281)
606 itemName = " Cracked Block: ";
607 if (_variableArray[flag] == 291)
608 itemName = " Boulder: ";
609 if (_variableArray[flag] == 331)
610 itemName = " Block: ";
611 if (_variableArray[flag] == 341)
612 itemName = " Switch: ";
613 if (_variableArray[flag] == 343)
614 itemName = " Button: ";
615 if ((_variableArray[flag] > 430) && (_variableArray[flag] < 480))
616 itemName = " Mosaic Block: ";
617 } else {
618 flag -= 300;
619 if (_variableArray[flag] == 5)
620 itemName = " Exit: ";
621 if ((_variableArray[flag] == 5) && (_variableArray[82] == 10))
622 itemName = " Gem: ";
623 }
624 break;
625
626 case 82:
627 if (_variableArray[flag]) {
628 if (_variableArray[flag] == 201 || _variableArray[flag] == 211)
629 itemName = " Unstable Track: ";
630 if (_variableArray[flag] == 281)
631 itemName = " Rubble Pile: ";
632 if (_variableArray[flag] == 291)
633 itemName = " Boulder: ";
634 if (_variableArray[flag] == 331)
635 itemName = " Crate: ";
636 if (_variableArray[flag] == 401 || _variableArray[flag] == 405)
637 itemName = " Cart: ";
638 } else {
639 flag -= 300;
640 if (_variableArray[flag] == 4)
641 itemName = " Hole: ";
642 if (_variableArray[flag] == 5)
643 itemName = " Exit: ";
644 if ((_variableArray[flag] == 5) && (_variableArray[83] == 10))
645 itemName = " Gem: ";
646 if ((_variableArray[flag] > 5) && (_variableArray[flag] < 10))
647 itemName = " Buffer Track: ";
648 if ((_variableArray[flag] > 9) && (_variableArray[flag] < 40))
649 itemName = " Track: ";
650 if (_variableArray[flag] == 300)
651 itemName = " Boulder: ";
652 }
653 break;
654
655 case 83:
656 if (_variableArray[flag]) {
657 if (_variableArray[flag] == 201)
658 itemName = " Broken Floor: ";
659 if (_variableArray[flag] == 231 || _variableArray[flag] == 241)
660 itemName = " Barrel: ";
661 if (_variableArray[flag] == 281)
662 itemName = " Cracked Rock: ";
663 if (_variableArray[flag] == 291)
664 itemName = " Spacehopper: ";
665 if (_variableArray[flag] == 311)
666 itemName = " Key: ";
667 if (_variableArray[flag] == 321)
668 itemName = " Trapdoor: ";
669 if (_variableArray[flag] == 324)
670 itemName = " Trapdoor: ";
671 if (_variableArray[flag] == 331)
672 itemName = " Crate: ";
673 } else {
674 flag -= 300;
675 if (_variableArray[flag] == 4)
676 itemName = " Hole: ";
677 if (_variableArray[flag] == 239 || _variableArray[flag] == 249)
678 itemName = " Barrel: ";
679 }
680 break;
681
682 case 84:
683 if (_variableArray[flag]) {
684 if (_variableArray[flag] == 201)
685 itemName = " Floating Platform: ";
686 if (_variableArray[flag] == 231)
687 itemName = " Cauldron: ";
688 if (_variableArray[flag] == 281)
689 itemName = " Cracked Block: ";
690 if (_variableArray[flag] == 311 || _variableArray[flag] == 312)
691 itemName = " Key: ";
692 if (_variableArray[flag] == 321 || _variableArray[flag] == 361 || _variableArray[flag] == 371)
693 itemName = " Gate: ";
694 if (_variableArray[flag] == 331)
695 itemName = " Chest: ";
696 if (_variableArray[flag] == 332)
697 itemName = " Jewel: ";
698 if (_variableArray[flag] == 351 || _variableArray[flag] == 352)
699 itemName = " Babies: ";
700 } else {
701 flag -= 300;
702 if (_variableArray[flag] == 6)
703 itemName = " Slime: ";
704 if (_variableArray[flag] == 334)
705 itemName = " Chest: ";
706 }
707 break;
708
709 default:
710 break;
711 }
712
713 if (itemName != NULL) {
714 Common::String buf = Common::String::format("%s\n%s", itemName, itemText);
715 GUI::TimedMessageDialog dialog(buf, 1500);
716 dialog.runModal();
717 }
718 }
719
720 // The Feeble Files specific
printScreenText(uint vgaSpriteId,uint color,const char * string,int16 x,int16 y,int16 width)721 void AGOSEngine_Feeble::printScreenText(uint vgaSpriteId, uint color, const char *string, int16 x, int16 y, int16 width) {
722 char convertedString[320];
723 char *convertedString2 = convertedString;
724 const char *string2 = string;
725 int16 height, talkDelay;
726 int stringLength = strlen(string);
727 const int textHeight = 15;
728
729 height = textHeight;
730
731 talkDelay = (stringLength + 3) / 3;
732 if (_variableArray[86] == 0)
733 talkDelay /= 2;
734 if (_variableArray[86] == 2)
735 talkDelay *= 2;
736 _variableArray[85] = talkDelay * 5;
737
738 assert(stringLength > 0);
739
740 uint16 b, pixels, spaces;
741
742 while (1) {
743 string2 = getPixelLength(string, width, pixels);
744 if (*string2 == 0) {
745 spaces = (width - pixels) / 12;
746 if (spaces != 0)
747 spaces--;
748 while (spaces) {
749 *convertedString2++ = ' ';
750 spaces--;
751 }
752 strcpy(convertedString2, string);
753 break;
754 }
755 while (*string2 != ' ') {
756 byte chr = *string2;
757 pixels -= (_language == Common::PL_POL) ? polish_charWidth[chr] : charWidth[chr];
758 string2--;
759 }
760 spaces = (width - pixels) / 12;
761 if (spaces != 0)
762 spaces--;
763 while (spaces) {
764 *convertedString2++ = ' ';
765 spaces--;
766 }
767 b = string2 - string;
768 strncpy(convertedString2, string, b);
769 convertedString2 += b;
770 *convertedString2++ = '\n';
771 height += textHeight;
772 y -= textHeight;
773 if (y < 2)
774 y = 2;
775 string = string2;
776 }
777
778 stopAnimateSimon2(2, vgaSpriteId);
779
780 renderString(1, color, width, height, convertedString);
781
782 animate(4, 2, vgaSpriteId, x, y, 12);
783 }
784
printInteractText(uint16 num,const char * string)785 void AGOSEngine_Feeble::printInteractText(uint16 num, const char *string) {
786 char convertedString[320];
787 char *convertedString2 = convertedString;
788 const char *string2 = string;
789 uint16 height = 15;
790 uint16 w = 0xFFFF;
791 uint16 b, pixels, x;
792
793 // It doesn't really matter what 'w' is to begin with, as long as it's
794 // something that cannot be generated by getPixelLength(). The original
795 // used 620, which was a potential problem.
796
797 while (1) {
798 string2 = getPixelLength(string, 620, pixels);
799 if (*string2 == 0x00) {
800 if (w == 0xFFFF)
801 w = pixels;
802 Common::strlcpy(convertedString2, string, 320);
803 break;
804 }
805 while (*string2 != ' ') {
806 byte chr = *string2;
807 pixels -= (_language == Common::PL_POL) ? polish_charWidth[chr] : charWidth[chr];
808 string2--;
809 }
810 if (w == 0xFFFF)
811 w = pixels;
812 b = string2 - string;
813 strncpy(convertedString2, string, b);
814 convertedString2 += b;
815 *convertedString2++ = '\n';
816 height += 15;
817 string = string2;
818 }
819
820 // ScrollX
821 x = _variableArray[251];
822 x += 20;
823
824 if (num == 1)
825 _interactY = 385;
826
827 // Returned values for box definition
828 _variableArray[51] = x;
829 _variableArray[52] = _interactY;
830 _variableArray[53] = w;
831 _variableArray[54] = height;
832
833 stopAnimateSimon2(2, num + 6);
834 renderString(num, 0, w, height, convertedString);
835 animate(4, 2, num + 6, x, _interactY, 12);
836
837 _interactY += height;
838 }
839
sendInteractText(uint16 num,const char * fmt,...)840 void AGOSEngine_Feeble::sendInteractText(uint16 num, const char *fmt, ...) {
841 va_list arglist;
842
843 va_start(arglist, fmt);
844 Common::String string = Common::String::vformat(fmt, arglist);
845 va_end(arglist);
846
847 printInteractText(num, string.c_str());
848 }
849 #endif
850
851 // Waxworks specific
getBoxSize()852 uint16 AGOSEngine_Waxworks::getBoxSize() {
853 int x;
854 switch (_boxLineCount) {
855 case 1: x = _lineCounts[0];
856 if (x <= 26)
857 return 1;
858 if (x <= 64)
859 if (checkFit(_linePtrs[0], 32, 2))
860 return 2;
861 if (x <= 111)
862 if (checkFit(_linePtrs[0], 37, 3))
863 return 3;
864 if (x <= 168)
865 if (checkFit(_linePtrs[0], 42, 4))
866 return 4;
867 if (x <= 240)
868 if (checkFit(_linePtrs[0], 48, 5))
869 return 5;
870 return 6;
871 case 2: if (_lineCounts[0] <= 32) {
872 if (_lineCounts[1] <= 32)
873 return 2;
874 if (_lineCounts[1] <= 74)
875 if (checkFit(_linePtrs[1], 37, 2))
876 return 3;
877 if (_lineCounts[1] <= 126)
878 if (checkFit(_linePtrs[1], 42, 3))
879 return 4;
880 if (_lineCounts[1] <= 172)
881 if (checkFit(_linePtrs[1], 48, 4))
882 return 5;
883 return 6;
884 }
885 if ((_lineCounts[0] <= 74) && (checkFit(_linePtrs[0], 37, 2))) {
886 if (_lineCounts[1] <= 37)
887 return 3;
888 if (_lineCounts[1] <= 84)
889 if (checkFit(_linePtrs[1], 42, 2))
890 return 4;
891 if (_lineCounts[1] <= 144)
892 if (checkFit(_linePtrs[1], 48, 3))
893 return 5;
894 return 6;
895 }
896 if ((_lineCounts[0] <= 126) && (checkFit(_linePtrs[0], 42, 3))) {
897 if (_lineCounts[1] <= 42)
898 return 4;
899 if (_lineCounts[1] <= 84)
900 if (checkFit(_linePtrs[1], 48, 2))
901 return 5;
902 return 6;
903 }
904 if ((_lineCounts[0] <= 192) && (checkFit(_linePtrs[0], 48, 4))) {
905 if (_lineCounts[1] <= 48)
906 return 5;
907 return 6;
908 }
909 return 6;
910 case 3: if (_lineCounts[0] <= 37) {
911 if (_lineCounts[1] <= 37) {
912 if (_lineCounts[2] <= 37)
913 return 3;
914 if (_lineCounts[2] <= 84)
915 if (checkFit(_linePtrs[2], 42, 2))
916 return 4;
917 if (_lineCounts[2] <= 144)
918 if (checkFit(_linePtrs[2], 48, 3))
919 return 5;
920 return 6;
921 }
922 if ((_lineCounts[1] <= 84) && (checkFit(_linePtrs[1], 42, 2))) {
923 if (_lineCounts[2] <= 42)
924 return 4;
925 if (_lineCounts[2] <= 96)
926 if (checkFit(_linePtrs[2], 48, 2))
927 return 5;
928 return 6;
929 }
930 if ((_lineCounts[1] <= 144) && (checkFit(_linePtrs[1], 48, 3))) {
931 if (_lineCounts[2] <= 48)
932 return 5;
933 return 6;
934 }
935 return 6;
936 }
937 if ((_lineCounts[0] <= 84) && (checkFit(_linePtrs[0], 42, 2))) {
938 if (_lineCounts[1] <= 42) {
939 if (_lineCounts[2] <= 42)
940 return 4;
941 if (_lineCounts[2] <= 96)
942 if (checkFit(_linePtrs[2], 48, 2))
943 return 5;
944 return 6;
945 }
946 if ((_lineCounts[1] <= 96) && (checkFit(_linePtrs[1], 48, 2))) {
947 if (_lineCounts[2] <= 48)
948 return 5;
949 return 6;
950 }
951 return 6;
952 }
953 if ((_lineCounts[0] <= 96) && (checkFit(_linePtrs[0], 48, 3))) {
954 if (_lineCounts[1] <= 48) {
955 if (_lineCounts[2] <= 48)
956 return 5;
957 }
958 return 6;
959 }
960 return 6;
961 case 4: if (_lineCounts[0] <= 42) {
962 if (_lineCounts[1] <= 42) {
963 if (_lineCounts[2] <= 42) {
964 if (_lineCounts[3] <= 42)
965 return 4;
966 if (_lineCounts[3] <= 96)
967 if (checkFit(_linePtrs[3], 48, 2))
968 return 5;
969 return 6;
970 }
971 if ((_lineCounts[2] <= 96) && (checkFit(_linePtrs[2], 48, 2)))
972 if (_lineCounts[3] <= 48)
973 return 5;
974 return 6;
975 }
976 if ((_lineCounts[1] <= 96) && (checkFit(_linePtrs[1], 48, 2)))
977 if ((_lineCounts[2] <= 48) && (_lineCounts[3] <= 48))
978 return 5;
979 return 6;
980 }
981 if ((_lineCounts[0] <= 96) && (checkFit(_linePtrs[0], 48, 2)))
982 if ((_lineCounts[1] <= 48) && (_lineCounts[2] <= 48) && (_lineCounts[3] <= 48))
983 return 5;
984 return 6;
985 case 5: if ((_lineCounts[0] > 48) || (_lineCounts[1] > 48) || (_lineCounts[2] > 48)
986 || (_lineCounts[3] > 48) || (_lineCounts[4] > 48))
987 return 6;
988 else
989 return 5;
990 default:
991 return 6;
992 }
993 }
994
995
checkFit(char * ptr,int width,int lines)996 uint16 AGOSEngine_Waxworks::checkFit(char *ptr, int width, int lines) {
997 int countw = 0;
998 int countl = 0;
999 char *x = NULL;
1000 while (*ptr) {
1001 if (*ptr == '\n')
1002 return 1;
1003 if (countw == width) {
1004 countl++;
1005 countw = 0;
1006 ptr = x;
1007 }
1008 if (*ptr == ' ') {
1009 x = ptr;
1010 x++;
1011 }
1012 countw++;
1013 if (countl == lines)
1014 return 0;
1015 ptr++;
1016 }
1017
1018 return 1;
1019 }
1020
boxTextMessage(const char * x)1021 void AGOSEngine_Waxworks::boxTextMessage(const char *x) {
1022 sprintf(_boxBufferPtr, "%s\n", x);
1023 _lineCounts[_boxLineCount] += strlen(x);
1024 _boxBufferPtr += strlen(x) + 1;
1025 _boxLineCount++;
1026 _linePtrs[_boxLineCount] = _boxBufferPtr;
1027 _boxCR = 1;
1028 }
1029
boxTextMsg(const char * x)1030 void AGOSEngine_Waxworks::boxTextMsg(const char *x) {
1031 sprintf(_boxBufferPtr, "%s", x);
1032 _lineCounts[_boxLineCount] += strlen(x);
1033 _boxBufferPtr += strlen(x);
1034 _boxCR = 0;
1035 }
1036
printBox()1037 void AGOSEngine_Waxworks::printBox() {
1038 uint16 BoxSize;
1039
1040 *_boxBufferPtr = 0;
1041 _linePtrs[0] = _boxBuffer;
1042 if (_boxCR == 0)
1043 _boxLineCount++;
1044 stopAnimate(105);
1045 BoxSize = getBoxSize();
1046 _variableArray[53] = BoxSize;
1047 animate(3, 1, 100, 0, 0, 0);
1048 changeWindow(5);
1049
1050 switch (BoxSize) {
1051 case 1: _textWindow->x = 10;
1052 _textWindow->y = 163;
1053 _textWindow->width = 20;
1054 _textWindow->height = 1;
1055 _textWindow->textMaxLength = 26;
1056 break;
1057 case 2: _textWindow->x = 8;
1058 _textWindow->y = 160;
1059 _textWindow->width = 24;
1060 _textWindow->height = 2;
1061 _textWindow->textMaxLength = 32;
1062 break;
1063 case 3: _textWindow->x = 6;
1064 _textWindow->y = 156;
1065 _textWindow->width = 28;
1066 _textWindow->height = 3;
1067 _textWindow->textMaxLength = 37;
1068 break;
1069 case 4: _textWindow->x = 4;
1070 _textWindow->y = 153;
1071 _textWindow->width = 32;
1072 _textWindow->height = 4;
1073 _textWindow->textMaxLength = 42;
1074 break;
1075 case 5: _textWindow->x = 2;
1076 _textWindow->y = 150;
1077 _textWindow->width = 36;
1078 _textWindow->height = 5;
1079 _textWindow->textMaxLength = 48;
1080 break;
1081 default:_textWindow->x = 1;
1082 _textWindow->y = 147;
1083 _textWindow->width = 38;
1084 _textWindow->height = 6;
1085 _textWindow->textMaxLength = 50;
1086 break;
1087 }
1088 _textWindow->textColumn = 0;
1089 _textWindow->textRow = 0;
1090 _textWindow->textColumnOffset = 0;
1091 _textWindow->textLength = 0;
1092 justifyStart();
1093 waitForSync(99);
1094 _boxBufferPtr = _boxBuffer;
1095 while (*_boxBufferPtr)
1096 justifyOutPut(*_boxBufferPtr++);
1097 _boxLineCount = 0;
1098 _boxBufferPtr = _boxBuffer;
1099 _lineCounts[0] = 0;
1100 _lineCounts[1] = 0;
1101 _lineCounts[2] = 0;
1102 _lineCounts[3] = 0;
1103 _lineCounts[4] = 0;
1104 _lineCounts[5] = 0;
1105 changeWindow(0);
1106 }
1107
1108 } // End of namespace AGOS
1109