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