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 "agos/agos.h"
24 #include "agos/intern.h"
25
26 #include "common/textconsole.h"
27
28 namespace AGOS {
29
ftext(uint32 base,int n)30 uint32 AGOSEngine_PN::ftext(uint32 base, int n) {
31 uint32 b = base;
32 int ct = n;
33 while (ct) {
34 while (_textBase[b++])
35 ;
36 ct--;
37 }
38 return b;
39 }
40
unctok(char * c,int n)41 char *AGOSEngine_PN::unctok(char *c, int n) {
42 int x;
43 uint8 *tokbase;
44 tokbase = _textBase + getlong(30);
45 x = n;
46 while (x-=(*tokbase++ > 127))
47 ;
48 while (*tokbase < 128)
49 *c++=*tokbase++;
50 *c++ = *tokbase & 127;
51 *c = 0;
52 return c;
53 }
54
uncomstr(char * c,uint32 x)55 void AGOSEngine_PN::uncomstr(char *c, uint32 x) {
56 if (x > _textBaseSize)
57 error("UNCOMSTR: TBASE over-run");
58 while (_textBase[x]) {
59 if (_textBase[x] < 244) {
60 c = unctok(c, _textBase[x]);
61 } else {
62 c = unctok(c, (_textBase[x] - 244) * 254 + _textBase[x + 1] - 1);
63 x++;
64 }
65 x++;
66 }
67 *c++ = 13;
68 *c = 0;
69 }
70
71 static const char *const objectNames[30] = {
72 "\0",
73 "Take \0",
74 "Inventory\r",
75 "Open \0",
76 "Close \0",
77 "Lock \0",
78 "Unlock \0",
79 "Examine \0",
80 "Look in \0",
81 "Exits \r",
82 "Look\r",
83 "Wait\r",
84 "Pause\r",
85 "\0",
86 "Save\r",
87 "Restore\r",
88 "\0",
89 "N\r",
90 "NE\r",
91 "E\r",
92 "SE\r",
93 "S\r",
94 "SW\r",
95 "W\r",
96 "NW\r",
97 "INVENTORY\r",
98 "ROOM DESCRIPTION\r",
99 "x\r",
100 "MORE\r",
101 "CLOSE\r"
102 };
103
getObjectName(char * v,uint16 x)104 void AGOSEngine_PN::getObjectName(char *v, uint16 x) {
105 if (x & 0x8000) {
106 x &= ~0x8000;
107 if (x > getptr(51))
108 error("getObjectName: Object %d out of range", x);
109 uncomstr(v, ftext(getlong(27), x * _dataBase[47]));
110 } else {
111 assert(x < 30);
112 strcpy(v, objectNames[x]);
113 }
114 }
115
pcl(const char * s)116 void AGOSEngine_PN::pcl(const char *s) {
117 Common::strlcat(_sb, s, 80);
118 if (strchr(s, '\n') == 0) {
119 for (char *str = _sb; *str; str++)
120 windowPutChar(_windowArray[_curWindow], *str);
121 strcpy(_sb, "");
122 }
123 }
124
pcf(uint8 ch)125 void AGOSEngine_PN::pcf(uint8 ch) {
126 int ct = 0;
127 if (ch == '[')
128 ch = '\n';
129 if (ch == 0)
130 return; /* Trap any C EOS chrs */
131 if (ch == 255) {
132 _bp = 0;
133 _xofs = 0;
134 return; /* pcf(255) initializes the routine */
135 } /* pcf(254) flushes its working _buffer */
136 if (ch != 254) {
137 if ((ch != 32) || (_bp + _xofs != 50))
138 _buffer[_bp++] = ch;
139 }
140 if ((ch != 254) && (!Common::isSpace(ch)) && (_bp < 60))
141 return;
142 /* We know have a case of needing to print the text */
143 if (_bp + _xofs > 50) {
144 pcl("\n");
145 if (_buffer[0] == ' ')
146 ct = 1; /* Skip initial space */
147 /* Note ' ' will give a single start of line space */
148 _xofs = 0;
149 }
150 _buffer[_bp] = 0;
151 pcl(_buffer + ct);
152 _xofs += _bp;
153 _bp = 0;
154 if (ch == '\n')
155 _xofs = 0; /* At Newline! */
156 }
157
patok(int n)158 void AGOSEngine_PN::patok(int n) {
159 int x;
160 uint8 *tokbase;
161 tokbase = _textBase + getlong(30);
162 x = n;
163 while (x -= (*tokbase++ > 127))
164 ;
165 while (*tokbase < 128)
166 pcf(*tokbase++);
167 pcf((uint8)(*tokbase & 127));
168 }
169
pmesd(int n)170 void AGOSEngine_PN::pmesd(int n) {
171 ptext(ftext(getlong(24), n));
172 }
173
plocd(int n,int m)174 void AGOSEngine_PN::plocd(int n, int m) {
175 if (n > getptr(53))
176 error("Location out of range");
177 ptext(ftext(getlong(21), n * _dataBase[48] + m));
178 }
179
pobjd(int n,int m)180 void AGOSEngine_PN::pobjd(int n, int m) {
181 if (n > getptr(51))
182 error("Object out of range");
183 ptext(ftext(getlong(27), n * _dataBase[47] + m));
184 }
185
ptext(uint32 tptr)186 void AGOSEngine_PN::ptext(uint32 tptr) {
187 if (tptr > _textBaseSize)
188 error("ptext: attempt to print beyond end of TBASE");
189
190 while (_textBase[tptr]) {
191 if (_textBase[tptr] < 244) {
192 patok(_textBase[tptr++]);
193 } else {
194 patok((_textBase[tptr] - 244) * 254 + _textBase[tptr + 1] - 1);
195 tptr += 2;
196 }
197 }
198 }
199
200 const uint8 characters[11][80] = {
201 // PETERMASON
202 {
203 118, 225,
204 91, 118,
205 94, 124,
206 236, 161,
207 241, 166,
208 168, 4,
209 138, 46,
210 139, 46,
211 249, 50,
212 38, 56,
213 80, 59,
214 149, 69,
215 37, 77,
216 93, 93,
217 86, 95,
218 0,
219 0,
220 58, 130,
221 62, 178,
222 83, 95,
223 0,
224 121, 58,
225 122, 59,
226 126, 60,
227 124, 61,
228 240, 62,
229 123, 63,
230 0
231 },
232 // JBLANDFORD
233 {
234 0,
235 0,
236 0,
237 0
238 },
239 // SBLANDFORD
240 {
241 120, 223,
242 94, 126,
243 112, 134,
244 45, 152,
245 241, 166,
246 168, 3,
247 150, 26,
248 220, 29,
249 138, 42,
250 139, 47,
251 249, 50,
252 38, 56,
253 230, 64,
254 37, 77,
255 93, 94,
256 86, 96,
257 0,
258 0,
259 58, 129,
260 59, 112,
261 83, 96,
262 81, 106,
263 62, 169,
264 0,
265 121, 54,
266 122, 55,
267 119, 56,
268 118, 57,
269 0
270 },
271 // MRJONES
272 {
273 121, 218,
274 91, 118,
275 253, 121,
276 154, 138,
277 235, 173,
278 236, 161,
279 241, 165,
280 168, 0,
281 150, 21,
282 36, 33,
283 138, 42,
284 249, 50,
285 80, 60,
286 4, 60,
287 37, 78,
288 68, 33,
289 93, 92,
290 101, 109,
291 0,
292 36, 35,
293 68, 90,
294 0,
295 58, 128,
296 59, 111,
297 62, 182,
298 0,
299 122, 13,
300 126, 14,
301 124, 15,
302 240, 16,
303 120, 17,
304 119, 18,
305 118, 19,
306 52, 20,
307 125, 21,
308 127, 22,
309 123, 23,
310 117, 24,
311 0
312 },
313 // MRSJONES
314 {
315 122, 219,
316 91, 119,
317 253, 123,
318 112, 136,
319 154, 137,
320 95, 142,
321 45, 152,
322 109, 155,
323 235, 160,
324 168, 1,
325 151, 13,
326 145, 15,
327 150, 22,
328 220, 28,
329 36, 33,
330 138, 43,
331 13, 51,
332 80, 59,
333 230, 64,
334 149, 69,
335 86, 100,
336 0,
337 36, 36,
338 0,
339 58, 127,
340 62, 179,
341 83, 100,
342 81, 102,
343 0,
344 121, 25,
345 126, 26,
346 124, 27,
347 120, 28,
348 119, 29,
349 118, 30,
350 52, 31,
351 125, 32,
352 127, 33,
353 123, 34,
354 117, 35,
355 0
356 },
357 // MRROBERTS
358 {
359 123, 229,
360 91, 117,
361 253, 120,
362 94, 125,
363 112, 134,
364 109, 156,
365 235, 172,
366 236, 162,
367 241, 165,
368 168, 3,
369 36, 33,
370 249, 50,
371 38, 56,
372 80, 58,
373 37, 75,
374 34, 81,
375 68, 33,
376 101, 109,
377 0,
378 36, 40,
379 68, 88,
380 0,
381 59, 111,
382 62, 181,
383 0,
384 0
385 },
386 // POSTMISTRESS
387 {
388 124, 221,
389 91, 119,
390 253, 122,
391 112, 136,
392 95, 142,
393 130, 149,
394 109, 155,
395 235, 176,
396 220, 29,
397 36, 33,
398 138, 43,
399 13, 51,
400 80, 57,
401 149, 68,
402 37, 73,
403 34, 33,
404 68, 33,
405 86, 100,
406 0,
407 36, 39,
408 34, 80,
409 68, 86,
410 0,
411 58, 130,
412 62, 181,
413 83, 100,
414 81, 103,
415 0,
416 121, 41,
417 122, 42,
418 126, 43,
419 240, 44,
420 120, 45,
421 119, 46,
422 118, 47,
423 52, 48,
424 123, 49,
425 83, 50,
426 117, 51,
427 0
428 },
429 // MWILLIAMS
430 {
431 125, 227,
432 94, 124,
433 95, 141,
434 241, 166,
435 168, 4,
436 150, 26,
437 38, 54,
438 4, 60,
439 230, 65,
440 149, 68,
441 37, 76,
442 101, 109,
443 0,
444 230, 63,
445 0,
446 59, 112,
447 62, 183,
448 0,
449 240, 71,
450 120, 72,
451 118, 73,
452 52, 74,
453 117, 75,
454 0
455 },
456 // TONY
457 {
458 126, 220,
459 95, 143,
460 130, 149,
461 45, 153,
462 109, 154,
463 235, 158,
464 241, 166,
465 168, 2,
466 145, 15,
467 150, 24,
468 220, 20,
469 36, 20,
470 4, 60,
471 37, 79,
472 86, 97,
473 0,
474 150, 23,
475 220, 27,
476 36, 34,
477 0,
478 83, 97,
479 0,
480 121, 36,
481 122, 37,
482 124, 38,
483 240, 39,
484 52, 40,
485 0
486 },
487 // PIG
488 {
489 127, 228,
490 112, 133,
491 45, 153,
492 235, 157,
493 236, 163,
494 241, 165,
495 36, 33,
496 80, 58,
497 34, 81,
498 68, 33,
499 86, 98,
500 0,
501 36, 37,
502 68, 90,
503 0,
504 62, 184,
505 83, 98,
506 0,
507 121, 76,
508 122, 77,
509 126, 78,
510 124, 79,
511 240, 80,
512 120, 81,
513 118, 82,
514 52, 83,
515 125, 84,
516 123, 85,
517 83, 86,
518 117, 87,
519 0
520 },
521 // JUDY
522 {
523 0,
524 0,
525 0,
526 240, 52,
527 117, 53,
528 0
529 }
530 };
531
getResponse(uint16 charNum,uint16 objNum,uint16 & msgNum1,uint16 & msgNum2)532 void AGOSEngine_PN::getResponse(uint16 charNum, uint16 objNum, uint16 &msgNum1, uint16 &msgNum2) {
533 const uint8 *ptr;
534 uint16 num;
535
536 msgNum1 = 0;
537 msgNum2 = 0;
538
539 if (charNum == 83)
540 charNum += 45;
541
542 if (charNum < 118 || charNum > 128) {
543 return;
544 }
545
546 ptr = characters[charNum - 118];
547
548 while ((num = *ptr++) != 0) {
549 if (num == objNum) {
550 msgNum1 = *ptr++;
551 msgNum1 += 400;
552
553 while ((num = *ptr++) != 0)
554 ptr++;
555 break;
556 }
557 ptr++;
558 }
559
560 while ((num = *ptr++) != 0) {
561 if (num == objNum) {
562 msgNum2 = *ptr++;
563 msgNum2 += 400;
564
565 if (msgNum1 == 569)
566 msgNum1 += 400;
567 if (msgNum2 == 0)
568 msgNum2 = msgNum1;
569 return;
570 }
571 ptr++;
572 }
573
574 if (objNum >= 200)
575 msgNum1 = 0;
576
577 objNum -= 200;
578 while ((num = *ptr++) != 0) {
579 if (num == objNum) {
580 msgNum1 = *ptr++;
581 msgNum1 += 400;
582
583 if (msgNum1 == 569)
584 msgNum1 += 400;
585 if (msgNum2 == 0)
586 msgNum2 = msgNum1;
587 return;
588 }
589 ptr++;
590 }
591
592 objNum += 200;
593 while ((num = *ptr++) != 0) {
594 if (num == objNum) {
595 msgNum1 = *ptr++;
596 msgNum1 += 200;
597
598 if (msgNum1 == 569)
599 msgNum1 += 400;
600 if (msgNum2 == 0)
601 msgNum2 = msgNum1;
602 return;
603 }
604 ptr++;
605 }
606
607 if (msgNum1 == 569)
608 msgNum1 += 400;
609 if (msgNum2 == 0)
610 msgNum2 = msgNum1;
611 }
612
getMessage(char * msg,uint16 num)613 char *AGOSEngine_PN::getMessage(char *msg, uint16 num) {
614 char *origPtr, *strPtr1 = msg;
615 uint8 count;
616
617 getObjectName(strPtr1, num);
618 if (!(num & 0x8000)) {
619 return msg;
620 }
621
622 if (strPtr1[0] == 0x41 || strPtr1[0] == 0x61) {
623 if (strPtr1[1] != 0x20)
624 strPtr1 += 2;
625 } else if (strPtr1[0] == 0x54 || strPtr1[0] == 0x74) {
626 if (strPtr1[1] == 0x68 &&
627 strPtr1[2] == 0x65 &&
628 strPtr1[3] == 0x20)
629 strPtr1 += 4;
630 }
631
632 origPtr = strPtr1;
633 while (*strPtr1 != 13)
634 strPtr1++;
635
636 strPtr1[0] = 32;
637 strPtr1[1] = 13;
638 strPtr1[2] = 0;
639
640 if (_videoLockOut & 0x10) {
641 strPtr1 = origPtr;
642 count = 6;
643 while (*strPtr1) {
644 if (*strPtr1 == 32) {
645 count = 6;
646 } else {
647 count--;
648 if (count == 0) {
649 char *tmpPtr = strPtr1;
650 char *strPtr2 = strPtr1;
651
652 while (*strPtr2 != 0 && *strPtr2 != 32)
653 strPtr2++;
654
655 while (*strPtr2) {
656 *strPtr1++ = *strPtr2++;
657 }
658 *strPtr1++ = *strPtr2++;
659
660 strPtr1 = tmpPtr;
661 count = 6;
662 }
663 }
664 strPtr1++;
665 }
666 }
667
668 return origPtr;
669 }
670
671 } // End of namespace AGOS
672