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 #2780: 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 alignTableMem();
336
337 if (_tablesHeapCurPos > _tablesHeapSize) {
338 error("loadTextIntoMem: Out of table memory");
339 }
340 return;
341 }
342
343 baseMin = baseMax;
344 }
345
346 error("loadTextIntoMem: didn't find %d", stringId);
347 }
348
349 static const byte polish_charWidth[226] = {
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, 0, 0, 0, 0, 0, 0, 0, 0,
353 0, 0, 6, 2, 8, 7, 6,10, 8, 2,
354 4, 4, 7, 6, 3, 4, 2, 3, 6, 4,
355 6, 6, 7, 6, 6, 6, 6, 6, 2, 8,
356 6, 9, 7, 6, 6, 8, 7, 8, 8, 7,
357 6, 9, 8, 2, 6, 7, 6,10, 8, 9,
358 7, 9, 7, 7, 8, 8, 8,12, 8, 8,
359 7, 6, 7, 6, 4, 7, 7, 7, 7, 6,
360 7, 7, 4, 7, 6, 2, 3, 6, 2,10,
361 6, 7, 7, 7, 5, 6, 4, 6, 6,10,
362 6, 6, 6, 0, 0, 0, 0, 0, 8, 6,
363 7, 7, 7, 7, 7, 6, 7, 7, 7, 4,
364 4, 3, 8, 8, 7, 0, 0, 7, 7, 7,
365 6, 6, 6, 9, 8, 0, 0, 0, 0, 0,
366 7, 3, 7, 6, 6, 8, 0, 0, 6, 0,
367 0, 0, 0, 2, 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, 0, 0, 0, 0, 0,
372 0, 0, 0, 0, 0, 7
373 };
374
375 static const byte charWidth[226] = {
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, 0, 0, 0, 0, 0, 0, 0, 0,
379 0, 0, 6, 2, 4, 8, 6,10, 9, 2,
380 4, 4, 6, 6, 3, 4, 2, 3, 6, 4,
381 6, 6, 7, 6, 6, 6, 6, 6, 2, 3,
382 7, 7, 7, 6,11, 8, 7, 8, 8, 7,
383 6, 9, 8, 2, 6, 7, 6,10, 8, 9,
384 7, 9, 7, 7, 8, 8, 8,12, 8, 8,
385 7, 3, 3, 3, 6, 8, 3, 7, 7, 6,
386 7, 7, 4, 7, 6, 2, 3, 6, 2,10,
387 6, 7, 7, 7, 5, 6, 4, 7, 7,10,
388 6, 6, 6, 0, 0, 0, 0, 0, 8, 6,
389 7, 7, 7, 7, 7, 6, 7, 7, 7, 4,
390 4, 3, 8, 8, 7, 0, 0, 7, 7, 7,
391 6, 6, 6, 9, 8, 0, 0, 0, 0, 0,
392 7, 3, 7, 6, 6, 8, 0, 6, 0, 0,
393 0, 0, 0, 2, 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, 0, 0, 0, 0, 0,
398 0, 0, 0, 0, 0, 7
399 };
400
getPixelLength(const char * string,uint16 maxWidth,uint16 & pixels)401 const char *AGOSEngine::getPixelLength(const char *string, uint16 maxWidth, uint16 &pixels) {
402 pixels = 0;
403
404 while (*string != 0) {
405 byte chr = *string;
406 uint8 len = (_language == Common::PL_POL) ? polish_charWidth[chr] : charWidth[chr];
407 if ((pixels + len) > maxWidth)
408 break;
409 pixels += len;
410 string++;
411 }
412
413 return string;
414 }
415
printTextOf(uint a,uint x,uint y)416 bool AGOSEngine::printTextOf(uint a, uint x, uint y) {
417 const byte *stringPtr;
418 uint16 pixels, w;
419
420 if (getGameType() == GType_SIMON2) {
421 if (getBitFlag(79)) {
422 Subroutine *sub;
423 _variableArray[84] = a;
424 sub = getSubroutineByID(5003);
425 if (sub != NULL)
426 startSubroutineEx(sub);
427 return true;
428 }
429 }
430
431 if (a >= _numTextBoxes)
432 return false;
433
434
435 stringPtr = getStringPtrByID(_shortText[a]);
436 if (getGameType() == GType_FF) {
437 getPixelLength((const char *)stringPtr, 400, pixels);
438 w = pixels + 1;
439 x -= w / 2;
440 printScreenText(6, 0, (const char *)stringPtr, x, y, w);
441 } else {
442 showActionString(stringPtr);
443 }
444
445 return true;
446 }
447
printNameOf(Item * item,uint x,uint y)448 bool AGOSEngine::printNameOf(Item *item, uint x, uint y) {
449 SubObject *subObject;
450 const byte *stringPtr;
451 uint16 pixels, w;
452
453 if (item == 0 || item == _dummyItem2 || item == _dummyItem3)
454 return false;
455
456 subObject = (SubObject *)findChildOfType(item, kObjectType);
457 if (subObject == NULL)
458 return false;
459
460 stringPtr = getStringPtrByID(subObject->objectName);
461 if (getGameType() == GType_FF) {
462 getPixelLength((const char *)stringPtr, 400, pixels);
463 w = pixels + 1;
464 x -= w / 2;
465 printScreenText(6, 0, (const char *)stringPtr, x, y, w);
466 } else {
467 showActionString(stringPtr);
468 }
469
470 return true;
471 }
472
printScreenText(uint vgaSpriteId,uint color,const char * string,int16 x,int16 y,int16 width)473 void AGOSEngine::printScreenText(uint vgaSpriteId, uint color, const char *string, int16 x, int16 y, int16 width) {
474 char convertedString[320];
475 char *convertedString2 = convertedString;
476 int16 height, talkDelay;
477 int stringLength = strlen(string);
478 int padding, lettersPerRow, lettersPerRowJustified;
479 const int textHeight = 10;
480
481 height = textHeight;
482 lettersPerRow = width / 6;
483 lettersPerRowJustified = stringLength / (stringLength / lettersPerRow + 1) + 1;
484
485 talkDelay = (stringLength + 3) / 3;
486 if (getGameType() == GType_SIMON1 && (getFeatures() & GF_TALKIE)) {
487 if (_variableArray[141] == 0)
488 _variableArray[141] = 9;
489 _variableArray[85] = _variableArray[141] * talkDelay;
490
491 if (_language == Common::HE_ISR)
492 _variableArray[85] += talkDelay * 2;
493 } else {
494 if (_variableArray[86] == 0)
495 talkDelay /= 2;
496 if (_variableArray[86] == 2)
497 talkDelay *= 2;
498 _variableArray[85] = talkDelay * 5;
499 }
500
501 assert(stringLength > 0);
502
503 while (stringLength > 0) {
504 int pos = 0;
505 if (stringLength > lettersPerRow) {
506 int removeLastWord = 0;
507 if (lettersPerRow > lettersPerRowJustified) {
508 pos = lettersPerRowJustified;
509 while (string[pos] != ' ')
510 pos++;
511 if (pos > lettersPerRow)
512 removeLastWord = 1;
513 }
514 if (lettersPerRow <= lettersPerRowJustified || removeLastWord) {
515 pos = lettersPerRow;
516 while (string[pos] != ' ' && pos > 0)
517 pos--;
518 }
519 height += textHeight;
520 y -= textHeight;
521 } else
522 pos = stringLength;
523 padding = ((lettersPerRow - pos) % 2) ? (lettersPerRow - pos) / 2 + 1 : (lettersPerRow - pos) / 2;
524 while (padding--)
525 *convertedString2++ = ' ';
526 stringLength -= pos;
527 while (pos--)
528 *convertedString2++ = *string++;
529 *convertedString2++ = '\n';
530 string++; // skip space
531 stringLength--; // skip space
532 }
533 *(convertedString2 - 1) = '\0';
534
535 if (getGameType() == GType_SIMON1)
536 stopAnimate(vgaSpriteId + 199);
537 else
538 stopAnimateSimon2(2, vgaSpriteId);
539
540 if (getPlatform() == Common::kPlatformAmiga) {
541 color = color * 3 + 1;
542 renderStringAmiga(vgaSpriteId, color, width, height, convertedString);
543 } else {
544 color = color * 3 + 192;
545 renderString(vgaSpriteId, color, width, height, convertedString);
546 }
547
548 uint16 windowNum = (!getBitFlag(133)) ? 3 : 4;
549 if (getGameType() == GType_SIMON1 && (getFeatures() & GF_DEMO))
550 windowNum = 4;
551
552 x /= 8;
553 if (y < 2)
554 y = 2;
555
556 if (getGameType() == GType_SIMON1) {
557 uint16 id = 199 + vgaSpriteId;
558 animate(windowNum, id / 100, id, x, y, 12);
559 } else {
560 animate(windowNum, 2, vgaSpriteId, x, y, 12);
561 }
562 }
563
564 #ifdef ENABLE_AGOS2
565 // Swampy Adventures specific
printInfoText(const char * itemText)566 void AGOSEngine_PuzzlePack::printInfoText(const char *itemText) {
567 const char *itemName = NULL;
568 int flag = (_mouse.y / 32) * 20 + (_mouse.x / 32) + 1300;
569
570 switch (_variableArray[999]) {
571 case 80:
572 if (_variableArray[flag]) {
573 if (_variableArray[flag] == 201)
574 itemName = " Bridge: ";
575 if (_variableArray[flag] == 231 || _variableArray[flag] == 241)
576 itemName = " Log: ";
577 if (_variableArray[flag] == 281)
578 itemName = " Rubble: ";
579 if (_variableArray[flag] == 291)
580 itemName = " Boulder: ";
581 if (_variableArray[flag] == 311)
582 itemName = " Key: ";
583 if (_variableArray[flag] == 312)
584 itemName = " Spanner: ";
585 if (_variableArray[flag] == 321)
586 itemName = " Gate: ";
587 if (_variableArray[flag] == 331)
588 itemName = " Crate: ";
589 } else {
590 flag -= 300;
591 if (_variableArray[flag] == 2)
592 itemName = " Water: ";
593 if (_variableArray[flag] == 5)
594 itemName = " Exit: ";
595 if ((_variableArray[flag] == 5) && (_variableArray[81] == 10))
596 itemName = " Gem: ";
597 if (_variableArray[flag] == 236 || _variableArray[flag] == 246)
598 itemName = " Floating Log: ";
599 if (_variableArray[flag] == 400)
600 itemName = " Valve: ";
601 }
602 break;
603
604 case 81:
605 if (_variableArray[flag]) {
606 if (_variableArray[flag] == 281)
607 itemName = " Cracked Block: ";
608 if (_variableArray[flag] == 291)
609 itemName = " Boulder: ";
610 if (_variableArray[flag] == 331)
611 itemName = " Block: ";
612 if (_variableArray[flag] == 341)
613 itemName = " Switch: ";
614 if (_variableArray[flag] == 343)
615 itemName = " Button: ";
616 if ((_variableArray[flag] > 430) && (_variableArray[flag] < 480))
617 itemName = " Mosaic Block: ";
618 } else {
619 flag -= 300;
620 if (_variableArray[flag] == 5)
621 itemName = " Exit: ";
622 if ((_variableArray[flag] == 5) && (_variableArray[82] == 10))
623 itemName = " Gem: ";
624 }
625 break;
626
627 case 82:
628 if (_variableArray[flag]) {
629 if (_variableArray[flag] == 201 || _variableArray[flag] == 211)
630 itemName = " Unstable Track: ";
631 if (_variableArray[flag] == 281)
632 itemName = " Rubble Pile: ";
633 if (_variableArray[flag] == 291)
634 itemName = " Boulder: ";
635 if (_variableArray[flag] == 331)
636 itemName = " Crate: ";
637 if (_variableArray[flag] == 401 || _variableArray[flag] == 405)
638 itemName = " Cart: ";
639 } else {
640 flag -= 300;
641 if (_variableArray[flag] == 4)
642 itemName = " Hole: ";
643 if (_variableArray[flag] == 5)
644 itemName = " Exit: ";
645 if ((_variableArray[flag] == 5) && (_variableArray[83] == 10))
646 itemName = " Gem: ";
647 if ((_variableArray[flag] > 5) && (_variableArray[flag] < 10))
648 itemName = " Buffer Track: ";
649 if ((_variableArray[flag] > 9) && (_variableArray[flag] < 40))
650 itemName = " Track: ";
651 if (_variableArray[flag] == 300)
652 itemName = " Boulder: ";
653 }
654 break;
655
656 case 83:
657 if (_variableArray[flag]) {
658 if (_variableArray[flag] == 201)
659 itemName = " Broken Floor: ";
660 if (_variableArray[flag] == 231 || _variableArray[flag] == 241)
661 itemName = " Barrel: ";
662 if (_variableArray[flag] == 281)
663 itemName = " Cracked Rock: ";
664 if (_variableArray[flag] == 291)
665 itemName = " Spacehopper: ";
666 if (_variableArray[flag] == 311)
667 itemName = " Key: ";
668 if (_variableArray[flag] == 321)
669 itemName = " Trapdoor: ";
670 if (_variableArray[flag] == 324)
671 itemName = " Trapdoor: ";
672 if (_variableArray[flag] == 331)
673 itemName = " Crate: ";
674 } else {
675 flag -= 300;
676 if (_variableArray[flag] == 4)
677 itemName = " Hole: ";
678 if (_variableArray[flag] == 239 || _variableArray[flag] == 249)
679 itemName = " Barrel: ";
680 }
681 break;
682
683 case 84:
684 if (_variableArray[flag]) {
685 if (_variableArray[flag] == 201)
686 itemName = " Floating Platform: ";
687 if (_variableArray[flag] == 231)
688 itemName = " Cauldron: ";
689 if (_variableArray[flag] == 281)
690 itemName = " Cracked Block: ";
691 if (_variableArray[flag] == 311 || _variableArray[flag] == 312)
692 itemName = " Key: ";
693 if (_variableArray[flag] == 321 || _variableArray[flag] == 361 || _variableArray[flag] == 371)
694 itemName = " Gate: ";
695 if (_variableArray[flag] == 331)
696 itemName = " Chest: ";
697 if (_variableArray[flag] == 332)
698 itemName = " Jewel: ";
699 if (_variableArray[flag] == 351 || _variableArray[flag] == 352)
700 itemName = " Babies: ";
701 } else {
702 flag -= 300;
703 if (_variableArray[flag] == 6)
704 itemName = " Slime: ";
705 if (_variableArray[flag] == 334)
706 itemName = " Chest: ";
707 }
708 break;
709
710 default:
711 break;
712 }
713
714 if (itemName != NULL) {
715 Common::String buf = Common::String::format("%s\n%s", itemName, itemText);
716 GUI::TimedMessageDialog dialog(buf, 1500);
717 dialog.runModal();
718 }
719 }
720
721 // The Feeble Files specific
printScreenText(uint vgaSpriteId,uint color,const char * string,int16 x,int16 y,int16 width)722 void AGOSEngine_Feeble::printScreenText(uint vgaSpriteId, uint color, const char *string, int16 x, int16 y, int16 width) {
723 char convertedString[320];
724 char *convertedString2 = convertedString;
725 const char *string2 = string;
726 int16 height, talkDelay;
727 int stringLength = strlen(string);
728 const int textHeight = 15;
729
730 height = textHeight;
731
732 talkDelay = (stringLength + 3) / 3;
733 if (_variableArray[86] == 0)
734 talkDelay /= 2;
735 if (_variableArray[86] == 2)
736 talkDelay *= 2;
737 _variableArray[85] = talkDelay * 5;
738
739 assert(stringLength > 0);
740
741 uint16 b, pixels, spaces;
742
743 while (1) {
744 string2 = getPixelLength(string, width, pixels);
745 if (*string2 == 0) {
746 spaces = (width - pixels) / 12;
747 if (spaces != 0)
748 spaces--;
749 while (spaces) {
750 *convertedString2++ = ' ';
751 spaces--;
752 }
753 strcpy(convertedString2, string);
754 break;
755 }
756 while (*string2 != ' ') {
757 byte chr = *string2;
758 pixels -= (_language == Common::PL_POL) ? polish_charWidth[chr] : charWidth[chr];
759 string2--;
760 }
761 spaces = (width - pixels) / 12;
762 if (spaces != 0)
763 spaces--;
764 while (spaces) {
765 *convertedString2++ = ' ';
766 spaces--;
767 }
768 b = string2 - string;
769 strncpy(convertedString2, string, b);
770 convertedString2 += b;
771 *convertedString2++ = '\n';
772 height += textHeight;
773 y -= textHeight;
774 if (y < 2)
775 y = 2;
776 string = string2;
777 }
778
779 stopAnimateSimon2(2, vgaSpriteId);
780
781 renderString(1, color, width, height, convertedString);
782
783 animate(4, 2, vgaSpriteId, x, y, 12);
784 }
785
printInteractText(uint16 num,const char * string)786 void AGOSEngine_Feeble::printInteractText(uint16 num, const char *string) {
787 char convertedString[320];
788 char *convertedString2 = convertedString;
789 const char *string2 = string;
790 uint16 height = 15;
791 uint16 w = 0xFFFF;
792 uint16 b, pixels, x;
793
794 // It doesn't really matter what 'w' is to begin with, as long as it's
795 // something that cannot be generated by getPixelLength(). The original
796 // used 620, which was a potential problem.
797
798 while (1) {
799 string2 = getPixelLength(string, 620, pixels);
800 if (*string2 == 0x00) {
801 if (w == 0xFFFF)
802 w = pixels;
803 Common::strlcpy(convertedString2, string, 320);
804 break;
805 }
806 while (*string2 != ' ') {
807 byte chr = *string2;
808 pixels -= (_language == Common::PL_POL) ? polish_charWidth[chr] : charWidth[chr];
809 string2--;
810 }
811 if (w == 0xFFFF)
812 w = pixels;
813 b = string2 - string;
814 strncpy(convertedString2, string, b);
815 convertedString2 += b;
816 *convertedString2++ = '\n';
817 height += 15;
818 string = string2;
819 }
820
821 // ScrollX
822 x = _variableArray[251];
823 x += 20;
824
825 if (num == 1)
826 _interactY = 385;
827
828 // Returned values for box definition
829 _variableArray[51] = x;
830 _variableArray[52] = _interactY;
831 _variableArray[53] = w;
832 _variableArray[54] = height;
833
834 stopAnimateSimon2(2, num + 6);
835 renderString(num, 0, w, height, convertedString);
836 animate(4, 2, num + 6, x, _interactY, 12);
837
838 _interactY += height;
839 }
840
sendInteractText(uint16 num,const char * fmt,...)841 void AGOSEngine_Feeble::sendInteractText(uint16 num, const char *fmt, ...) {
842 va_list arglist;
843
844 va_start(arglist, fmt);
845 Common::String string = Common::String::vformat(fmt, arglist);
846 va_end(arglist);
847
848 printInteractText(num, string.c_str());
849 }
850 #endif
851
852 // Waxworks specific
getBoxSize()853 uint16 AGOSEngine_Waxworks::getBoxSize() {
854 int x;
855 switch (_boxLineCount) {
856 case 1: x = _lineCounts[0];
857 if (x <= 26)
858 return 1;
859 if (x <= 64)
860 if (checkFit(_linePtrs[0], 32, 2))
861 return 2;
862 if (x <= 111)
863 if (checkFit(_linePtrs[0], 37, 3))
864 return 3;
865 if (x <= 168)
866 if (checkFit(_linePtrs[0], 42, 4))
867 return 4;
868 if (x <= 240)
869 if (checkFit(_linePtrs[0], 48, 5))
870 return 5;
871 return 6;
872 case 2: if (_lineCounts[0] <= 32) {
873 if (_lineCounts[1] <= 32)
874 return 2;
875 if (_lineCounts[1] <= 74)
876 if (checkFit(_linePtrs[1], 37, 2))
877 return 3;
878 if (_lineCounts[1] <= 126)
879 if (checkFit(_linePtrs[1], 42, 3))
880 return 4;
881 if (_lineCounts[1] <= 172)
882 if (checkFit(_linePtrs[1], 48, 4))
883 return 5;
884 return 6;
885 }
886 if ((_lineCounts[0] <= 74) && (checkFit(_linePtrs[0], 37, 2))) {
887 if (_lineCounts[1] <= 37)
888 return 3;
889 if (_lineCounts[1] <= 84)
890 if (checkFit(_linePtrs[1], 42, 2))
891 return 4;
892 if (_lineCounts[1] <= 144)
893 if (checkFit(_linePtrs[1], 48, 3))
894 return 5;
895 return 6;
896 }
897 if ((_lineCounts[0] <= 126) && (checkFit(_linePtrs[0], 42, 3))) {
898 if (_lineCounts[1] <= 42)
899 return 4;
900 if (_lineCounts[1] <= 84)
901 if (checkFit(_linePtrs[1], 48, 2))
902 return 5;
903 return 6;
904 }
905 if ((_lineCounts[0] <= 192) && (checkFit(_linePtrs[0], 48, 4))) {
906 if (_lineCounts[1] <= 48)
907 return 5;
908 return 6;
909 }
910 return 6;
911 case 3: if (_lineCounts[0] <= 37) {
912 if (_lineCounts[1] <= 37) {
913 if (_lineCounts[2] <= 37)
914 return 3;
915 if (_lineCounts[2] <= 84)
916 if (checkFit(_linePtrs[2], 42, 2))
917 return 4;
918 if (_lineCounts[2] <= 144)
919 if (checkFit(_linePtrs[2], 48, 3))
920 return 5;
921 return 6;
922 }
923 if ((_lineCounts[1] <= 84) && (checkFit(_linePtrs[1], 42, 2))) {
924 if (_lineCounts[2] <= 42)
925 return 4;
926 if (_lineCounts[2] <= 96)
927 if (checkFit(_linePtrs[2], 48, 2))
928 return 5;
929 return 6;
930 }
931 if ((_lineCounts[1] <= 144) && (checkFit(_linePtrs[1], 48, 3))) {
932 if (_lineCounts[2] <= 48)
933 return 5;
934 return 6;
935 }
936 return 6;
937 }
938 if ((_lineCounts[0] <= 84) && (checkFit(_linePtrs[0], 42, 2))) {
939 if (_lineCounts[1] <= 42) {
940 if (_lineCounts[2] <= 42)
941 return 4;
942 if (_lineCounts[2] <= 96)
943 if (checkFit(_linePtrs[2], 48, 2))
944 return 5;
945 return 6;
946 }
947 if ((_lineCounts[1] <= 96) && (checkFit(_linePtrs[1], 48, 2))) {
948 if (_lineCounts[2] <= 48)
949 return 5;
950 return 6;
951 }
952 return 6;
953 }
954 if ((_lineCounts[0] <= 96) && (checkFit(_linePtrs[0], 48, 3))) {
955 if (_lineCounts[1] <= 48) {
956 if (_lineCounts[2] <= 48)
957 return 5;
958 }
959 return 6;
960 }
961 return 6;
962 case 4: if (_lineCounts[0] <= 42) {
963 if (_lineCounts[1] <= 42) {
964 if (_lineCounts[2] <= 42) {
965 if (_lineCounts[3] <= 42)
966 return 4;
967 if (_lineCounts[3] <= 96)
968 if (checkFit(_linePtrs[3], 48, 2))
969 return 5;
970 return 6;
971 }
972 if ((_lineCounts[2] <= 96) && (checkFit(_linePtrs[2], 48, 2)))
973 if (_lineCounts[3] <= 48)
974 return 5;
975 return 6;
976 }
977 if ((_lineCounts[1] <= 96) && (checkFit(_linePtrs[1], 48, 2)))
978 if ((_lineCounts[2] <= 48) && (_lineCounts[3] <= 48))
979 return 5;
980 return 6;
981 }
982 if ((_lineCounts[0] <= 96) && (checkFit(_linePtrs[0], 48, 2)))
983 if ((_lineCounts[1] <= 48) && (_lineCounts[2] <= 48) && (_lineCounts[3] <= 48))
984 return 5;
985 return 6;
986 case 5: if ((_lineCounts[0] > 48) || (_lineCounts[1] > 48) || (_lineCounts[2] > 48)
987 || (_lineCounts[3] > 48) || (_lineCounts[4] > 48))
988 return 6;
989 else
990 return 5;
991 default:
992 return 6;
993 }
994 }
995
996
checkFit(char * ptr,int width,int lines)997 uint16 AGOSEngine_Waxworks::checkFit(char *ptr, int width, int lines) {
998 int countw = 0;
999 int countl = 0;
1000 char *x = NULL;
1001 while (*ptr) {
1002 if (*ptr == '\n')
1003 return 1;
1004 if (countw == width) {
1005 countl++;
1006 countw = 0;
1007 ptr = x;
1008 }
1009 if (*ptr == ' ') {
1010 x = ptr;
1011 x++;
1012 }
1013 countw++;
1014 if (countl == lines)
1015 return 0;
1016 ptr++;
1017 }
1018
1019 return 1;
1020 }
1021
boxTextMessage(const char * x)1022 void AGOSEngine_Waxworks::boxTextMessage(const char *x) {
1023 sprintf(_boxBufferPtr, "%s\n", x);
1024 _lineCounts[_boxLineCount] += strlen(x);
1025 _boxBufferPtr += strlen(x) + 1;
1026 _boxLineCount++;
1027 _linePtrs[_boxLineCount] = _boxBufferPtr;
1028 _boxCR = 1;
1029 }
1030
boxTextMsg(const char * x)1031 void AGOSEngine_Waxworks::boxTextMsg(const char *x) {
1032 sprintf(_boxBufferPtr, "%s", x);
1033 _lineCounts[_boxLineCount] += strlen(x);
1034 _boxBufferPtr += strlen(x);
1035 _boxCR = 0;
1036 }
1037
printBox()1038 void AGOSEngine_Waxworks::printBox() {
1039 uint16 BoxSize;
1040
1041 *_boxBufferPtr = 0;
1042 _linePtrs[0] = _boxBuffer;
1043 if (_boxCR == 0)
1044 _boxLineCount++;
1045 stopAnimate(105);
1046 BoxSize = getBoxSize();
1047 _variableArray[53] = BoxSize;
1048 animate(3, 1, 100, 0, 0, 0);
1049 changeWindow(5);
1050
1051 switch (BoxSize) {
1052 case 1: _textWindow->x = 10;
1053 _textWindow->y = 163;
1054 _textWindow->width = 20;
1055 _textWindow->height = 1;
1056 _textWindow->textMaxLength = 26;
1057 break;
1058 case 2: _textWindow->x = 8;
1059 _textWindow->y = 160;
1060 _textWindow->width = 24;
1061 _textWindow->height = 2;
1062 _textWindow->textMaxLength = 32;
1063 break;
1064 case 3: _textWindow->x = 6;
1065 _textWindow->y = 156;
1066 _textWindow->width = 28;
1067 _textWindow->height = 3;
1068 _textWindow->textMaxLength = 37;
1069 break;
1070 case 4: _textWindow->x = 4;
1071 _textWindow->y = 153;
1072 _textWindow->width = 32;
1073 _textWindow->height = 4;
1074 _textWindow->textMaxLength = 42;
1075 break;
1076 case 5: _textWindow->x = 2;
1077 _textWindow->y = 150;
1078 _textWindow->width = 36;
1079 _textWindow->height = 5;
1080 _textWindow->textMaxLength = 48;
1081 break;
1082 default:_textWindow->x = 1;
1083 _textWindow->y = 147;
1084 _textWindow->width = 38;
1085 _textWindow->height = 6;
1086 _textWindow->textMaxLength = 50;
1087 break;
1088 }
1089 _textWindow->textColumn = 0;
1090 _textWindow->textRow = 0;
1091 _textWindow->textColumnOffset = 0;
1092 _textWindow->textLength = 0;
1093 justifyStart();
1094 waitForSync(99);
1095 _boxBufferPtr = _boxBuffer;
1096 while (*_boxBufferPtr)
1097 justifyOutPut(*_boxBufferPtr++);
1098 _boxLineCount = 0;
1099 _boxBufferPtr = _boxBuffer;
1100 _lineCounts[0] = 0;
1101 _lineCounts[1] = 0;
1102 _lineCounts[2] = 0;
1103 _lineCounts[3] = 0;
1104 _lineCounts[4] = 0;
1105 _lineCounts[5] = 0;
1106 changeWindow(0);
1107 }
1108
1109 } // End of namespace AGOS
1110