1 /* ScummVM Tools
2  *
3  * ScummVM Tools is the legal property of its developers, whose
4  * names are too numerous to list here. Please refer to the
5  * COPYRIGHT 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 /* GobEngine Script disassembler */
23 
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <stdio.h>
28 
29 #include "degob_script.h"
30 #include "common/endian.h"
31 #include "common/util.h"
32 
ExtTable(byte * data,uint32 size,byte * dataCom,uint32 sizeCom)33 ExtTable::ExtTable(byte *data, uint32 size, byte *dataCom, uint32 sizeCom) :
34 	_data(data), _size(size), _dataCom(dataCom), _sizeCom(sizeCom) {
35 
36 	assert(data && (size >= 3));
37 
38 	init();
39 }
40 
~ExtTable()41 ExtTable::~ExtTable() {
42 	delete[] _items;
43 }
44 
init()45 void ExtTable::init() {
46 	byte *data = _data;
47 
48 	_itemsCount = READ_LE_UINT16(data);
49 	_items = _itemsCount ? new Item[_itemsCount] : 0;
50 	data += 3;
51 
52 	assert(_size >= (uint32) (3 + _itemsCount * 10));
53 
54 	for (uint16 i = 0; i < _itemsCount; i++, data += 10) {
55 		_items[i].offset = READ_LE_UINT32(data);
56 		_items[i].size = READ_LE_UINT16(data + 4);
57 		_items[i].width = READ_LE_UINT16(data + 6);
58 		_items[i].height = READ_LE_UINT16(data + 8);
59 		_items[i].isPacked = (_items[i].width & 0x8000) != 0;
60 
61 		_items[i].width &= 0x7FFF;
62 
63 		if (_items[i].width & 0x4000)
64 			_items[i].size += 1 << 16;
65 		if (_items[i].width & 0x2000)
66 			_items[i].size += 2 << 16;
67 		if (_items[i].width & 0x1000)
68 			_items[i].size += 4 << 16;
69 		if (_items[i].height == 0)
70 			_items[i].size += _items[i].width << 16;
71 
72 		_items[i].width &= 0xFFF;
73 	}
74 }
75 
getItem(uint16 i,uint32 & size) const76 byte *ExtTable::getItem(uint16 i, uint32 &size) const {
77 	assert(i < _itemsCount);
78 
79 	Item &item = _items[i];
80 	int32 offset = item.offset;
81 	byte *data, *dataBuf;
82 
83 	if (offset < 0) {
84 		offset = -(offset + 1);
85 
86 		if (!_dataCom)
87 			error("commun.exN needed");
88 
89 		assert(((uint32) offset) < _sizeCom);
90 
91 		data = _dataCom;
92 	} else {
93 		assert(((uint32) offset) < _size);
94 
95 		data = _data + (3 + _itemsCount * 10);
96 	}
97 
98 	size = item.size;
99 
100 	if (item.isPacked)
101 		dataBuf = new byte[size + 2];
102 	else
103 		dataBuf = new byte[size];
104 
105 	memcpy(dataBuf, data + offset, size);
106 
107 	if (item.isPacked) {
108 		byte *packedBuf = dataBuf;
109 		dataBuf = unpack(packedBuf, size);
110 		delete[] packedBuf;
111 	}
112 
113 	return dataBuf;
114 }
115 
116 // Some LZ77-variant
unpack(const byte * packedData,uint32 & size) const117 byte *ExtTable::unpack(const byte *packedData, uint32 &size) const {
118 	byte *dataBuf, *tmpBuf, *dest;
119 	uint32 counter;
120 	uint16 tmpIndex;
121 	uint16 cmd;
122 	int16 off;
123 	byte len;
124 
125 	counter = size = READ_LE_UINT32(packedData);
126 	dataBuf = new byte[size];
127 
128 	tmpBuf = new byte[4114];
129 
130 	for (int i = 0; i < 4078; i++)
131 		tmpBuf[i] = 0x20;
132 	tmpIndex = 4078;
133 
134 	packedData += 4;
135 
136 	dest = dataBuf;
137 	cmd = 0;
138 	while (1) {
139 		cmd >>= 1;
140 		if ((cmd & 0x0100) == 0) {
141 			cmd = *packedData | 0xFF00;
142 			packedData++;
143 		}
144 		if ((cmd & 1) != 0) { /* copy */
145 			*dest++ = *packedData;
146 			tmpBuf[tmpIndex] = *packedData;
147 			packedData++;
148 			tmpIndex++;
149 			tmpIndex %= 4096;
150 			counter--;
151 			if (counter == 0)
152 				break;
153 		} else { /* copy string */
154 
155 			off = *packedData++;
156 			off |= (*packedData & 0xF0) << 4;
157 			len = (*packedData & 0x0F) + 3;
158 			packedData++;
159 
160 			for (int i = 0; i < len; i++) {
161 				*dest++ = tmpBuf[(off + i) % 4096];
162 				counter--;
163 				if (counter == 0) {
164 					delete[] tmpBuf;
165 					return dataBuf;
166 				}
167 				tmpBuf[tmpIndex] = tmpBuf[(off + i) % 4096];
168 				tmpIndex++;
169 				tmpIndex %= 4096;
170 			}
171 
172 		}
173 	}
174 	delete[] tmpBuf;
175 
176 	return dataBuf;
177 }
178 
Script(byte * totData,uint32 totSize,ExtTable * extTable)179 Script::Script(byte *totData, uint32 totSize, ExtTable *extTable) :
180 	_totData(totData), _ptr(totData), _totSize(totSize), _extTable(extTable) {
181 
182 	assert(totData && (totSize > 128));
183 
184 	_indent = 0;
185 
186 	loadProperties(totData);
187 }
~Script()188 Script::~Script() {}
189 
getStart() const190 uint16 Script::getStart() const { return _start; }
getTextCenter() const191 uint16 Script::getTextCenter() const { return _textCenter; }
getVarsCount() const192 uint16 Script::getVarsCount() const { return _varsCount; }
getTotTextCount() const193 uint32 Script::getTotTextCount() const { return _totTextCount; }
getTotResOffset() const194 uint32 Script::getTotResOffset() const { return _totResOffset; }
getTotResCount() const195 uint16 Script::getTotResCount() const { return _totResCount; }
getAnimDataSize() const196 uint16 Script::getAnimDataSize() const { return _animDataSize; }
getVerScript() const197 uint8 Script::getVerScript() const { return _verScript; }
getVerIMEX() const198 uint8 Script::getVerIMEX() const { return _verIMEX; }
getSuffixIM() const199 uint8 Script::getSuffixIM() const { return _suffixIM; }
getSuffixEX() const200 uint8 Script::getSuffixEX() const { return _suffixEX; }
201 
putString(const char * s) const202 void Script::putString(const char *s) const {
203 	printf("%s", s);
204 }
print(const char * s,...) const205 void Script::print(const char *s, ...) const {
206 	char buf[1024];
207 	va_list va;
208 
209 	va_start(va, s);
210 	vsnprintf(buf, 1024, s, va);
211 	va_end(va);
212 
213 	putString(buf);
214 }
printIndent() const215 void Script::printIndent() const {
216 	print("%08d:", getPos());
217 	for (uint32 i = 0; i < _indent; i++)
218 		putString("	");
219 }
printLine(const char * str) const220 void Script::printLine(const char *str) const {
221 	printIndent(); putString(str); putString("\n");
222 }
printStr(const char * s,...) const223 std::string Script::printStr(const char *s, ...) const {
224 	char buf[1024];
225 	va_list va;
226 
227 	va_start(va, s);
228 	vsnprintf(buf, 1024, s, va);
229 	va_end(va);
230 
231 	return buf;
232 }
233 
incIndent()234 void Script::incIndent() { _indent++; }
decIndent()235 void Script::decIndent() { _indent--; }
236 
getPos() const237 uint32 Script::getPos() const { return _ptr - _totData; }
skip(uint32 off)238 void Script::skip(uint32 off) { seek(off, SEEK_CUR); }
seek(uint32 off,int whence)239 void Script::seek(uint32 off, int whence) {
240 	switch (whence) {
241 	case SEEK_END:
242 		off = _totSize - off;
243 		// fall through
244 	case SEEK_SET:
245 		_ptr = _totData + off;
246 	break;
247 
248 	case SEEK_CUR:
249 		_ptr += (int32) off;
250 		break;
251 	}
252 }
253 
peekUint8() const254 uint8  Script::peekUint8()  const { return *_ptr; }
peekUint16() const255 uint16 Script::peekUint16() const { return READ_LE_UINT16(_ptr); }
peekUint32() const256 uint32 Script::peekUint32() const { return READ_LE_UINT32(_ptr); }
readUint8()257 uint8  Script::readUint8()        { uint8  i = peekUint8();  _ptr += 1; return i; }
readUint16()258 uint16 Script::readUint16()       { uint16 i = peekUint16(); _ptr += 2; return i; }
readUint32()259 uint32 Script::readUint32()       { uint32 i = peekUint32(); _ptr += 4; return i; }
peekString() const260 const char *Script::peekString() const { return (char *) _ptr; }
readString()261 const char *Script::readString()  { const char *i = peekString(); _ptr += strlen(i) + 1; return i; }
262 
skipExpr(char stopToken)263 void Script::skipExpr(char stopToken) {
264 	int16 dimCount;
265 	byte operation;
266 	int16 num;
267 	int16 dim;
268 
269 	num = 0;
270 	while (1) {
271 		operation = readUint8();
272 
273 		if ((operation >= 14) && (operation <= 29)) {
274 			switch (operation) {
275 			case 14:
276 				skip(4);
277 				if (peekUint8() == 97)
278 					skip(1);
279 				break;
280 
281 			case 17:
282 			case 18:
283 			case 20:
284 			case 23:
285 			case 24:
286 				skip(2);
287 				break;
288 
289 			case 19:
290 				skip(4);
291 				break;
292 
293 			case 21:
294 				skip(1);
295 				break;
296 
297 			case 22:
298 				skip(strlen((char *) _ptr) + 1);
299 				break;
300 
301 			case 25:
302 				skip(2);
303 				if (peekUint8() == 13) {
304 					skip(1);
305 					skipExpr(12);
306 				}
307 				break;
308 
309 			case 15:
310 				skip(2);
311 				// fall through
312 			case 16:
313 			case 26:
314 			case 27:
315 			case 28:
316 				dimCount = _ptr[2];
317 				// skip header and dimensions
318 				skip(3 + dimCount);
319 				// skip indices
320 				for (dim = 0; dim < dimCount; dim++)
321 					skipExpr(12);
322 
323 				if ((operation == 28) && (peekUint8() == 13)) {
324 					skip(1);
325 					skipExpr(12);
326 				}
327 				break;
328 
329 			case 29:
330 				skip(1);
331 				skipExpr(10);
332 			}
333 			continue;
334 		} // if ((operation >= 14) && (operation <= 29))
335 
336 		if (operation == 9) {
337 			num++;
338 			continue;
339 		}
340 
341 		if ((operation == 11) || ((operation >= 1) && (operation <= 8)))
342 			continue;
343 
344 		if ((operation >= 30) && (operation <= 37))
345 			continue;
346 
347 		if (operation == 10)
348 			num--;
349 
350 		if (operation != stopToken)
351 			continue;
352 
353 		if ((stopToken != 10) || (num < 0))
354 			return;
355 	}
356 }
357 
readExpr(char stopToken)358 std::string Script::readExpr(char stopToken) {
359 	std::string expr;
360 	int16 dimCount;
361 	byte operation;
362 	int16 num;
363 	int16 dim;
364 	byte *arrDesc;
365 	byte func;
366 
367 	num = 0;
368 	while (1) {
369 		operation = readUint8();
370 
371 		while ((operation == 14) || (operation == 15)) {
372 			if (operation == 14) {
373 				expr += printStr("#%d#", readUint16() * 4);
374 
375 				skip(2);
376 				if (peekUint8() == 97)
377 					skip(1);
378 			} else if (operation == 15) {
379 				expr += printStr("#%d->", readUint16() * 4);
380 
381 				skip(2);
382 				uint8 var_A = readUint8();
383 
384 				skip(var_A);
385 
386 				for (int i = 0; i < var_A; i++)
387 					expr += readExpr(12) + "->";
388 
389 				expr += "#";
390 
391 				if (peekUint8() == 97)
392 					skip(1);
393 			}
394 
395 			operation = readUint8();
396 		}
397 
398 		if ((operation >= 16) && (operation <= 29)) {
399 			// operands
400 
401 			switch (operation) {
402 			case 17: // uint16 variable load
403 				expr += printStr("var16_%d", readUint16() * 2);
404 				break;
405 
406 			case 18: // uint8 variable load:
407 				expr += printStr("var8_%d", readUint16());
408 				break;
409 
410 			case 19: // int32/uint32 immediate
411 				expr += printStr("%d", readUint32());
412 				break;
413 
414 			case 20: // int16 immediate
415 				expr += printStr("%d", (int16) readUint16());
416 				break;
417 
418 			case 21: // int8 immediate
419 				expr += printStr("%d", (int8) readUint8());
420 				break;
421 
422 			case 22: // string immediate
423 				expr += printStr("\"%s\"", readString());
424 				break;
425 
426 			case 23: // uint32 variable load
427 			case 24: // uint32 variable load as uint16
428 				expr += printStr("var32_%d", readUint16() * 4);
429 				break;
430 
431 			case 25: // string variable load
432 				expr += printStr("(&var8_%d)", readUint16() * 4);
433 				if (peekUint8() == 13) {
434 					skip(1);
435 					expr += "+{*";
436 					expr += readExpr(12); // this also prints the closing }
437 				}
438 				break;
439 
440 			case 16: // uint8 array access
441 			case 26: // uint32 array access
442 			case 27: // uint16 array access
443 			case 28: // string array access
444 
445 				if (operation == 16)
446 					expr += printStr("var8_%d[", readUint16());
447 				else if (operation == 26)
448 					expr += printStr("var32_%d[", readUint16() * 4);
449 				else if (operation == 27)
450 					expr += printStr("var16_%d[", readUint16() * 2);
451 				else if (operation == 28)
452 					expr += printStr("(&var8_%d[", readUint16() * 4);
453 
454 				dimCount = readUint8();
455 				arrDesc = _ptr;
456 				skip(dimCount);
457         for (dim = 0; dim < dimCount; dim++) {
458           expr += readExpr(12) + printStr(" of %d", (int16) arrDesc[dim]);
459 					if (dim != dimCount - 1)
460 						expr += "][";
461         }
462 
463 				expr += "]";
464 				if (operation == 28)
465 					expr += ")";
466 
467 				if ((operation == 28) && (peekUint8() == 13)) {
468 					skip(1);
469 					expr += "+{*" + readExpr(12);
470 				}
471 				break;
472 
473 			case 29: // function
474 				func = readUint8();
475 				if (func == 5)
476 					expr += "sqr(";
477 				else if (func == 10)
478 					expr += "rand(";
479 				else if (func == 7)
480 					expr += "abs(";
481 				else if ((func == 0) || (func == 1) || (func == 6))
482 					expr += "sqrt(";
483 				else
484 					expr += "id(";
485 				expr += readExpr(10);
486 				break;
487 			}
488 			continue;
489 		}		// if ((operation >= 16) && (operation <= 29))
490 
491 		// operators
492 		switch (operation) {
493 		case 9:
494 			expr += "(";
495 			break;
496 
497 		case 11:
498 			expr += "!";
499 			break;
500 
501 		case 10:
502 			expr += ")";
503 			break;
504 
505 		case 1:
506 			expr += "-";
507 			break;
508 
509 		case 2:
510 			expr += "+";
511 			break;
512 
513 		case 3:
514 			expr += "-";
515 			break;
516 
517 		case 4:
518 			expr += "|";
519 			break;
520 
521 		case 5:
522 			expr += "*";
523 			break;
524 
525 		case 6:
526 			expr += "/";
527 			break;
528 
529 		case 7:
530 			expr += "%";
531 			break;
532 
533 		case 8:
534 			expr += "&";
535 			break;
536 
537 		case 30:
538 			expr += " || ";
539 			break;
540 
541 		case 31:
542 			expr += " && ";
543 			break;
544 
545 		case 32:
546 			expr += "<";
547 			break;
548 
549 		case 33:
550 			expr += "<=";
551 			break;
552 
553 		case 34:
554 			expr += ">";
555 			break;
556 
557 		case 35:
558 			expr += ">=";
559 			break;
560 
561 		case 36:
562 			expr += "==";
563 			break;
564 
565 		case 37:
566 			expr += "!=";
567 			break;
568 
569 		case 99:
570 //			expr += "\n";
571 			break;
572 
573 		case 12:
574 			expr += "}";
575 			if (stopToken != 12)
576 				warning("Closing paren without opening?");
577 			break;
578 
579 		default:
580 			// Unknown token -- don't know how to handle this, so just
581 			// skip over everything until we reach the stopToken.
582 			while (((char) readUint8()) != stopToken) {}
583 			return printStr("Invalid operator in expression: <%d>", (int16) operation);
584 			break;
585 		}
586 
587 		if (operation == 9) {
588 			num++;
589 			continue;
590 		}
591 
592 		if ((operation == 11) || ((operation >= 1) && (operation <= 8)))
593 			continue;
594 
595 		if ((operation >= 30) && (operation <= 37))
596 			continue;
597 
598 		if (operation == 10)
599 			num--;
600 
601 		if (operation == stopToken) {
602 			if ((stopToken != 10) || (num < 0)) {
603 				return expr;
604 			}
605 		}
606 	}
607 }
608 
readVarIndex(uint16 * arg_0,uint16 * arg_4)609 std::string Script::readVarIndex(uint16 *arg_0, uint16 *arg_4) {
610 	std::string expr, pref;
611 	byte *arrDesc;
612 	int16 dim;
613 	int16 dimCount;
614 	int16 operation;
615 	int16 temp;
616 
617 	operation = readUint8();
618 
619 	while ((operation == 14) || (operation == 15)) {
620 		if (operation == 14) {
621 			pref += printStr("#%d#", readUint16() * 4);
622 
623 			if (arg_0)
624 				*arg_0 = peekUint16();
625 			if (arg_4)
626 				*arg_4 = 14;
627 
628 			skip(2);
629 			if (peekUint8() != 97)
630 				return expr;
631 
632 			skip(1);
633 		} else if (operation == 15) {
634 			pref += printStr("#%d->", readUint16() * 4);
635 
636 			if (arg_0)
637 				*arg_0 = peekUint16();
638 			if (arg_4)
639 				*arg_4 = 14;
640 
641 			skip(2);
642 			uint8 var_A = readUint8();
643 
644 			skip(var_A);
645 
646 			for (int i = 0; i < var_A; i++)
647 				pref += readExpr(12) + "->";
648 
649 			pref += "#";
650 
651 			if (peekUint8() != 97)
652 				return expr;
653 
654 			skip(1);
655 		}
656 
657 		operation = readUint8();
658 	}
659 
660 	if (arg_0)
661 		*arg_0 = 0;
662 	if (arg_4)
663 		*arg_4 = operation;
664 
665 	if ((operation == 16) || (operation == 18) || (operation == 25) || (operation == 28))
666 		expr = "var8_";
667 	else if ((operation == 17) || (operation == 24) || (operation == 27))
668 		expr = "var16_";
669 	else if ((operation == 23) || (operation == 26))
670 		expr = "var32_";
671 
672 	expr += pref;
673 
674 	switch (operation) {
675 	case 23:
676 	case 24:
677 	case 25:
678 		temp = readUint16() * 4;
679 		expr += printStr("%d", temp);
680 		if ((operation == 25) && (peekUint8() == 13)) {
681 			skip(1);
682 			expr += "+{*";
683 			expr += readExpr(12);
684 		}
685 		break;
686 
687 	case 17:
688 		expr += printStr("%d", readUint16() * 2);
689 		break;
690 
691 	case 18:
692 		expr += printStr("%d", readUint16());
693 		break;
694 
695 	case 16:
696 	case 26:
697 	case 27:
698 	case 28:
699 		if (operation == 16)
700 			expr += printStr("%d[", readUint16());
701 		else if (operation == 26)
702 			expr += printStr("%d[", readUint16() * 4);
703 		else if (operation == 27)
704 			expr += printStr("%d[", readUint16() * 2);
705 		else if (operation == 28)
706 			expr += printStr("%d[", readUint16() * 4);
707 
708 		dimCount = readUint8();
709 		arrDesc = _ptr;
710 		skip(dimCount);
711 		for (dim = 0; dim < dimCount; dim++) {
712 			expr += readExpr(12);
713 			expr += printStr(" of %d", (int16) arrDesc[dim]);
714 			if (dim != dimCount - 1)
715 				expr += "][";
716 		}
717 		expr += "]";
718 
719 		if ((operation == 28) && (peekUint8() == 13)) {
720 			skip(1);
721 			expr += "+{*";
722 			expr += readExpr(12);
723 		}
724 		break;
725 
726 	default:
727 		expr += "var_0";
728 		break;
729 	}
730 
731 	return expr;
732 }
733 
getBlockSize() const734 uint16 Script::getBlockSize() const {
735 	return READ_LE_UINT16(_ptr + 2) + 2;
736 }
737 
evaluateParams(const Param * params)738 void Script::evaluateParams(const Param *params) {
739 	bool first = true;
740 
741 	while (*params != PARAM_NONE) {
742 		if (!first)
743 			print(", ");
744 		else
745 			first = false;
746 
747 		switch (*params++) {
748 		case PARAM_UINT8:
749 			print("%u", readUint8());
750 			break;
751 
752 		case PARAM_UINT16:
753 			print("%u", readUint16());
754 			break;
755 
756 		case PARAM_UINT32:
757 			print("%u", readUint32());
758 			break;
759 
760 		case PARAM_INT8:
761 			print("%d", (int8) readUint8());
762 			break;
763 
764 		case PARAM_INT16:
765 			print("%d", (int16) readUint16());
766 			break;
767 
768 		case PARAM_INT32:
769 			print("%d", (int32) readUint32());
770 			break;
771 
772 		case PARAM_STR:
773 			print("\"%s\"", readString());
774 			break;
775 
776 		case PARAM_EXPR:
777 			print("%s", readExpr().c_str());
778 			break;
779 
780 		case PARAM_VARINDEX:
781 			print("%s", readVarIndex().c_str());
782 			break;
783 
784 		default:
785 			error("Unknown parameter type");
786 			break;
787 		}
788 	}
789 }
790 
printFuncDesc(const FuncParams & fParams,const Param * params)791 void Script::printFuncDesc(const FuncParams &fParams, const Param *params) {
792 	if (!fParams.desc)
793 		return;
794 
795 	printIndent();
796 	putString(fParams.desc);
797 	putString("(");
798 
799 	if (params)
800 		evaluateParams(params);
801 
802 	putString(");\n");
803 }
804 
printFuncDesc(const FuncParams & fParams) const805 void Script::printFuncDesc(const FuncParams &fParams) const {
806 	if (!fParams.desc)
807 		return;
808 
809 	printIndent();
810 	putString(fParams.desc);
811 	putString("(");
812 
813 	print("%d, %d", fParams.objIndex, fParams.extraData);
814 
815 	putString(");\n");
816 }
817 
startFunc(const FuncParams & fParams) const818 void Script::startFunc(const FuncParams &fParams) const {
819 	printIndent();
820 	print("%s(", fParams.desc);
821 }
822 
endFunc() const823 void Script::endFunc() const {
824 	print(");\n");
825 }
826 
loadProperties(byte * data)827 void Script::loadProperties(byte *data) {
828 	_start = READ_LE_UINT16(data + 0x64);
829 	assert(_start >= 128);
830 
831 	_varsCount = READ_LE_UINT16(data + 0x2C);
832 	_totTextCount = READ_LE_UINT32(data + 0x30);
833 	_totResOffset = READ_LE_UINT32(data + 0x34);
834 	_totResCount = (_totResOffset == 0xFFFFFFFF) ? 0 : READ_LE_UINT16(data + _totResOffset);
835 	_verScript = data[0x29];
836 	_verIMEX = data[0x3D];
837 	_suffixIM = data[0x3B];
838 	_suffixEX = data[0x3C];
839 	_animDataSize = READ_LE_UINT16(data + 0x38);
840 	_textCenter = READ_LE_UINT16(data + 0x7E);
841 }
842 
funcBlock(int16 retFlag)843 void Script::funcBlock(int16 retFlag) {
844 	FuncParams params;
845 	byte cmd;
846 	byte cmd2;
847 
848 	params.retFlag = retFlag;
849 
850 	skip(1);
851 	params.cmdCount = readUint8();
852 	skip(2);
853 
854 	if (params.cmdCount == 0)
855 		return;
856 
857 	params.counter = 0;
858 	do {
859 		cmd = readUint8();
860 		if ((cmd >> 4) >= 12) {
861 			cmd2 = 16 - (cmd >> 4);
862 			cmd &= 0xF;
863 		} else
864 			cmd2 = 0;
865 
866 		params.counter++;
867 
868 		if (cmd2 == 0)
869 			cmd >>= 4;
870 
871 		funcOpcode(cmd2, cmd, params);
872 
873 	} while (params.counter != params.cmdCount);
874 }
875 
addStartingOffsets()876 void Script::addStartingOffsets() {
877 	for (int i = 100; i < 128; i += 2) {
878 		uint16 offset = READ_LE_UINT16(_totData + i);
879 		if ((offset >= 128) && (offset != ((uint16) -1)))
880 			addFuncOffset(offset);
881 	}
882 }
883 
addFuncOffset(uint32 offset)884 void Script::addFuncOffset(uint32 offset) {
885 	for (std::list<uint32>::iterator it = _funcOffsets.begin(); it != _funcOffsets.end(); ++it)
886 		if (*it == offset)
887 			return;
888 
889 	_funcOffsets.push_back(offset);
890 }
891 
deGob(int32 offset)892 void Script::deGob(int32 offset) {
893 	_funcOffsets.clear();
894 
895 	if (offset < 0)
896 		addStartingOffsets();
897 	else
898 	_funcOffsets.push_back(offset);
899 
900 	for (std::list<uint32>::iterator it = _funcOffsets.begin(); it != _funcOffsets.end(); ++it) {
901 		seek(*it);
902 		deGobFunction();
903 		print("\n");
904 	}
905 }
906 
deGobFunction()907 void Script::deGobFunction() {
908 	printIndent();
909 	print("sub_%d {\n", getPos());
910 	incIndent();
911 
912 	funcBlock(2);
913 
914 	decIndent();
915 	printIndent();
916 	print("}\n");
917 }
918