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 "common/textconsole.h"
24 
25 #include "parallaction/parallaction.h"
26 #include "parallaction/parser.h"
27 #include "parallaction/sound.h"
28 
29 namespace Parallaction {
30 
31 #define CMD_SET			1
32 #define CMD_CLEAR		2
33 #define CMD_START		3
34 #define CMD_SPEAK		4
35 #define CMD_GET			5
36 #define CMD_LOCATION	6
37 #define CMD_OPEN		7
38 #define CMD_CLOSE		8
39 #define CMD_ON			9
40 #define CMD_OFF			10
41 #define CMD_CALL		11
42 #define CMD_TOGGLE		12
43 #define CMD_DROP		13
44 #define CMD_QUIT		14
45 #define CMD_MOVE		15
46 #define CMD_STOP		16
47 #define CMD_CHARACTER	17
48 #define CMD_FOLLOWME	18
49 #define CMD_ONMOUSE		19
50 #define CMD_OFFMOUSE	20
51 #define CMD_ADD			21
52 #define CMD_LEAVE		22
53 #define CMD_INC			23
54 #define CMD_DEC			24
55 #define CMD_TEST		25
56 #define CMD_TEST_GT		26
57 #define CMD_TEST_LT		27
58 #define CMD_LET			28
59 #define CMD_MUSIC		29
60 #define CMD_FIX			30
61 #define CMD_UNFIX		31
62 #define CMD_ZETA		32
63 #define CMD_SCROLL		33
64 #define CMD_SWAP		34
65 #define CMD_GIVE		35
66 #define CMD_TEXT		36
67 #define CMD_PART		37
68 #define CMD_TEST_SFX	38
69 #define CMD_RETURN		39
70 #define CMD_ONSAVE		40
71 #define CMD_OFFSAVE		41
72 
73 
74 #define INST_ON			1
75 #define INST_OFF		2
76 #define INST_X			3
77 #define INST_Y			4
78 #define INST_Z			5
79 #define INST_F			6
80 #define INST_LOOP		7
81 #define INST_ENDLOOP	8
82 #define INST_SHOW		9
83 #define INST_INC		10
84 #define INST_DEC		11
85 #define INST_SET		12
86 #define INST_PUT		13
87 #define INST_CALL		14
88 #define INST_WAIT		15
89 #define INST_START		16
90 #define INST_PROCESS	17
91 #define INST_MOVE		18
92 #define INST_COLOR		19
93 #define INST_SOUND		20
94 #define INST_MASK		21
95 #define INST_PRINT		22
96 #define INST_TEXT		23
97 #define INST_MUL		24
98 #define INST_DIV		25
99 #define INST_IF			26
100 #define INST_IFEQ		27
101 #define INST_IFLT		28
102 #define INST_IFGT		29
103 #define INST_ENDIF		30
104 #define INST_STOP		31
105 
106 
107 const char *_zoneTypeNamesRes_br[] = {
108 	"examine",
109 	"door",
110 	"get",
111 	"merge",
112 	"taste",
113 	"hear",
114 	"feel",
115 	"speak",
116 	"none",
117 	"trap",
118 	"you",
119 	"command",
120 	"path",
121 	"box"
122 };
123 
124 const char *_zoneFlagNamesRes_br[] = {
125 	"closed",
126 	"active",
127 	"remove",
128 	"acting",
129 	"locked",
130 	"fixed",
131 	"noname",
132 	"nomasked",
133 	"looping",
134 	"added",
135 	"character",
136 	"nowalk",
137 	"yourself",
138 	"scaled",
139 	"selfuse"
140 };
141 
142 const char *_commandsNamesRes_br[] = {
143 	"set",
144 	"clear",
145 	"start",
146 	"speak",
147 	"get",
148 	"location",
149 	"open",
150 	"close",
151 	"on",
152 	"off",
153 	"call",
154 	"toggle",
155 	"drop",
156 	"quit",
157 	"move",
158 	"stop",
159 	"character",
160 	"followme",
161 	"onmouse",
162 	"offmouse",
163 	"add",
164 	"leave",
165 	"inc",
166 	"dec",
167 	"test",
168 	"dummy",
169 	"dummy",
170 	"let",
171 	"music",
172 	"fix",
173 	"unfix",
174 	"zeta",
175 	"scroll",
176 	"swap",
177 	"give",
178 	"text",
179 	"part",
180 	"dummy",
181 	"return",
182 	"onsave",
183 	"offsave",
184 	"endcommands",
185 	"ifchar",
186 	"endif"
187 };
188 
189 
190 const char *_audioCommandsNamesRes_br[] = {
191 	"play",
192 	"stop",
193 	"pause",
194 	"channel_level",
195 	"fadein",
196 	"fadeout",
197 	"volume",
198 	" ",
199 	"faderate",
200 	" ",
201 	" ",
202 	" ",
203 	" ",
204 	" ",
205 	" ",
206 	" ",
207 	"loop"
208 };
209 
210 const char *_locationStmtRes_br[] = {
211 	"character",
212 	"endlocation",
213 	"ifchar",
214 	"endif",
215 	"location",
216 	"mask",
217 	"path",
218 	"disk",
219 	"localflags",
220 	"commands",
221 	"escape",
222 	"acommands",
223 	"flags",
224 	"comment",
225 	"endcomment",
226 	"zone",
227 	"animation",
228 	"zeta",
229 	"music",
230 	"sound"
231 };
232 
233 const char *_locationZoneStmtRes_br[] = {
234 	"endzone",
235 	"limits",
236 	"moveto",
237 	"type",
238 	"commands",
239 	"label",
240 	"flags"
241 };
242 
243 const char *_locationAnimStmtRes_br[] = {
244 	"endanimation",
245 	"endzone",
246 	"script",
247 	"commands",
248 	"type",
249 	"label",
250 	"flags",
251 	"file",
252 	"position",
253 	"moveto"
254 };
255 
256 const char *_instructionNamesRes_br[] = {
257 	"on",
258 	"off",
259 	"x",
260 	"y",
261 	"z",
262 	"f",
263 	"loop",
264 	"endloop",
265 	"show",
266 	"inc",
267 	"dec",
268 	"set",
269 	"put",
270 	"call",
271 	"wait",
272 	"start",
273 	"process",
274 	"move",
275 	"color",
276 	"sound",
277 	"mask",
278 	"print",
279 	"text",
280 	"mul",
281 	"div",
282 	"if",
283 	"dummy",
284 	"dummy",
285 	"endif",
286 	"stop",
287 	"endscript"
288 };
289 
290 
291 #define SetOpcodeTable(x) table = &x;
292 
293 typedef Common::Functor0Mem<void, ProgramParser_br> OpcodeV1;
294 #define INSTRUCTION_PARSER(sig) table->push_back(new OpcodeV1(this, &ProgramParser_br::instParse_##sig))
295 
296 typedef Common::Functor0Mem<void, LocationParser_br> OpcodeV2;
297 #define ZONE_PARSER(sig)		table->push_back(new OpcodeV2(this, &LocationParser_br::locZoneParse_##sig))
298 #define ANIM_PARSER(sig)		table->push_back(new OpcodeV2(this, &LocationParser_br::locAnimParse_##sig))
299 #define LOCATION_PARSER(sig)	table->push_back(new OpcodeV2(this, &LocationParser_br::locParse_##sig))
300 #define COMMAND_PARSER(sig)		table->push_back(new OpcodeV2(this, &LocationParser_br::cmdParse_##sig))
301 
302 #define WARNING_PARSER(sig)		table->push_back(new OpcodeV2(this, &LocationParser_br::warning_##sig))
303 
304 
305 #define DECLARE_ZONE_PARSER(sig) void LocationParser_br::locZoneParse_##sig()
306 #define DECLARE_ANIM_PARSER(sig) void LocationParser_br::locAnimParse_##sig()
307 #define DECLARE_COMMAND_PARSER(sig) void LocationParser_br::cmdParse_##sig()
308 #define DECLARE_LOCATION_PARSER(sig) void LocationParser_br::locParse_##sig()
309 
310 #define DECLARE_INSTRUCTION_PARSER(sig) void ProgramParser_br::instParse_##sig()
311 
312 
DECLARE_LOCATION_PARSER(location)313 DECLARE_LOCATION_PARSER(location)  {
314 	debugC(7, kDebugParser, "LOCATION_PARSER(location) ");
315 
316 	strcpy(_vm->_location._name, _tokens[1]);
317 
318 	bool flip = false;
319 	int nextToken;
320 
321 	if (!scumm_stricmp("flip", _tokens[2])) {
322 		flip = true;
323 		nextToken = 3;
324 	} else {
325 		nextToken = 2;
326 	}
327 
328 	debugC(7, kDebugParser, "flip: %d", flip);
329 	// TODO: handle background horizontal flip (via a context parameter)
330 
331 	if (_tokens[nextToken][0] != '\0') {
332 		_vm->_char._ani->setX(atoi(_tokens[nextToken]));
333 		nextToken++;
334 		_vm->_char._ani->setY(atoi(_tokens[nextToken]));
335 		nextToken++;
336 	}
337 
338 	if (_tokens[nextToken][0] != '\0') {
339 		_vm->_char._ani->setF(atoi(_tokens[nextToken]));
340 	}
341 
342 	_out->_backgroundName = _tokens[1];
343 }
344 
DECLARE_LOCATION_PARSER(zone)345 DECLARE_LOCATION_PARSER(zone)  {
346 	debugC(7, kDebugParser, "LOCATION_PARSER(zone) ");
347 
348 	ctxt.z.reset();
349 	parseZone(_vm->_location._zones, _tokens[1]);
350 	if (!ctxt.z) {
351 		return;
352 	}
353 
354 	ctxt.z->_index = _zoneProg;
355 	ctxt.z->_locationIndex = _vm->_currentLocationIndex;
356 
357 	_vm->restoreOrSaveZoneFlags(ctxt.z, _vm->getLocationFlags() & kFlagsVisited);
358 }
359 
360 
DECLARE_LOCATION_PARSER(animation)361 DECLARE_LOCATION_PARSER(animation)  {
362 	debugC(7, kDebugParser, "LOCATION_PARSER(animation) ");
363 
364 	ctxt.a.reset();
365 	parseAnimation(_vm->_location._animations, _tokens[1]);
366 	if (!ctxt.a) {
367 		return;
368 	}
369 
370 	ctxt.a->_index = _zoneProg;
371 	ctxt.a->_locationIndex = _vm->_currentLocationIndex;
372 
373 	_vm->restoreOrSaveZoneFlags(ctxt.a, _vm->getLocationFlags() & kFlagsVisited);
374 }
375 
376 
DECLARE_LOCATION_PARSER(localflags)377 DECLARE_LOCATION_PARSER(localflags)  {
378 	debugC(7, kDebugParser, "LOCATION_PARSER(localflags) ");
379 
380 	int _si = 1;
381 	while (_tokens[_si][0] != '\0') {
382 		_vm->_localFlagNames->addData(_tokens[_si]);
383 		_si++;
384 	}
385 }
386 
387 
DECLARE_LOCATION_PARSER(flags)388 DECLARE_LOCATION_PARSER(flags)  {
389 	debugC(7, kDebugParser, "LOCATION_PARSER(flags) ");
390 
391 	if ((_vm->getLocationFlags() & kFlagsVisited) == 0) {
392 		// only for 1st visit
393 		_vm->clearLocationFlags((uint32)kFlagsAll);
394 		int _si = 1;
395 
396 		do {
397 			byte _al = _vm->_localFlagNames->lookup(_tokens[_si]);
398 			_vm->setLocationFlags(1 << (_al - 1));
399 
400 			_si++;
401 			if (scumm_stricmp(_tokens[_si], "|")) break;
402 			_si++;
403 		} while (true);
404 	}
405 }
406 
407 
DECLARE_LOCATION_PARSER(comment)408 DECLARE_LOCATION_PARSER(comment)  {
409 	debugC(7, kDebugParser, "LOCATION_PARSER(comment) ");
410 
411 	_vm->_location._comment = parseComment();
412 }
413 
414 
DECLARE_LOCATION_PARSER(endcomment)415 DECLARE_LOCATION_PARSER(endcomment)  {
416 	debugC(7, kDebugParser, "LOCATION_PARSER(endcomment) ");
417 
418 	_vm->_location._endComment = parseComment();
419 }
420 
421 
DECLARE_LOCATION_PARSER(sound)422 DECLARE_LOCATION_PARSER(sound)  {
423 	warning("SOUND command unexpected when parsing location");
424 }
425 
426 
DECLARE_LOCATION_PARSER(music)427 DECLARE_LOCATION_PARSER(music)  {
428 	debugC(7, kDebugParser, "LOCATION_PARSER(music) ");
429 	_vm->_soundMan->execute(SC_SETMUSICFILE, _tokens[1]);
430 }
431 
DECLARE_LOCATION_PARSER(redundant)432 DECLARE_LOCATION_PARSER(redundant)  {
433 	debugC(7, kDebugParser, "LOCATION_PARSER(redundant) ");
434 
435 	warning("redundant '%s' line found in script '%s'", _tokens[0], ctxt.filename);
436 }
437 
438 
DECLARE_LOCATION_PARSER(character)439 DECLARE_LOCATION_PARSER(character)  {
440 	debugC(7, kDebugParser, "LOCATION_PARSER(character) ");
441 	_out->_characterName = _tokens[1];
442 }
443 
444 
DECLARE_LOCATION_PARSER(ifchar)445 DECLARE_LOCATION_PARSER(ifchar)  {
446 	debugC(7, kDebugParser, "LOCATION_PARSER(ifchar) ");
447 
448 	if (scumm_stricmp(_vm->_char.getName(), _tokens[1])) {
449 		_script->skip("ENDIF");
450 	}
451 }
452 
453 
DECLARE_LOCATION_PARSER(null)454 DECLARE_LOCATION_PARSER(null)  {
455 	debugC(7, kDebugParser, "LOCATION_PARSER(null) ");
456 
457 
458 }
459 
460 
DECLARE_LOCATION_PARSER(mask)461 DECLARE_LOCATION_PARSER(mask)  {
462 	debugC(7, kDebugParser, "LOCATION_PARSER(mask) ");
463 
464 	_out->_info->layers[0] = 0;
465 	_out->_info->layers[1] = atoi(_tokens[2]);
466 	_out->_info->layers[2] = atoi(_tokens[3]);
467 	_out->_info->layers[3] = atoi(_tokens[4]);
468 
469 	// postpone loading of screen mask data, because background must be loaded first
470 	_out->_maskName = _tokens[1];
471 }
472 
473 
DECLARE_LOCATION_PARSER(path)474 DECLARE_LOCATION_PARSER(path)  {
475 	debugC(7, kDebugParser, "LOCATION_PARSER(path) ");
476 
477 	// postpone loading of screen path data, because background must be loaded first
478 	_out->_pathName = _tokens[1];
479 }
480 
481 
DECLARE_LOCATION_PARSER(escape)482 DECLARE_LOCATION_PARSER(escape)  {
483 	debugC(7, kDebugParser, "LOCATION_PARSER(escape) ");
484 
485 	parseCommands(_vm->_location._escapeCommands);
486 }
487 
488 
DECLARE_LOCATION_PARSER(zeta)489 DECLARE_LOCATION_PARSER(zeta)  {
490 	debugC(7, kDebugParser, "LOCATION_PARSER(zeta) ");
491 
492 	_vm->_location._zeta0 = atoi(_tokens[1]);
493 	_vm->_location._zeta1 = atoi(_tokens[2]);
494 
495 	if (_tokens[3][0] != '\0') {
496 		_vm->_location._zeta2 = atoi(_tokens[3]);
497 	} else {
498 		_vm->_location._zeta2 = 50;
499 	}
500 }
501 
DECLARE_COMMAND_PARSER(ifchar)502 DECLARE_COMMAND_PARSER(ifchar)  {
503 	debugC(7, kDebugParser, "COMMAND_PARSER(ifchar) ");
504 
505 	if (!scumm_stricmp(_vm->_char.getName(), _tokens[1]))
506 		_script->skip("endif");
507 }
508 
509 
DECLARE_COMMAND_PARSER(endif)510 DECLARE_COMMAND_PARSER(endif)  {
511 	debugC(7, kDebugParser, "COMMAND_PARSER(endif) ");
512 
513 
514 }
515 
516 
DECLARE_COMMAND_PARSER(location)517 DECLARE_COMMAND_PARSER(location)  {
518 	debugC(7, kDebugParser, "COMMAND_PARSER(location) ");
519 
520 	createCommand(_parser->_lookup);
521 
522 	ctxt.cmd->_string = _tokens[1];
523 	ctxt.nextToken++;
524 
525 	ctxt.cmd->_startPos.x = -1000;
526 	ctxt.cmd->_startPos2.x = -1000;
527 	if (_tokens[ctxt.nextToken][0] != '\0') {
528 		if (Common::isDigit(_tokens[ctxt.nextToken][0]) || _tokens[ctxt.nextToken][0] == '-') {
529 			ctxt.cmd->_startPos.x = atoi(_tokens[ctxt.nextToken]);
530 			ctxt.nextToken++;
531 			ctxt.cmd->_startPos.y = atoi(_tokens[ctxt.nextToken]);
532 			ctxt.nextToken++;
533 		}
534 
535 		if (Common::isDigit(_tokens[ctxt.nextToken][0]) || _tokens[ctxt.nextToken][0] == '-') {
536 			ctxt.cmd->_startPos2.x = atoi(_tokens[ctxt.nextToken]);
537 			ctxt.nextToken++;
538 			ctxt.cmd->_startPos2.y = atoi(_tokens[ctxt.nextToken]);
539 			ctxt.nextToken++;
540 		}
541 	}
542 
543 	parseCommandFlags();
544 	addCommand();
545 }
546 
547 
DECLARE_COMMAND_PARSER(string)548 DECLARE_COMMAND_PARSER(string)  {
549 	debugC(7, kDebugParser, "COMMAND_PARSER(string) ");
550 
551 	createCommand(_parser->_lookup);
552 
553 	ctxt.cmd->_string = _tokens[1];
554 	ctxt.nextToken++;
555 
556 	parseCommandFlags();
557 	addCommand();
558 }
559 
DECLARE_COMMAND_PARSER(math)560 DECLARE_COMMAND_PARSER(math)  {
561 	debugC(7, kDebugParser, "COMMAND_PARSER(math) ");
562 
563 	createCommand(_parser->_lookup);
564 
565 	if (!_vm->counterExists(_tokens[1])) {
566 		error("counter '%s' doesn't exists", _tokens[1]);
567 	}
568 
569 	ctxt.cmd->_counterName = _tokens[1];
570 	ctxt.nextToken++;
571 	ctxt.cmd->_counterValue = atoi(_tokens[2]);
572 	ctxt.nextToken++;
573 
574 	parseCommandFlags();
575 	addCommand();
576 }
577 
578 
DECLARE_COMMAND_PARSER(test)579 DECLARE_COMMAND_PARSER(test)  {
580 	debugC(7, kDebugParser, "COMMAND_PARSER(test) ");
581 
582 	createCommand(_parser->_lookup);
583 	ctxt.nextToken++;
584 
585 	if (!_vm->counterExists(_tokens[1])) {
586 		if (!scumm_stricmp("SFX", _tokens[1])) {
587 			ctxt.cmd->_id = CMD_TEST_SFX;
588 		} else {
589 			error("unknown counter '%s' in test opcode", _tokens[1]);
590 		}
591 	} else {
592 		ctxt.cmd->_counterName = _tokens[1];
593 		ctxt.cmd->_counterValue = atoi(_tokens[3]);
594 		ctxt.nextToken++;
595 
596 		if (_tokens[2][0] == '>') {
597 			ctxt.cmd->_id = CMD_TEST_GT;
598 		} else
599 		if (_tokens[2][0] == '<') {
600 			ctxt.cmd->_id = CMD_TEST_LT;
601 		}
602 		ctxt.nextToken++;
603 	}
604 
605 	parseCommandFlags();
606 	addCommand();
607 }
608 
609 
DECLARE_COMMAND_PARSER(music)610 DECLARE_COMMAND_PARSER(music)  {
611 	debugC(7, kDebugParser, "COMMAND_PARSER(music) ");
612 
613 	createCommand(_parser->_lookup);
614 
615 	ctxt.cmd->_musicCommand = _audioCommandsNames->lookup(_tokens[1]);
616 	ctxt.nextToken++;
617 
618 	if (_tokens[2][0] != '\0' && scumm_stricmp("flags", _tokens[2]) && scumm_stricmp("gflags", _tokens[2])) {
619 		ctxt.cmd->_musicParm = atoi(_tokens[2]);
620 		ctxt.nextToken++;
621 	}
622 
623 	parseCommandFlags();
624 	addCommand();
625 }
626 
627 
DECLARE_COMMAND_PARSER(zeta)628 DECLARE_COMMAND_PARSER(zeta)  {
629 	debugC(7, kDebugParser, "COMMAND_PARSER(zeta) ");
630 
631 	createCommand(_parser->_lookup);
632 
633 	ctxt.cmd->_zeta0 = atoi(_tokens[1]);
634 	ctxt.nextToken++;
635 	ctxt.cmd->_zeta1 = atoi(_tokens[2]);
636 	ctxt.nextToken++;
637 
638 	if (_tokens[3][0] != '\0') {
639 		ctxt.cmd->_zeta2 = atoi(_tokens[3]);
640 		ctxt.nextToken++;
641 	} else {
642 		ctxt.cmd->_zeta2 = 50;
643 	}
644 
645 	parseCommandFlags();
646 	addCommand();
647 }
648 
649 
DECLARE_COMMAND_PARSER(give)650 DECLARE_COMMAND_PARSER(give)  {
651 	debugC(7, kDebugParser, "COMMAND_PARSER(give) ");
652 
653 	createCommand(_parser->_lookup);
654 
655 	ctxt.cmd->_object = 4 + atoi(_tokens[1]);
656 	ctxt.nextToken++;
657 
658 	if (!scumm_stricmp("dino", _tokens[2])) {
659 		ctxt.cmd->_characterId = 1;
660 	} else
661 	if (!scumm_stricmp("doug", _tokens[2])) {
662 		ctxt.cmd->_characterId = 2;
663 	} else
664 	if (!scumm_stricmp("donna", _tokens[2])) {
665 		ctxt.cmd->_characterId = 3;
666 	} else
667 		error("unknown recipient '%s' in give command", _tokens[2]);
668 
669 	ctxt.nextToken++;
670 
671 	parseCommandFlags();
672 	addCommand();
673 }
674 
675 
DECLARE_COMMAND_PARSER(text)676 DECLARE_COMMAND_PARSER(text)  {
677 	debugC(7, kDebugParser, "COMMAND_PARSER(text) ");
678 
679 	createCommand(_parser->_lookup);
680 
681 	if (Common::isDigit(_tokens[1][1])) {
682 		ctxt.cmd->_zeta0 = atoi(_tokens[1]);
683 		ctxt.nextToken++;
684 	} else {
685 		ctxt.cmd->_zeta0 = -1;
686 	}
687 
688 	ctxt.cmd->_string = _tokens[ctxt.nextToken];
689 	ctxt.nextToken++;
690 
691 	if (_tokens[ctxt.nextToken][0] != '\0' && scumm_stricmp("flags", _tokens[ctxt.nextToken])) {
692 		ctxt.cmd->_string2 = _tokens[ctxt.nextToken];
693 		ctxt.nextToken++;
694 	}
695 
696 
697 	parseCommandFlags();
698 	addCommand();
699 }
700 
701 
DECLARE_COMMAND_PARSER(unary)702 DECLARE_COMMAND_PARSER(unary)  {
703 	debugC(7, kDebugParser, "COMMAND_PARSER(unary) ");
704 
705 	createCommand(_parser->_lookup);
706 
707 	ctxt.cmd->_counterValue = atoi(_tokens[1]);
708 	ctxt.nextToken++;
709 
710 	parseCommandFlags();
711 	addCommand();
712 }
713 
714 
DECLARE_ZONE_PARSER(limits)715 DECLARE_ZONE_PARSER(limits)  {
716 	debugC(7, kDebugParser, "ZONE_PARSER(limits) ");
717 
718 	if (Common::isAlpha(_tokens[1][1])) {
719 		ctxt.z->_flags |= kFlagsAnimLinked;
720 		ctxt.z->_linkedName = _tokens[1];
721 	} else {
722 		ctxt.z->setRect(atoi(_tokens[1]), atoi(_tokens[2]), atoi(_tokens[3]), atoi(_tokens[4]));
723 	}
724 }
725 
726 
DECLARE_ZONE_PARSER(moveto)727 DECLARE_ZONE_PARSER(moveto)  {
728 	debugC(7, kDebugParser, "ZONE_PARSER(moveto) ");
729 
730 	ctxt.z->_moveTo.x = atoi(_tokens[1]);
731 	ctxt.z->_moveTo.y = atoi(_tokens[2]);
732 //	ctxt.z->_moveTo.z = atoi(_tokens[3]);
733 }
734 
735 
DECLARE_ZONE_PARSER(type)736 DECLARE_ZONE_PARSER(type)  {
737 	debugC(7, kDebugParser, "ZONE_PARSER(type) ");
738 
739 	ctxt.z->_type = buildZoneType(_tokens[1], _tokens[2]);
740 	if (ACTIONTYPE(ctxt.z) != 0) {
741 		parseZoneTypeBlock(ctxt.z);
742 
743 //		if (ACTIONTYPE(ctxt.z) == kZoneHear) {
744 //			_soundMan->sfxCommand(START...);
745 //		}
746 	}
747 
748 	_parser->popTables();
749 }
750 
parsePathData(ZonePtr z)751 void LocationParser_br::parsePathData(ZonePtr z) {
752 	TypeData *data = &z->u;
753 	if (!scumm_stricmp("zone", _tokens[0])) {
754 		int id = atoi(_tokens[1]);
755 		parsePointList(data->_pathLists[id]);
756 		data->_pathNumLists++;
757 	}
758 }
759 
parseGetData(ZonePtr z)760 void LocationParser_br::parseGetData(ZonePtr z) {
761 	TypeData *data = &z->u;
762 	if (!scumm_stricmp(_tokens[0], "file")) {
763 		GfxObj *obj = _vm->_gfx->loadGet(_tokens[1]);
764 		obj->frame = 0;
765 		obj->x = z->getX();
766 		obj->y = z->getY();
767 		obj->_prog = _zoneProg;
768 		data->_gfxobj = obj;
769 	} else
770 	if (!scumm_stricmp(_tokens[0], "mask")) {
771 		_out->_info->loadGfxObjMask(_vm, _tokens[1], data->_gfxobj);
772 	} else
773 	if (!scumm_stricmp(_tokens[0], "path")) {
774 		_out->_info->loadGfxObjPath(_vm, _tokens[1], data->_gfxobj);
775 	} else
776 	if (!scumm_stricmp(_tokens[0], "icon")) {
777 		data->_getIcon = 4 + _vm->_objectsNames->lookup(_tokens[1]);
778 	}
779 }
780 
parseDoorData(ZonePtr z)781 void LocationParser_br::parseDoorData(ZonePtr z) {
782 	TypeData *data = &z->u;
783 	if (!scumm_stricmp(_tokens[0], "slidetext")) {
784 		_vm->_location._slideText[0] = _tokens[1];
785 		_vm->_location._slideText[1] = _tokens[2];
786 	} else
787 	if (!scumm_stricmp(_tokens[0], "location")) {
788 		data->_doorLocation = _tokens[1];
789 	} else
790 	if (!scumm_stricmp(_tokens[0], "file")) {
791 		GfxObj *obj = _vm->_gfx->loadDoor(_tokens[1]);
792 		obj->frame = z->_flags & kFlagsClosed ? 0 : 1;
793 		obj->x = z->getX();
794 		obj->y = z->getY();
795 		_vm->_gfx->showGfxObj(obj, true);
796 		data->_gfxobj = obj;
797 	} else
798 	if (!scumm_stricmp(_tokens[0],	"startpos")) {
799 		data->_doorStartPos.x = atoi(_tokens[1]);
800 		data->_doorStartPos.y = atoi(_tokens[2]);
801 		data->_doorStartFrame = atoi(_tokens[3]);
802 	} else
803 	if (!scumm_stricmp(_tokens[0],	"startpos2")) {
804 		data->_doorStartPos2_br.x = atoi(_tokens[1]);
805 		data->_doorStartPos2_br.y = atoi(_tokens[2]);
806 		data->_doorStartFrame2_br = atoi(_tokens[3]);
807 	}
808 }
809 
parseHearData(ZonePtr z)810 void LocationParser_br::parseHearData(ZonePtr z) {
811 	TypeData *data = &z->u;
812 	if (!scumm_stricmp(_tokens[0], "sound")) {
813 		assert(!data->_filename.size());
814 		data->_filename = _tokens[1];
815 		data->_hearChannel = atoi(_tokens[2]);
816 	} else
817 	if (!scumm_stricmp(_tokens[0], "freq")) {
818 		data->_hearFreq = atoi(_tokens[1]);
819 	} else
820 	if (!scumm_stricmp(_tokens[0], "music")) {
821 		assert(data->_hearChannel == FREE_HEAR_CHANNEL);
822 		data->_filename = _tokens[1];
823 		data->_hearChannel = MUSIC_HEAR_CHANNEL;
824 	}
825 }
826 
parseNoneData(ZonePtr z)827 void LocationParser_br::parseNoneData(ZonePtr z) {
828 	/* the only case we have to handle here is that of "scende2", which is the only Animation with
829 	   a command list following the type marker.
830 	*/
831 	if (!scumm_stricmp(_tokens[0], "commands")) {
832 		parseCommands(z->_commands);
833 	}
834 }
835 
836 
837 typedef void (LocationParser_br::*ZoneTypeParser)(ZonePtr);
838 static ZoneTypeParser parsers[] = {
839 	0,	// no type
840 	&LocationParser_br::parseExamineData,
841 	&LocationParser_br::parseDoorData,
842 	&LocationParser_br::parseGetData,
843 	&LocationParser_br::parseMergeData,
844 	0,	// taste
845 	&LocationParser_br::parseHearData,
846 	0,	// feel
847 	&LocationParser_br::parseSpeakData,
848 	&LocationParser_br::parseNoneData,
849 	0,	// trap
850 	0,	// you
851 	0,	// command
852 	&LocationParser_br::parsePathData,
853 	0,	// box
854 };
855 
parseZoneTypeBlock(ZonePtr z)856 void LocationParser_br::parseZoneTypeBlock(ZonePtr z) {
857 	debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_name, z->_type);
858 
859 	ZoneTypeParser p = parsers[ACTIONTYPE(z)];
860 	do {
861 		if (p) {
862 			(this->*p)(z);
863 		}
864 		_script->readLineToken(true);
865 	} while (scumm_stricmp(_tokens[0], "endzone") && scumm_stricmp(_tokens[0], "endanimation"));
866 	debugC(7, kDebugParser, "parseZoneTypeBlock() done");
867 }
868 
DECLARE_ANIM_PARSER(file)869 DECLARE_ANIM_PARSER(file)  {
870 	debugC(7, kDebugParser, "ANIM_PARSER(file) ");
871 
872 	ctxt.a->gfxobj = _vm->_gfx->loadAnim(_tokens[1]);
873 }
874 
875 
DECLARE_ANIM_PARSER(position)876 DECLARE_ANIM_PARSER(position)  {
877 	debugC(7, kDebugParser, "ANIM_PARSER(position) ");
878 
879 	ctxt.a->setX(atoi(_tokens[1]));
880 	ctxt.a->setY(atoi(_tokens[2]));
881 	ctxt.a->setZ(atoi(_tokens[3]));
882 	ctxt.a->setF(atoi(_tokens[4]));
883 }
884 
885 
DECLARE_ANIM_PARSER(moveto)886 DECLARE_ANIM_PARSER(moveto)  {
887 	debugC(7, kDebugParser, "ANIM_PARSER(moveto) ");
888 
889 	ctxt.a->_moveTo.x = atoi(_tokens[1]);
890 	ctxt.a->_moveTo.y = atoi(_tokens[2]);
891 //	ctxt.a->_moveTo.z = atoi(_tokens[3]);
892 }
893 
DECLARE_ANIM_PARSER(endanimation)894 DECLARE_ANIM_PARSER(endanimation)  {
895 	debugC(7, kDebugParser, "ANIM_PARSER(endanimation) ");
896 
897 #if 0
898 	// I have disabled the following code since it seems useless.
899 	// I will remove it after mask processing is done.
900 	if (ctxt.a->gfxobj) {
901 		ctxt.a->_right = ctxt.a->width();
902 		ctxt.a->_bottom = ctxt.a->height();
903 	}
904 #endif
905 	ctxt.a->_flags |= 0x1000000;
906 
907 	_parser->popTables();
908 }
909 
910 
parseAnswerCounter(Answer * answer)911 void LocationParser_br::parseAnswerCounter(Answer *answer) {
912 	if (!_tokens[1][0]) {
913 		return;
914 	}
915 
916 	if (scumm_stricmp(_tokens[1], "counter")) {
917 		return;
918 	}
919 
920 	if (!_vm->counterExists(_tokens[2])) {
921 		error("unknown counter '%s' in dialogue", _tokens[2]);
922 	}
923 
924 	answer->_hasCounterCondition = true;
925 
926 	answer->_counterName = _tokens[2];
927 	answer->_counterValue = atoi(_tokens[4]);
928 
929 	if (_tokens[3][0] == '>') {
930 		answer->_counterOp = CMD_TEST_GT;
931 	} else
932 	if (_tokens[3][0] == '<') {
933 		answer->_counterOp = CMD_TEST_LT;
934 	} else {
935 		answer->_counterOp = CMD_TEST;
936 	}
937 
938 }
939 
940 
941 
parseAnswer()942 Answer *LocationParser_br::parseAnswer() {
943 	Answer *answer = new Answer;
944 	assert(answer);
945 	parseAnswerFlags(answer);
946 	parseAnswerCounter(answer);
947 	parseAnswerBody(answer);
948 	return answer;
949 }
950 
951 
952 
953 
954 
955 
956 
957 
DECLARE_INSTRUCTION_PARSER(zone)958 DECLARE_INSTRUCTION_PARSER(zone)  {
959 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(zone) ");
960 
961 	ctxt.inst->_z = _vm->_location.findZone(_tokens[1]);
962 	ctxt.inst->_index = _parser->_lookup;
963 }
964 
965 
966 
DECLARE_INSTRUCTION_PARSER(color)967 DECLARE_INSTRUCTION_PARSER(color)  {
968 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(color) ");
969 
970 
971 	parseRValue(ctxt.inst->_opB, _tokens[1]);
972 
973 	ctxt.inst->_colors[0] = atoi(_tokens[2]);
974 	ctxt.inst->_colors[1] = atoi(_tokens[3]);
975 	ctxt.inst->_colors[2] = atoi(_tokens[4]);
976 	ctxt.inst->_index = _parser->_lookup;
977 
978 }
979 
980 
DECLARE_INSTRUCTION_PARSER(mask)981 DECLARE_INSTRUCTION_PARSER(mask)  {
982 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(mask) ");
983 
984 
985 	parseRValue(ctxt.inst->_opA, _tokens[1]);
986 	parseRValue(ctxt.inst->_opB, _tokens[2]);
987 	parseRValue(ctxt.inst->_opC, _tokens[3]);
988 	ctxt.inst->_index = _parser->_lookup;
989 
990 }
991 
992 
DECLARE_INSTRUCTION_PARSER(print)993 DECLARE_INSTRUCTION_PARSER(print)  {
994 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(print) ");
995 
996 	parseRValue(ctxt.inst->_opB, _tokens[1]);
997 	ctxt.inst->_index = _parser->_lookup;
998 }
999 
1000 
DECLARE_INSTRUCTION_PARSER(text)1001 DECLARE_INSTRUCTION_PARSER(text)  {
1002 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(text) ");
1003 
1004 
1005 	int _si = 1;
1006 
1007 	if (Common::isDigit(_tokens[1][1])) {
1008 		ctxt.inst->_y = atoi(_tokens[1]);
1009 		_si = 2;
1010 	} else {
1011 		ctxt.inst->_y = -1;
1012 	}
1013 
1014 	ctxt.inst->_text = _tokens[_si];
1015 	_si++;
1016 
1017 	if (_tokens[_si][0] != '\0' && scumm_stricmp("flags", _tokens[_si])) {
1018 		ctxt.inst->_text2 = _tokens[_si];
1019 	}
1020 	ctxt.inst->_index = _parser->_lookup;
1021 
1022 }
1023 
1024 
DECLARE_INSTRUCTION_PARSER(if_op)1025 DECLARE_INSTRUCTION_PARSER(if_op)  {
1026 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(if_op) ");
1027 
1028 	beginIfStatement();
1029 
1030 	parseLValue(ctxt.inst->_opA, _tokens[1]);
1031 	parseRValue(ctxt.inst->_opB, _tokens[3]);
1032 
1033 	if (_tokens[2][0] == '=') {
1034 		ctxt.inst->_index = INST_IFEQ;
1035 	} else
1036 	if (_tokens[2][0] == '>') {
1037 		ctxt.inst->_index = INST_IFGT;
1038 	} else
1039 	if (_tokens[2][0] == '<') {
1040 		ctxt.inst->_index = INST_IFLT;
1041 	} else
1042 		error("unknown test operator '%s' in if-clause", _tokens[2]);
1043 }
1044 
beginIfStatement()1045 void ProgramParser_br::beginIfStatement() {
1046 	if (_openIfStatement != -1)
1047 		error("cannot nest 'if' statements");
1048 
1049 	_openIfStatement = _currentInstruction;
1050 }
1051 
endIfStatement()1052 void ProgramParser_br::endIfStatement() {
1053 	if (_openIfStatement == -1)
1054 		error("unexpected 'endif' in script");
1055 
1056 	_program->_instructions[_openIfStatement]->_endif = _currentInstruction;
1057 	_openIfStatement = -1;
1058 }
1059 
1060 
DECLARE_INSTRUCTION_PARSER(endif)1061 DECLARE_INSTRUCTION_PARSER(endif)  {
1062 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(endif) ");
1063 	endIfStatement();
1064 	ctxt.inst->_index = _parser->_lookup;
1065 }
1066 
1067 
parseRValue(ScriptVar & v,const char * str)1068 void ProgramParser_br::parseRValue(ScriptVar &v, const char *str) {
1069 
1070 	if (Common::isDigit(str[0]) || str[0] == '-') {
1071 		v.setImmediate(atoi(str));
1072 		return;
1073 	}
1074 
1075 	int index = _program->findLocal(str);
1076 	if (index != -1) {
1077 		v.setLocal(&ctxt.locals[index]);
1078 		return;
1079 	}
1080 
1081 	AnimationPtr a;
1082 	if (str[1] == '.') {
1083 		a = _vm->_location.findAnimation(&str[2]);
1084 		if (!a) {
1085 			error("unknown animation '%s' in script", &str[2]);
1086 		}
1087 	} else
1088 		a = AnimationPtr(ctxt.a);
1089 
1090 	if (str[0] == 'X') {
1091 		v.setField(a.get(), &Animation::getX);
1092 	} else
1093 	if (str[0] == 'Y') {
1094 		v.setField(a.get(), &Animation::getY);
1095 	} else
1096 	if (str[0] == 'Z') {
1097 		v.setField(a.get(), &Animation::getZ);
1098 	} else
1099 	if (str[0] == 'F') {
1100 		v.setField(a.get(), &Animation::getF);
1101 	}	else
1102 	if (str[0] == 'N') {
1103 		v.setImmediate(a->getFrameNum());
1104 	} else
1105 	if (str[0] == 'R') {
1106 		v.setRandom(atoi(&str[1]));
1107 	} else
1108 	if (str[0] == 'L') {
1109 #if 0	// disabled because no references to lip sync has been found in the scripts
1110 		v.setField(&_vm->_lipSyncVal);
1111 #endif
1112 		warning("Lip sync instruction encountered! Please notify the team");
1113 	}
1114 
1115 }
1116 
parse(Script * script,ProgramPtr program)1117 void ProgramParser_br::parse(Script *script, ProgramPtr program) {
1118 	_openIfStatement = -1;
1119 	ProgramParser_ns::parse(script, program);
1120 }
1121 
1122 
init()1123 void LocationParser_br::init() {
1124 
1125 	_parser = new Parser;
1126 
1127 	_zoneFlagNames = new Table(ARRAYSIZE(_zoneFlagNamesRes_br), _zoneFlagNamesRes_br);
1128 	_zoneTypeNames = new Table(ARRAYSIZE(_zoneTypeNamesRes_br), _zoneTypeNamesRes_br);
1129 	_commandsNames = new Table(ARRAYSIZE(_commandsNamesRes_br), _commandsNamesRes_br);
1130 	_audioCommandsNames = new Table(ARRAYSIZE(_audioCommandsNamesRes_br), _audioCommandsNamesRes_br);
1131 	_locationStmt = new Table(ARRAYSIZE(_locationStmtRes_br), _locationStmtRes_br);
1132 	_locationZoneStmt = new Table(ARRAYSIZE(_locationZoneStmtRes_br), _locationZoneStmtRes_br);
1133 	_locationAnimStmt = new Table(ARRAYSIZE(_locationAnimStmtRes_br), _locationAnimStmtRes_br);
1134 
1135 	Common::Array<const Opcode *> *table = 0;
1136 
1137 	SetOpcodeTable(_commandParsers);
1138 	WARNING_PARSER(unexpected);
1139 	COMMAND_PARSER(flags);		// set
1140 	COMMAND_PARSER(flags);		// clear
1141 	COMMAND_PARSER(zone);	// start
1142 	COMMAND_PARSER(zone);		// speak
1143 	COMMAND_PARSER(zone);		// get
1144 	COMMAND_PARSER(location);
1145 	COMMAND_PARSER(zone);		// open
1146 	COMMAND_PARSER(zone);		// close
1147 	COMMAND_PARSER(zone);		// on
1148 	COMMAND_PARSER(zone);		// off
1149 	COMMAND_PARSER(call);
1150 	COMMAND_PARSER(flags);		// toggle
1151 	COMMAND_PARSER(invObject);	// drop
1152 	COMMAND_PARSER(simple);		// quit
1153 	COMMAND_PARSER(move);
1154 	COMMAND_PARSER(zone);	// stop
1155 	COMMAND_PARSER(string);		// character
1156 	COMMAND_PARSER(string);		// followme
1157 	COMMAND_PARSER(simple);		// onmouse
1158 	COMMAND_PARSER(simple);		// offmouse
1159 	COMMAND_PARSER(invObject);		// add
1160 	COMMAND_PARSER(zone);		// leave
1161 	COMMAND_PARSER(math);		// inc
1162 	COMMAND_PARSER(math);		// dec
1163 	COMMAND_PARSER(test);		// test
1164 	WARNING_PARSER(unexpected);
1165 	WARNING_PARSER(unexpected);
1166 	COMMAND_PARSER(math);		// let
1167 	COMMAND_PARSER(music);
1168 	COMMAND_PARSER(zone);		// fix
1169 	COMMAND_PARSER(zone);		// unfix
1170 	COMMAND_PARSER(zeta);
1171 	COMMAND_PARSER(unary);		// scroll
1172 	COMMAND_PARSER(string);		// swap
1173 	COMMAND_PARSER(give);
1174 	COMMAND_PARSER(text);
1175 	COMMAND_PARSER(unary);		// part
1176 	WARNING_PARSER(unexpected);
1177 	COMMAND_PARSER(simple);		// return
1178 	COMMAND_PARSER(simple);		// onsave
1179 	COMMAND_PARSER(simple);		// offsave
1180 	COMMAND_PARSER(endcommands);	// endcommands
1181 	COMMAND_PARSER(ifchar);
1182 	COMMAND_PARSER(endif);
1183 
1184 	SetOpcodeTable(_locationParsers);
1185 	WARNING_PARSER(unexpected);
1186 	LOCATION_PARSER(character);
1187 	LOCATION_PARSER(endlocation);
1188 	LOCATION_PARSER(ifchar);
1189 	LOCATION_PARSER(null);			// endif
1190 	LOCATION_PARSER(location);
1191 	LOCATION_PARSER(mask);
1192 	LOCATION_PARSER(path);
1193 	LOCATION_PARSER(null);			// disk
1194 	LOCATION_PARSER(localflags);
1195 	LOCATION_PARSER(commands);
1196 	LOCATION_PARSER(escape);
1197 	LOCATION_PARSER(acommands);
1198 	LOCATION_PARSER(flags);
1199 	LOCATION_PARSER(comment);
1200 	LOCATION_PARSER(endcomment);
1201 	LOCATION_PARSER(zone);
1202 	LOCATION_PARSER(animation);
1203 	LOCATION_PARSER(zeta);
1204 	LOCATION_PARSER(music);
1205 	LOCATION_PARSER(sound);
1206 
1207 	SetOpcodeTable(_locationZoneParsers);
1208 	WARNING_PARSER(unexpected);
1209 	ZONE_PARSER(endzone);
1210 	ZONE_PARSER(limits);
1211 	ZONE_PARSER(moveto);
1212 	ZONE_PARSER(type);
1213 	ZONE_PARSER(commands);
1214 	ZONE_PARSER(label);
1215 	ZONE_PARSER(flags);
1216 
1217 
1218 	SetOpcodeTable(_locationAnimParsers);
1219 	WARNING_PARSER(unexpected);
1220 	ANIM_PARSER(endanimation);
1221 	ANIM_PARSER(endanimation);		// endzone
1222 	ANIM_PARSER(script);
1223 	ANIM_PARSER(commands);
1224 	ANIM_PARSER(type);
1225 	ANIM_PARSER(label);
1226 	ANIM_PARSER(flags);
1227 	ANIM_PARSER(file);
1228 	ANIM_PARSER(position);
1229 	ANIM_PARSER(moveto);
1230 }
1231 
init()1232 void ProgramParser_br::init() {
1233 
1234 	_parser = new Parser;
1235 
1236 	_instructionNames = new Table(ARRAYSIZE(_instructionNamesRes_br), _instructionNamesRes_br);
1237 
1238 	Common::Array<const Opcode *> *table = 0;
1239 
1240 	SetOpcodeTable(_instructionParsers);
1241 	INSTRUCTION_PARSER(defLocal);	// invalid opcode -> local definition
1242 	INSTRUCTION_PARSER(zone);		// on
1243 	INSTRUCTION_PARSER(zone);		// off
1244 	INSTRUCTION_PARSER(x);
1245 	INSTRUCTION_PARSER(y);
1246 	INSTRUCTION_PARSER(z);
1247 	INSTRUCTION_PARSER(f);
1248 	INSTRUCTION_PARSER(loop);
1249 	INSTRUCTION_PARSER(null);		// endloop
1250 	INSTRUCTION_PARSER(null);		// show
1251 	INSTRUCTION_PARSER(inc);
1252 	INSTRUCTION_PARSER(inc);		// dec
1253 	INSTRUCTION_PARSER(set);
1254 	INSTRUCTION_PARSER(put);
1255 	INSTRUCTION_PARSER(call);
1256 	INSTRUCTION_PARSER(null);		// wait
1257 	INSTRUCTION_PARSER(zone);		// start
1258 	INSTRUCTION_PARSER(zone);		// process
1259 	INSTRUCTION_PARSER(move);
1260 	INSTRUCTION_PARSER(color);
1261 	INSTRUCTION_PARSER(zone);		// sound
1262 	INSTRUCTION_PARSER(mask);
1263 	INSTRUCTION_PARSER(print);
1264 	INSTRUCTION_PARSER(text);
1265 	INSTRUCTION_PARSER(inc);		// mul
1266 	INSTRUCTION_PARSER(inc);		// div
1267 	INSTRUCTION_PARSER(if_op);
1268 	INSTRUCTION_PARSER(null);
1269 	INSTRUCTION_PARSER(null);
1270 	INSTRUCTION_PARSER(endif);
1271 	INSTRUCTION_PARSER(zone);		// stop
1272 	INSTRUCTION_PARSER(endscript);
1273 }
1274 
parse(Script * script,LocationParserOutput_br * out)1275 void LocationParser_br::parse(Script *script, LocationParserOutput_br *out) {
1276 	assert(out);
1277 	_out = out;
1278 	_out->_info = new BackgroundInfo;
1279 	assert(_out->_info);
1280 
1281 	LocationParser_ns::parse(script);
1282 }
1283 
1284 } // namespace Parallaction
1285