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 
48 #define INST_ON				1
49 #define INST_OFF			2
50 #define INST_X				3
51 #define INST_Y				4
52 #define INST_Z				5
53 #define INST_F				6
54 #define INST_LOOP			7
55 #define INST_ENDLOOP		8
56 #define INST_SHOW			9
57 #define INST_INC			10
58 #define INST_DEC			11
59 #define INST_SET			12
60 #define INST_PUT			13
61 #define INST_CALL			14
62 #define INST_WAIT			15
63 #define INST_START			16
64 #define INST_SOUND			17
65 #define INST_MOVE			18
66 #define INST_END			19
67 
68 
69 const char *_zoneFlagNamesRes_ns[] = {
70 	"closed",
71 	"active",
72 	"remove",
73 	"acting",
74 	"locked",
75 	"fixed",
76 	"noname",
77 	"nomasked",
78 	"looping",
79 	"added",
80 	"character",
81 	"nowalk"
82 };
83 
84 const char *_zoneTypeNamesRes_ns[] = {
85 	"examine",
86 	"door",
87 	"get",
88 	"merge",
89 	"taste",
90 	"hear",
91 	"feel",
92 	"speak",
93 	"none",
94 	"trap",
95 	"yourself",
96 	"Command"
97 };
98 
99 const char *_commandsNamesRes_ns[] = {
100 	"set",
101 	"clear",
102 	"start",
103 	"speak",
104 	"get",
105 	"location",
106 	"open",
107 	"close",
108 	"on",
109 	"off",
110 	"call",
111 	"toggle",
112 	"drop",
113 	"quit",
114 	"move",
115 	"stop",
116 	"endcommands",
117 	"endzone"
118 };
119 
120 const char *_locationStmtRes_ns[] = {
121 	"endlocation",
122 	"location",
123 	"disk",
124 	"nodes",
125 	"zone",
126 	"animation",
127 	"localflags",
128 	"commands",
129 	"acommands",
130 	"flags",
131 	"comment",
132 	"endcomment",
133 	"sound",
134 	"music"
135 };
136 
137 const char *_locationZoneStmtRes_ns[] = {
138 	"limits",
139 	"moveto",
140 	"type",
141 	"commands",
142 	"label",
143 	"flags",
144 	"endzone"
145 };
146 
147 const char *_locationAnimStmtRes_ns[] = {
148 	"script",
149 	"commands",
150 	"type",
151 	"label",
152 	"flags",
153 	"file",
154 	"position",
155 	"moveto",
156 	"endanimation"
157 };
158 
159 const char *_instructionNamesRes_ns[] = {
160 	"on",
161 	"off",
162 	"x",
163 	"y",
164 	"z",
165 	"f",
166 	"loop",
167 	"endloop",
168 	"show",
169 	"inc",
170 	"dec",
171 	"set",
172 	"put",
173 	"call",
174 	"wait",
175 	"start",
176 	"sound",
177 	"move",
178 	"endscript"
179 };
180 
181 
182 #define DECLARE_ZONE_PARSER(sig) void LocationParser_ns::locZoneParse_##sig()
183 #define DECLARE_ANIM_PARSER(sig) void LocationParser_ns::locAnimParse_##sig()
184 #define DECLARE_COMMAND_PARSER(sig) void LocationParser_ns::cmdParse_##sig()
185 #define DECLARE_LOCATION_PARSER(sig) void LocationParser_ns::locParse_##sig()
186 
187 #define DECLARE_INSTRUCTION_PARSER(sig) void ProgramParser_ns::instParse_##sig()
188 
189 
warning_unexpected()190 void LocationParser_ns::warning_unexpected() {
191 	debugC(1, kDebugParser, "unexpected keyword '%s' in line %i", _tokens[0], _script->getLine());
192 }
193 
194 
DECLARE_ANIM_PARSER(script)195 DECLARE_ANIM_PARSER(script)  {
196 	debugC(7, kDebugParser, "ANIM_PARSER(script) ");
197 
198 	ctxt.a->_scriptName = _tokens[1];
199 }
200 
201 
DECLARE_ANIM_PARSER(commands)202 DECLARE_ANIM_PARSER(commands)  {
203 	debugC(7, kDebugParser, "ANIM_PARSER(commands) ");
204 
205 	 parseCommands(ctxt.a->_commands);
206 }
207 
208 
DECLARE_ANIM_PARSER(type)209 DECLARE_ANIM_PARSER(type)  {
210 	debugC(7, kDebugParser, "ANIM_PARSER(type) ");
211 
212 	ctxt.a->_type = buildZoneType(_tokens[1], _tokens[2]);
213 	if ((ACTIONTYPE(ctxt.a) != 0) && (ACTIONTYPE(ctxt.a) != kZoneCommand)) {
214 		parseZoneTypeBlock(ctxt.a);
215 	}
216 
217 	ctxt.a->_flags |= 0x1000000;
218 
219 	_parser->popTables();
220 }
221 
222 
DECLARE_ANIM_PARSER(label)223 DECLARE_ANIM_PARSER(label)  {
224 	debugC(7, kDebugParser, "ANIM_PARSER(label) ");
225 
226 	ctxt.a->_label = _vm->_gfx->renderFloatingLabel(_vm->_labelFont, _tokens[1]);
227 	ctxt.a->_flags &= ~kFlagsNoName;
228 }
229 
230 
DECLARE_ANIM_PARSER(flags)231 DECLARE_ANIM_PARSER(flags)  {
232 	debugC(7, kDebugParser, "ANIM_PARSER(flags) ");
233 
234 	uint16 _si = 1;
235 
236 	do {
237 		byte _al = _zoneFlagNames->lookup(_tokens[_si]);
238 		_si++;
239 		ctxt.a->_flags |= 1 << (_al - 1);
240 	} while (!scumm_stricmp(_tokens[_si++], "|"));
241 }
242 
243 
DECLARE_ANIM_PARSER(file)244 DECLARE_ANIM_PARSER(file)  {
245 	debugC(7, kDebugParser, "ANIM_PARSER(file) ");
246 
247 	char vC8[200];
248 	strcpy(vC8, _tokens[1]);
249 	if (g_engineFlags & kEngineTransformedDonna) {
250 		if (!scumm_stricmp(_tokens[1], "donnap") || !scumm_stricmp(_tokens[1], "donnapa")) {
251 			strcat(vC8, "tras");
252 		}
253 	}
254 	ctxt.a->gfxobj = _vm->_gfx->loadAnim(vC8);
255 }
256 
257 
DECLARE_ANIM_PARSER(position)258 DECLARE_ANIM_PARSER(position)  {
259 	debugC(7, kDebugParser, "ANIM_PARSER(position) ");
260 
261 	ctxt.a->setX(atoi(_tokens[1]));
262 	ctxt.a->setY(atoi(_tokens[2]));
263 	ctxt.a->setZ(atoi(_tokens[3]));
264 }
265 
266 
DECLARE_ANIM_PARSER(moveto)267 DECLARE_ANIM_PARSER(moveto)  {
268 	debugC(7, kDebugParser, "ANIM_PARSER(moveto) ");
269 
270 	ctxt.a->_moveTo.x = atoi(_tokens[1]);
271 	ctxt.a->_moveTo.y = atoi(_tokens[2]);
272 }
273 
274 
DECLARE_ANIM_PARSER(endanimation)275 DECLARE_ANIM_PARSER(endanimation)  {
276 	debugC(7, kDebugParser, "ANIM_PARSER(endanimation) ");
277 
278 	ctxt.a->_flags |= 0x1000000;
279 
280 	_parser->popTables();
281 }
282 
parseAnimation(AnimationList & list,char * name)283 void LocationParser_ns::parseAnimation(AnimationList &list, char *name) {
284 	debugC(5, kDebugParser, "parseAnimation(name: %s)", name);
285 
286 	if (_vm->_location.findAnimation(name)) {
287 		_zoneProg++;
288 		_script->skip("endanimation");
289 		return;
290 	}
291 
292 	AnimationPtr a(new Animation);
293 	_zoneProg++;
294 
295 	Common::strlcpy(a->_name, name, ZONENAME_LENGTH);
296 	a->_flags |= kFlagsIsAnimation;
297 
298 	list.push_front(AnimationPtr(a));
299 
300 	ctxt.a = a;
301 	_parser->pushTables(&_locationAnimParsers, _locationAnimStmt);
302 }
303 
parseInstruction()304 void ProgramParser_ns::parseInstruction() {
305 
306 	_script->readLineToken(true);
307 
308 	if (_tokens[0][1] == '.') {
309 		_tokens[0][1] = '\0';
310 		ctxt.a = _vm->_location.findAnimation(&_tokens[0][2]);
311 	} else
312 	if (_tokens[1][1] == '.') {
313 		_tokens[1][1] = '\0';
314 		ctxt.a = _vm->_location.findAnimation(&_tokens[1][2]);
315 	} else
316 		ctxt.a = _program->_anim;
317 
318 	if (!ctxt.a) {
319 		return;
320 	}
321 
322 	InstructionPtr inst(new Instruction);
323 	ctxt.inst = inst;
324 
325 	_currentInstruction = _program->_instructions.size();
326 
327 	_parser->parseStatement();
328 	_program->_instructions.push_back(inst);
329 
330 	return;
331 }
332 
parse(Script * script,ProgramPtr program)333 void ProgramParser_ns::parse(Script *script, ProgramPtr program) {
334 	_script = script;
335 	_program = program;
336 
337 	ctxt.end = false;
338 	ctxt.locals = program->_locals;
339 
340 	_parser->reset();
341 	_parser->pushTables(&_instructionParsers, _instructionNames);
342 	do {
343 		parseInstruction();
344 	} while (!ctxt.end);
345 	_parser->popTables();
346 
347 	program->_ip = 0;
348 }
349 
loadProgram(AnimationPtr a,const char * filename)350 void Parallaction_ns::loadProgram(AnimationPtr a, const char *filename) {
351 	debugC(1, kDebugParser, "loadProgram(Animation: %s, script: %s)", a->_name, filename);
352 
353 	Script *script = _disk->loadScript(filename);
354 	ProgramPtr program(new Program);
355 	program->_anim = a;
356 
357 	_programParser->parse(script, program);
358 
359 	delete script;
360 
361 	_location._programs.push_back(program);
362 
363 	debugC(1, kDebugParser, "loadProgram() done");
364 
365 	return;
366 }
367 
DECLARE_INSTRUCTION_PARSER(animation)368 DECLARE_INSTRUCTION_PARSER(animation)  {
369 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(animation) ");
370 
371 	if (!scumm_stricmp(_tokens[1], ctxt.a->_name)) {
372 		ctxt.inst->_a = ctxt.a;
373 	} else {
374 		ctxt.inst->_a = _vm->_location.findAnimation(_tokens[1]);
375 	}
376 
377 	ctxt.inst->_index = _parser->_lookup;
378 }
379 
380 
DECLARE_INSTRUCTION_PARSER(loop)381 DECLARE_INSTRUCTION_PARSER(loop)  {
382 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(loop) ");
383 
384 	parseRValue(ctxt.inst->_opB, _tokens[1]);
385 	ctxt.inst->_index = _parser->_lookup;
386 }
387 
388 
DECLARE_INSTRUCTION_PARSER(x)389 DECLARE_INSTRUCTION_PARSER(x)  {
390 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(x) ");
391 
392 	parseLValue(ctxt.inst->_opA, "X");
393 	parseRValue(ctxt.inst->_opB, _tokens[1]);
394 	ctxt.inst->_index = _parser->_lookup;
395 }
396 
397 
DECLARE_INSTRUCTION_PARSER(y)398 DECLARE_INSTRUCTION_PARSER(y)  {
399 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(y) ");
400 
401 	parseLValue(ctxt.inst->_opA, "Y");
402 	parseRValue(ctxt.inst->_opB, _tokens[1]);
403 	ctxt.inst->_index = _parser->_lookup;
404 }
405 
406 
DECLARE_INSTRUCTION_PARSER(z)407 DECLARE_INSTRUCTION_PARSER(z)  {
408 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(z) ");
409 
410 	parseLValue(ctxt.inst->_opA, "Z");
411 	parseRValue(ctxt.inst->_opB, _tokens[1]);
412 	ctxt.inst->_index = _parser->_lookup;
413 }
414 
415 
DECLARE_INSTRUCTION_PARSER(f)416 DECLARE_INSTRUCTION_PARSER(f)  {
417 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(f) ");
418 
419 	parseLValue(ctxt.inst->_opA, "F");
420 	parseRValue(ctxt.inst->_opB, _tokens[1]);
421 	ctxt.inst->_index = _parser->_lookup;
422 }
423 
424 
DECLARE_INSTRUCTION_PARSER(inc)425 DECLARE_INSTRUCTION_PARSER(inc)  {
426 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(inc) ");
427 
428 	parseLValue(ctxt.inst->_opA, _tokens[1]);
429 	parseRValue(ctxt.inst->_opB, _tokens[2]);
430 
431 	if (!scumm_stricmp(_tokens[3], "mod")) {
432 		ctxt.inst->_flags |= kInstMod;
433 	}
434 	ctxt.inst->_index = _parser->_lookup;
435 }
436 
437 
DECLARE_INSTRUCTION_PARSER(set)438 DECLARE_INSTRUCTION_PARSER(set)  {
439 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(set) ");
440 
441 	// WORKAROUND: At least one script (balzo.script) in Amiga versions didn't declare
442 	//	local variables before using them, thus leading to crashes. The line launching the
443 	// script was commented out on Dos version. This workaround enables the engine
444 	// to dynamically add a local variable when it is encountered the first time in
445 	// the script, so should fix any other occurrence as well.
446 	if (_program->findLocal(_tokens[1]) == -1) {
447 		_program->addLocal(_tokens[1]);
448 	}
449 
450 	parseLValue(ctxt.inst->_opA, _tokens[1]);
451 	parseRValue(ctxt.inst->_opB, _tokens[2]);
452 	ctxt.inst->_index = _parser->_lookup;
453 }
454 
455 
DECLARE_INSTRUCTION_PARSER(move)456 DECLARE_INSTRUCTION_PARSER(move)  {
457 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(move) ");
458 
459 	parseRValue(ctxt.inst->_opA, _tokens[1]);
460 	parseRValue(ctxt.inst->_opB, _tokens[2]);
461 	ctxt.inst->_index = _parser->_lookup;
462 }
463 
464 
DECLARE_INSTRUCTION_PARSER(put)465 DECLARE_INSTRUCTION_PARSER(put)  {
466 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(put) ");
467 
468 	if (!scumm_stricmp(_tokens[1], ctxt.a->_name)) {
469 		ctxt.inst->_a = ctxt.a;
470 	} else {
471 		ctxt.inst->_a = _vm->_location.findAnimation(_tokens[1]);
472 	}
473 
474 	parseRValue(ctxt.inst->_opA, _tokens[2]);
475 	parseRValue(ctxt.inst->_opB, _tokens[3]);
476 	if (!scumm_stricmp(_tokens[4], "masked")) {
477 		ctxt.inst->_flags |= kInstMaskedPut;
478 	}
479 	ctxt.inst->_index = _parser->_lookup;
480 }
481 
482 
DECLARE_INSTRUCTION_PARSER(call)483 DECLARE_INSTRUCTION_PARSER(call)  {
484 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(call) ");
485 
486 	int index = _vm->_callableNames->lookup(_tokens[1]);
487 	if (index == Table::notFound)
488 		error("unknown callable '%s'", _tokens[1]);
489 	ctxt.inst->_immediate = index - 1;
490 	ctxt.inst->_index = _parser->_lookup;
491 }
492 
493 
DECLARE_INSTRUCTION_PARSER(sound)494 DECLARE_INSTRUCTION_PARSER(sound)  {
495 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(sound) ");
496 
497 	ctxt.inst->_z = _vm->_location.findZone(_tokens[1]);
498 	ctxt.inst->_index = _parser->_lookup;
499 }
500 
501 
DECLARE_INSTRUCTION_PARSER(null)502 DECLARE_INSTRUCTION_PARSER(null)  {
503 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(null) ");
504 	ctxt.inst->_index = _parser->_lookup;
505 }
506 
507 
DECLARE_INSTRUCTION_PARSER(defLocal)508 DECLARE_INSTRUCTION_PARSER(defLocal)  {
509 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(defLocal) ");
510 
511 	int16 val = atoi(_tokens[2]);
512 	int16 index;
513 
514 	if (_tokens[3][0] != '\0') {
515 		index = _program->addLocal(_tokens[0], val, atoi(_tokens[3]), atoi(_tokens[4]));
516 	} else {
517 		index = _program->addLocal(_tokens[0], val);
518 	}
519 
520 	ctxt.inst->_opA.setLocal(&ctxt.locals[index]);
521 	ctxt.inst->_opB.setImmediate(ctxt.locals[index].getValue());
522 
523 	ctxt.inst->_index = INST_SET;
524 }
525 
DECLARE_INSTRUCTION_PARSER(endscript)526 DECLARE_INSTRUCTION_PARSER(endscript)  {
527 	debugC(7, kDebugParser, "INSTRUCTION_PARSER(endscript) ");
528 
529 	ctxt.end = true;
530 	ctxt.inst->_index = _parser->_lookup;
531 }
532 
533 
534 
parseRValue(ScriptVar & v,const char * str)535 void ProgramParser_ns::parseRValue(ScriptVar &v, const char *str) {
536 
537 	if (Common::isDigit(str[0]) || str[0] == '-') {
538 		v.setImmediate(atoi(str));
539 		return;
540 	}
541 
542 	int index = _program->findLocal(str);
543 	if (index != -1) {
544 		v.setLocal(&ctxt.locals[index]);
545 		return;
546 	}
547 
548 	AnimationPtr a;
549 	if (str[1] == '.') {
550 		a = _vm->_location.findAnimation(&str[2]);
551 	} else {
552 		a = ctxt.a;
553 	}
554 
555 	if (str[0] == 'X') {
556 		v.setField(a.get(), &Animation::getX);
557 	} else
558 	if (str[0] == 'Y') {
559 		v.setField(a.get(), &Animation::getY);
560 	} else
561 	if (str[0] == 'Z') {
562 		v.setField(a.get(), &Animation::getZ);
563 	} else
564 	if (str[0] == 'F') {
565 		v.setField(a.get(), &Animation::getF);
566 	}
567 
568 }
569 
parseLValue(ScriptVar & v,const char * str)570 void ProgramParser_ns::parseLValue(ScriptVar &v, const char *str) {
571 
572 	int index = _program->findLocal(str);
573 	if (index != -1) {
574 		v.setLocal(&ctxt.locals[index]);
575 		return;
576 	}
577 
578 	AnimationPtr a;
579 	if (str[1] == '.') {
580 		a = _vm->_location.findAnimation(&str[2]);
581 	} else {
582 		a = ctxt.a;
583 	}
584 
585 	if (str[0] == 'X') {
586 		v.setField(a.get(), &Animation::getX, &Animation::setX);
587 	} else
588 	if (str[0] == 'Y') {
589 		v.setField(a.get(), &Animation::getY, &Animation::setY);
590 	} else
591 	if (str[0] == 'Z') {
592 		v.setField(a.get(), &Animation::getZ, &Animation::setZ);
593 	} else
594 	if (str[0] == 'F') {
595 		v.setField(a.get(), &Animation::getF, &Animation::setF);
596 	}
597 
598 }
599 
600 
DECLARE_COMMAND_PARSER(flags)601 DECLARE_COMMAND_PARSER(flags)  {
602 	debugC(7, kDebugParser, "COMMAND_PARSER(flags) ");
603 
604 	createCommand(_parser->_lookup);
605 
606 	if (_vm->_globalFlagsNames->lookup(_tokens[1]) == Table::notFound) {
607 		do {
608 			char _al = _vm->_localFlagNames->lookup(_tokens[ctxt.nextToken]);
609 			ctxt.nextToken++;
610 			ctxt.cmd->_flags |= 1 << (_al - 1);
611 		} while (!scumm_stricmp(_tokens[ctxt.nextToken++], "|"));
612 		ctxt.nextToken--;
613 	} else {
614 		ctxt.cmd->_flags |= kFlagsGlobal;
615 		do {
616 			char _al = _vm->_globalFlagsNames->lookup(_tokens[1]);
617 			ctxt.nextToken++;
618 			ctxt.cmd->_flags |= 1 << (_al - 1);
619 		} while (!scumm_stricmp(_tokens[ctxt.nextToken++], "|"));
620 		ctxt.nextToken--;
621 	}
622 
623 	parseCommandFlags();
624 	addCommand();
625 }
626 
627 
DECLARE_COMMAND_PARSER(zone)628 DECLARE_COMMAND_PARSER(zone)  {
629 	debugC(7, kDebugParser, "COMMAND_PARSER(zone) ");
630 
631 	createCommand(_parser->_lookup);
632 
633 	ctxt.cmd->_zoneName = _tokens[ctxt.nextToken];
634 	ctxt.nextToken++;
635 
636 	parseCommandFlags();
637 	addCommand();
638 }
639 
640 
DECLARE_COMMAND_PARSER(location)641 DECLARE_COMMAND_PARSER(location)  {
642 	debugC(7, kDebugParser, "COMMAND_PARSER(location) ");
643 
644 	createCommand(_parser->_lookup);
645 
646 	ctxt.cmd->_string = _tokens[ctxt.nextToken];
647 	ctxt.nextToken++;
648 
649 	parseCommandFlags();
650 	addCommand();
651 }
652 
653 
DECLARE_COMMAND_PARSER(invObject)654 DECLARE_COMMAND_PARSER(invObject)  {
655 	debugC(7, kDebugParser, "COMMAND_PARSER(drop) ");
656 
657 	createCommand(_parser->_lookup);
658 
659 	ctxt.cmd->_object = 4 + _vm->_objectsNames->lookup(_tokens[ctxt.nextToken]);
660 	ctxt.nextToken++;
661 
662 	parseCommandFlags();
663 	addCommand();
664 }
665 
666 
DECLARE_COMMAND_PARSER(call)667 DECLARE_COMMAND_PARSER(call)  {
668 	debugC(7, kDebugParser, "COMMAND_PARSER(call) ");
669 
670 	createCommand(_parser->_lookup);
671 
672 	ctxt.cmd->_callable = _vm->_callableNames->lookup(_tokens[ctxt.nextToken]) - 1;
673 	ctxt.nextToken++;
674 
675 	parseCommandFlags();
676 	addCommand();
677 }
678 
679 
DECLARE_COMMAND_PARSER(simple)680 DECLARE_COMMAND_PARSER(simple)  {
681 	debugC(7, kDebugParser, "COMMAND_PARSER(simple) ");
682 
683 	createCommand(_parser->_lookup);
684 	parseCommandFlags();
685 	addCommand();
686 }
687 
688 
DECLARE_COMMAND_PARSER(move)689 DECLARE_COMMAND_PARSER(move)  {
690 	debugC(7, kDebugParser, "COMMAND_PARSER(move) ");
691 
692 	createCommand(_parser->_lookup);
693 
694 	ctxt.cmd->_move.x = atoi(_tokens[ctxt.nextToken]);
695 	ctxt.nextToken++;
696 	ctxt.cmd->_move.y = atoi(_tokens[ctxt.nextToken]);
697 	ctxt.nextToken++;
698 
699 	parseCommandFlags();
700 	addCommand();
701 }
702 
DECLARE_COMMAND_PARSER(endcommands)703 DECLARE_COMMAND_PARSER(endcommands)  {
704 	debugC(7, kDebugParser, "COMMAND_PARSER(endcommands) ");
705 
706 	_parser->popTables();
707 
708 	// temporary trick to handle dialogue commands
709 	ctxt.endcommands = true;
710 }
711 
parseCommandFlag(CommandPtr cmd,const char * flag,Table * table)712 void LocationParser_ns::parseCommandFlag(CommandPtr cmd, const char *flag, Table *table) {
713 
714 	if (!scumm_stricmp(flag, "exit")) {
715 		cmd->_flagsOn |= kFlagsExit;
716 	} else
717 	if (!scumm_stricmp(flag, "exittrap")) {
718 		cmd->_flagsOn |= kFlagsExit;
719 	} else
720 	if (!scumm_stricmp(flag, "enter")) {
721 		cmd->_flagsOn |= kFlagsEnter;
722 	} else
723 	if (!scumm_stricmp(flag, "entertrap")) {
724 		cmd->_flagsOn |= kFlagsEnter;
725 	} else
726 	if (!scumm_strnicmp(flag, "no", 2)) {
727 		byte _al = table->lookup(flag+2);
728 		if (_al != Table::notFound) {
729 			cmd->_flagsOff |= 1 << (_al - 1);
730 		} else {
731 			warning("Flag '%s' not found", flag);
732 		}
733 	} else {
734 		byte _al = table->lookup(flag);
735 		if (_al != Table::notFound) {
736 			cmd->_flagsOn |= 1 << (_al - 1);
737 		} else {
738 			warning("Flag '%s' not found", flag);
739 		}
740 	}
741 }
742 
parseCommandFlags()743 void LocationParser_ns::parseCommandFlags() {
744 
745 	int _si = ctxt.nextToken;
746 	CommandPtr cmd = ctxt.cmd;
747 
748 	if (!scumm_stricmp(_tokens[_si], "flags")) {
749 		do {
750 			_si++;
751 			parseCommandFlag(cmd, _tokens[_si], _vm->_localFlagNames);
752 			_si++;
753 		} while (!scumm_stricmp(_tokens[_si], "|"));
754 	}
755 
756 	if (!scumm_stricmp(_tokens[_si], "gflags")) {
757 		do {
758 			_si++;
759 			parseCommandFlag(cmd, _tokens[_si], _vm->_globalFlagsNames);
760 			_si++;
761 		} while (!scumm_stricmp(_tokens[_si], "|"));
762 		cmd->_flagsOn |= kFlagsGlobal;
763 	}
764 }
765 
addCommand()766 void LocationParser_ns::addCommand() {
767 	ctxt.list->push_front(ctxt.cmd);	// NOTE: command lists are written backwards in scripts
768 }
769 
createCommand(uint id)770 void LocationParser_ns::createCommand(uint id) {
771 
772 	ctxt.nextToken = 1;
773 	ctxt.cmd = CommandPtr(new Command);
774 	ctxt.cmd->_id = id;
775 	ctxt.cmd->_valid = true;
776 
777 }
778 
parseCommands(CommandList & list)779 void LocationParser_ns::parseCommands(CommandList& list) {
780 	debugC(5, kDebugParser, "parseCommands()");
781 
782 	ctxt.list = &list;
783 	ctxt.endcommands = false;
784 
785 	_parser->pushTables(&_commandParsers, _commandsNames);
786 }
787 
parseDialogue()788 Dialogue *LocationParser_ns::parseDialogue() {
789 	debugC(7, kDebugParser, "parseDialogue()");
790 
791 	Dialogue *dialogue = new Dialogue;
792 	assert(dialogue);
793 
794 	_script->readLineToken(true);
795 
796 	while (scumm_stricmp(_tokens[0], "enddialogue")) {
797 		if (!scumm_stricmp(_tokens[0], "question")) {
798 			Question *q = new Question(_tokens[1]);
799 			assert(q);
800 			parseQuestion(q);
801 			dialogue->addQuestion(q);
802 		}
803 		_script->readLineToken(true);
804 	}
805 
806 	debugC(7, kDebugParser, "parseDialogue() done");
807 
808 	return dialogue;
809 }
810 
parseQuestion(Question * q)811 void LocationParser_ns::parseQuestion(Question *q) {
812 	q->_text = parseDialogueString();
813 
814 	_script->readLineToken(true);
815 	q->_mood = atoi(_tokens[0]);
816 
817 	uint16 numAnswers = 0;
818 
819 	_script->readLineToken(true);
820 	while (scumm_stricmp(_tokens[0], "endquestion")) {	// parse answers
821 		q->_answers[numAnswers] = parseAnswer();
822 		numAnswers++;
823 	}
824 }
825 
parseAnswerBody(Answer * answer)826 void LocationParser_ns::parseAnswerBody(Answer *answer) {
827 	answer->_text = parseDialogueString();
828 
829 	_script->readLineToken(true);
830 	answer->_mood = atoi(_tokens[0]);
831 	answer->_followingName = parseDialogueString();
832 
833 	_script->readLineToken(true);
834 	if (!scumm_stricmp(_tokens[0], "commands")) {
835 
836 		parseCommands(answer->_commands);
837 		ctxt.endcommands = false;
838 		do {
839 			_script->readLineToken(true);
840 			_parser->parseStatement();
841 		} while (!ctxt.endcommands);
842 
843 		_script->readLineToken(true);
844 	}
845 }
846 
parseAnswerFlags(Answer * answer)847 void LocationParser_ns::parseAnswerFlags(Answer *answer) {
848 	if (!_tokens[1][0]) {
849 		return;
850 	}
851 
852 	Table* flagNames;
853 	uint16 token;
854 
855 	if (!scumm_stricmp(_tokens[1], "global")) {
856 		token = 2;
857 		flagNames = _vm->_globalFlagsNames;
858 		answer->_yesFlags |= kFlagsGlobal;
859 	} else {
860 		token = 1;
861 		flagNames = _vm->_localFlagNames;
862 	}
863 
864 	do {
865 
866 		if (!scumm_strnicmp(_tokens[token], "no", 2)) {
867 			byte _al = flagNames->lookup(_tokens[token]+2);
868 			answer->_noFlags |= 1 << (_al - 1);
869 		} else {
870 			byte _al = flagNames->lookup(_tokens[token]);
871 			answer->_yesFlags |= 1 << (_al - 1);
872 		}
873 
874 		token++;
875 
876 	} while (!scumm_stricmp(_tokens[token++], "|"));
877 }
878 
parseAnswer()879 Answer *LocationParser_ns::parseAnswer() {
880 	Answer *answer = new Answer;
881 	assert(answer);
882 	parseAnswerFlags(answer);
883 	parseAnswerBody(answer);
884 	return answer;
885 }
886 
887 
parseDialogueString()888 Common::String LocationParser_ns::parseDialogueString() {
889 	char buf[400];
890 	char *line = _script->readLine(buf, 400);
891 	if (line == 0) {
892 		return 0;
893 	}
894 	return Common::String(line);
895 }
896 
897 
DECLARE_LOCATION_PARSER(endlocation)898 DECLARE_LOCATION_PARSER(endlocation)  {
899 	debugC(7, kDebugParser, "LOCATION_PARSER(endlocation) ");
900 
901 	ctxt.end = true;
902 }
903 
904 
DECLARE_LOCATION_PARSER(location)905 DECLARE_LOCATION_PARSER(location)  {
906 	debugC(7, kDebugParser, "LOCATION_PARSER(location) ");
907 
908 	// The parameter for location is 'location.mask'.
909 	// If mask is not present, then it is assumed
910 	// that path & mask are encoded in the background
911 	// bitmap, otherwise a separate .msk file exists.
912 
913 	char *mask = strchr(_tokens[1], '.');
914 	if (mask) {
915 		mask[0] = '\0';
916 		mask++;
917 	}
918 
919 	strcpy(_vm->_location._name, _tokens[1]);
920 	_vm->changeBackground(_vm->_location._name, mask);
921 
922 	if (_tokens[2][0] != '\0') {
923 		_vm->_char._ani->setX(atoi(_tokens[2]));
924 		_vm->_char._ani->setY(atoi(_tokens[3]));
925 	}
926 
927 	if (_tokens[4][0] != '\0') {
928 		_vm->_char._ani->setF(atoi(_tokens[4]));
929 	}
930 }
931 
932 
DECLARE_LOCATION_PARSER(disk)933 DECLARE_LOCATION_PARSER(disk)  {
934 	debugC(7, kDebugParser, "LOCATION_PARSER(disk) ");
935 
936 	_vm->_disk->selectArchive(_tokens[1]);
937 }
938 
939 
DECLARE_LOCATION_PARSER(nodes)940 DECLARE_LOCATION_PARSER(nodes)  {
941 	debugC(7, kDebugParser, "LOCATION_PARSER(nodes) ");
942 
943 	parsePointList(_vm->_location._walkPoints);
944 }
945 
946 
DECLARE_LOCATION_PARSER(zone)947 DECLARE_LOCATION_PARSER(zone)  {
948 	debugC(7, kDebugParser, "LOCATION_PARSER(zone) ");
949 
950 	parseZone(_vm->_location._zones, _tokens[1]);
951 }
952 
953 
DECLARE_LOCATION_PARSER(animation)954 DECLARE_LOCATION_PARSER(animation)  {
955 	debugC(7, kDebugParser, "LOCATION_PARSER(animation) ");
956 
957 	parseAnimation(_vm->_location._animations, _tokens[1]);
958 }
959 
960 
DECLARE_LOCATION_PARSER(localflags)961 DECLARE_LOCATION_PARSER(localflags)  {
962 	debugC(7, kDebugParser, "LOCATION_PARSER(localflags) ");
963 
964 	int _si = 1;
965 	while (_tokens[_si][0] != '\0') {
966 		_vm->_localFlagNames->addData(_tokens[_si]);
967 		_si++;
968 	}
969 }
970 
971 
DECLARE_LOCATION_PARSER(commands)972 DECLARE_LOCATION_PARSER(commands)  {
973 	debugC(7, kDebugParser, "LOCATION_PARSER(commands) ");
974 
975 	parseCommands(_vm->_location._commands);
976 }
977 
978 
DECLARE_LOCATION_PARSER(acommands)979 DECLARE_LOCATION_PARSER(acommands)  {
980 	debugC(7, kDebugParser, "LOCATION_PARSER(acommands) ");
981 
982 	parseCommands(_vm->_location._aCommands);
983 }
984 
985 
DECLARE_LOCATION_PARSER(flags)986 DECLARE_LOCATION_PARSER(flags)  {
987 	debugC(7, kDebugParser, "LOCATION_PARSER(flags) ");
988 
989 	if ((_vm->getLocationFlags() & kFlagsVisited) == 0) {
990 		// only for 1st visit
991 		_vm->clearLocationFlags((uint32)kFlagsAll);
992 		int _si = 1;
993 
994 		do {
995 			byte _al = _vm->_localFlagNames->lookup(_tokens[_si]);
996 			_vm->setLocationFlags(1 << (_al - 1));
997 
998 			_si++;
999 			if (scumm_stricmp(_tokens[_si], "|")) break;
1000 			_si++;
1001 		} while (true);
1002 	}
1003 }
1004 
1005 
DECLARE_LOCATION_PARSER(comment)1006 DECLARE_LOCATION_PARSER(comment)  {
1007 	debugC(7, kDebugParser, "LOCATION_PARSER(comment) ");
1008 
1009 	_vm->_location._comment = parseComment();
1010 }
1011 
1012 
DECLARE_LOCATION_PARSER(endcomment)1013 DECLARE_LOCATION_PARSER(endcomment)  {
1014 	debugC(7, kDebugParser, "LOCATION_PARSER(endcomment) ");
1015 
1016 	_vm->_location._endComment = parseComment();
1017 }
1018 
1019 
DECLARE_LOCATION_PARSER(sound)1020 DECLARE_LOCATION_PARSER(sound)  {
1021 	debugC(7, kDebugParser, "LOCATION_PARSER(sound) ");
1022 
1023 	if (_vm->getPlatform() == Common::kPlatformAmiga) {
1024 		strcpy(_vm->_location._soundFile, _tokens[1]);
1025 		_vm->_location._hasSound = true;
1026 	}
1027 }
1028 
1029 
DECLARE_LOCATION_PARSER(music)1030 DECLARE_LOCATION_PARSER(music)  {
1031 	debugC(7, kDebugParser, "LOCATION_PARSER(music) ");
1032 
1033 	if (_vm->getPlatform() == Common::kPlatformAmiga)
1034 		_vm->_soundMan->execute(SC_SETMUSICFILE, _tokens[1]);
1035 }
1036 
parse(Script * script)1037 void LocationParser_ns::parse(Script *script) {
1038 	_zoneProg = 0;
1039 
1040 	ctxt.end = false;
1041 	_script = script;
1042 	ctxt.filename = 0;//filename;
1043 
1044 	_parser->reset();
1045 	_parser->pushTables(&_locationParsers, _locationStmt);
1046 	do {
1047 		_script->readLineToken(true);
1048 		_parser->parseStatement();
1049 	} while (!ctxt.end);
1050 	_parser->popTables();
1051 }
1052 
parsePointList(PointList & list)1053 void LocationParser_ns::parsePointList(PointList &list) {
1054 	debugC(5, kDebugParser, "parsePointList()");
1055 
1056 	_script->readLineToken(true);
1057 	while (scumm_stricmp(_tokens[0], "ENDNODES")) {
1058 
1059 		if (!scumm_stricmp(_tokens[0], "COORD")) {
1060 			list.push_front(Common::Point(atoi(_tokens[1]), atoi(_tokens[2])));
1061 		}
1062 
1063 		_script->readLineToken(true);
1064 	}
1065 
1066 	debugC(5, kDebugParser, "parsePointList() done");
1067 
1068 	return;
1069 }
1070 /*
1071 typedef OpcodeImpl<ProgramParser_ns> OpcodeV1;
1072 #define INSTRUCTION_PARSER(sig) OpcodeV1(this, &ProgramParser_ns::instParse_##sig)
1073 
1074 typedef OpcodeImpl<LocationParser_ns> OpcodeV2;
1075 #define ZONE_PARSER(sig)		OpcodeV2(this, &LocationParser_ns::locZoneParse_##sig)
1076 #define ANIM_PARSER(sig)		OpcodeV2(this, &LocationParser_ns::locAnimParse_##sig)
1077 #define LOCATION_PARSER(sig)	OpcodeV2(this, &LocationParser_ns::locParse_##sig)
1078 #define COMMAND_PARSER(sig)		OpcodeV2(this, &LocationParser_ns::cmdParse_##sig)
1079 
1080 #define WARNING_PARSER(sig)		OpcodeV2(this, &LocationParser_br::warning_##sig)
1081 */
1082 
1083 #define SetOpcodeTable(x) table = &x;
1084 
1085 
1086 typedef Common::Functor0Mem<void, ProgramParser_ns> OpcodeV1;
1087 #define SetOpcodeTable(x) table = &x;
1088 #define INSTRUCTION_PARSER(sig) table->push_back(new OpcodeV1(this, &ProgramParser_ns::instParse_##sig))
1089 
1090 typedef Common::Functor0Mem<void, LocationParser_ns> OpcodeV2;
1091 #define ZONE_PARSER(sig)		table->push_back(new OpcodeV2(this, &LocationParser_ns::locZoneParse_##sig))
1092 #define ANIM_PARSER(sig)		table->push_back(new OpcodeV2(this, &LocationParser_ns::locAnimParse_##sig))
1093 #define LOCATION_PARSER(sig)	table->push_back(new OpcodeV2(this, &LocationParser_ns::locParse_##sig))
1094 #define COMMAND_PARSER(sig)		table->push_back(new OpcodeV2(this, &LocationParser_ns::cmdParse_##sig))
1095 
1096 #define WARNING_PARSER(sig)		table->push_back(new OpcodeV2(this, &LocationParser_br::warning_##sig))
1097 
1098 
init()1099 void LocationParser_ns::init() {
1100 
1101 	_parser = new Parser;
1102 
1103 	_zoneFlagNames = new Table(ARRAYSIZE(_zoneFlagNamesRes_ns), _zoneFlagNamesRes_ns);
1104 	_zoneTypeNames = new Table(ARRAYSIZE(_zoneTypeNamesRes_ns), _zoneTypeNamesRes_ns);
1105 	_commandsNames = new Table(ARRAYSIZE(_commandsNamesRes_ns), _commandsNamesRes_ns);
1106 	_locationStmt = new Table(ARRAYSIZE(_locationStmtRes_ns), _locationStmtRes_ns);
1107 	_locationZoneStmt = new Table(ARRAYSIZE(_locationZoneStmtRes_ns), _locationZoneStmtRes_ns);
1108 	_locationAnimStmt = new Table(ARRAYSIZE(_locationAnimStmtRes_ns), _locationAnimStmtRes_ns);
1109 
1110 	Common::Array<const Opcode *> *table = 0;
1111 
1112 	SetOpcodeTable(_commandParsers);
1113 	WARNING_PARSER(unexpected);
1114 	COMMAND_PARSER(flags);			// set
1115 	COMMAND_PARSER(flags);			// clear
1116 	COMMAND_PARSER(zone);		// start
1117 	COMMAND_PARSER(zone);			// speak
1118 	COMMAND_PARSER(zone);			// get
1119 	COMMAND_PARSER(location);		// location
1120 	COMMAND_PARSER(zone);			// open
1121 	COMMAND_PARSER(zone);			// close
1122 	COMMAND_PARSER(zone);			// on
1123 	COMMAND_PARSER(zone);			// off
1124 	COMMAND_PARSER(call);			// call
1125 	COMMAND_PARSER(flags);			// toggle
1126 	COMMAND_PARSER(invObject);			// drop
1127 	COMMAND_PARSER(simple);			// quit
1128 	COMMAND_PARSER(move);			// move
1129 	COMMAND_PARSER(zone);		// stop
1130 	COMMAND_PARSER(endcommands);	// endcommands
1131 	COMMAND_PARSER(endcommands);		// endzone
1132 
1133 	SetOpcodeTable(_locationParsers);
1134 	WARNING_PARSER(unexpected);
1135 	LOCATION_PARSER(endlocation);
1136 	LOCATION_PARSER(location);
1137 	LOCATION_PARSER(disk);
1138 	LOCATION_PARSER(nodes);
1139 	LOCATION_PARSER(zone);
1140 	LOCATION_PARSER(animation);
1141 	LOCATION_PARSER(localflags);
1142 	LOCATION_PARSER(commands);
1143 	LOCATION_PARSER(acommands);
1144 	LOCATION_PARSER(flags);
1145 	LOCATION_PARSER(comment);
1146 	LOCATION_PARSER(endcomment);
1147 	LOCATION_PARSER(sound);
1148 	LOCATION_PARSER(music);
1149 
1150 	SetOpcodeTable(_locationZoneParsers);
1151 	WARNING_PARSER(unexpected);
1152 	ZONE_PARSER(limits);
1153 	ZONE_PARSER(moveto);
1154 	ZONE_PARSER(type);
1155 	ZONE_PARSER(commands);
1156 	ZONE_PARSER(label);
1157 	ZONE_PARSER(flags);
1158 	ZONE_PARSER(endzone);
1159 
1160 	SetOpcodeTable(_locationAnimParsers);
1161 	WARNING_PARSER(unexpected);
1162 	ANIM_PARSER(script);
1163 	ANIM_PARSER(commands);
1164 	ANIM_PARSER(type);
1165 	ANIM_PARSER(label);
1166 	ANIM_PARSER(flags);
1167 	ANIM_PARSER(file);
1168 	ANIM_PARSER(position);
1169 	ANIM_PARSER(moveto);
1170 	ANIM_PARSER(endanimation);
1171 
1172 }
1173 
init()1174 void ProgramParser_ns::init() {
1175 
1176 	_parser = new Parser;
1177 
1178 	_instructionNames = new Table(ARRAYSIZE(_instructionNamesRes_ns), _instructionNamesRes_ns);
1179 
1180 	Common::Array<const Opcode *> *table = 0;
1181 	SetOpcodeTable(_instructionParsers);
1182 	INSTRUCTION_PARSER(defLocal);	// invalid opcode -> local definition
1183 	INSTRUCTION_PARSER(animation);	// on
1184 	INSTRUCTION_PARSER(animation);	// off
1185 	INSTRUCTION_PARSER(x);
1186 	INSTRUCTION_PARSER(y);
1187 	INSTRUCTION_PARSER(z);
1188 	INSTRUCTION_PARSER(f);
1189 	INSTRUCTION_PARSER(loop);
1190 	INSTRUCTION_PARSER(null);		// endloop
1191 	INSTRUCTION_PARSER(null);		// show
1192 	INSTRUCTION_PARSER(inc);
1193 	INSTRUCTION_PARSER(inc);		// dec
1194 	INSTRUCTION_PARSER(set);
1195 	INSTRUCTION_PARSER(put);
1196 	INSTRUCTION_PARSER(call);
1197 	INSTRUCTION_PARSER(null);		// wait
1198 	INSTRUCTION_PARSER(animation);	// start
1199 	INSTRUCTION_PARSER(sound);
1200 	INSTRUCTION_PARSER(move);
1201 	INSTRUCTION_PARSER(endscript);
1202 }
1203 
1204 //
1205 //	a comment can appear both at location and Zone levels
1206 //	comments are displayed into rectangles on the screen
1207 //
parseComment()1208 Common::String LocationParser_ns::parseComment() {
1209 	Common::String comment;
1210 	char buf[400];
1211 	do {
1212 		char *line = _script->readLine(buf, 400);
1213 		if (!scumm_stricmp(line, "endtext"))
1214 			break;
1215 
1216 		if (comment.size() > 0)
1217 			comment += " ";
1218 
1219 		comment += line;
1220 	} while (true);
1221 
1222 	if (comment.size() == 0) {
1223 		return 0;
1224 	}
1225 
1226 	return comment;
1227 }
1228 
DECLARE_ZONE_PARSER(null)1229 DECLARE_ZONE_PARSER(null) {
1230 	debugC(7, kDebugParser, "ZONE_PARSER(null) ");
1231 }
1232 
1233 
DECLARE_ZONE_PARSER(endzone)1234 DECLARE_ZONE_PARSER(endzone)  {
1235 	debugC(7, kDebugParser, "ZONE_PARSER(endzone) ");
1236 
1237 	_parser->popTables();
1238 }
1239 
DECLARE_ZONE_PARSER(limits)1240 DECLARE_ZONE_PARSER(limits)  {
1241 	debugC(7, kDebugParser, "ZONE_PARSER(limits) ");
1242 	ctxt.z->setRect(atoi(_tokens[1]), atoi(_tokens[2]), atoi(_tokens[3]), atoi(_tokens[4]));
1243 }
1244 
1245 
DECLARE_ZONE_PARSER(moveto)1246 DECLARE_ZONE_PARSER(moveto)  {
1247 	debugC(7, kDebugParser, "ZONE_PARSER(moveto) ");
1248 
1249 	ctxt.z->_moveTo.x = atoi(_tokens[1]);
1250 	ctxt.z->_moveTo.y = atoi(_tokens[2]);
1251 }
1252 
buildZoneType(const char * t0,const char * t1)1253 uint32 LocationParser_ns::buildZoneType(const char *t0, const char* t1) {
1254 	uint16 it = 0;
1255 	if (t1[0] != '\0') {
1256 		it = 4 + _vm->_objectsNames->lookup(t1);
1257 	}
1258 	uint16 zt = _zoneTypeNames->lookup(t0);
1259 	return PACK_ZONETYPE(zt, it);
1260 }
1261 
1262 
DECLARE_ZONE_PARSER(type)1263 DECLARE_ZONE_PARSER(type)  {
1264 	debugC(7, kDebugParser, "ZONE_PARSER(type) ");
1265 
1266 	ctxt.z->_type = buildZoneType(_tokens[1], _tokens[2]);
1267 	if (ACTIONTYPE(ctxt.z) != 0) {
1268 		parseZoneTypeBlock(ctxt.z);
1269 	}
1270 
1271 	_parser->popTables();
1272 }
1273 
1274 
DECLARE_ZONE_PARSER(commands)1275 DECLARE_ZONE_PARSER(commands)  {
1276 	debugC(7, kDebugParser, "ZONE_PARSER(commands) ");
1277 
1278 	 parseCommands(ctxt.z->_commands);
1279 }
1280 
1281 
DECLARE_ZONE_PARSER(label)1282 DECLARE_ZONE_PARSER(label)  {
1283 	debugC(7, kDebugParser, "ZONE_PARSER(label) ");
1284 
1285 //			debug("label: %s", _tokens[1]);
1286 	ctxt.z->_label = _vm->_gfx->renderFloatingLabel(_vm->_labelFont, _tokens[1]);
1287 	ctxt.z->_flags &= ~kFlagsNoName;
1288 }
1289 
1290 
DECLARE_ZONE_PARSER(flags)1291 DECLARE_ZONE_PARSER(flags)  {
1292 	debugC(7, kDebugParser, "ZONE_PARSER(flags) ");
1293 
1294 	uint16 _si = 1;
1295 
1296 	do {
1297 		char _al = _zoneFlagNames->lookup(_tokens[_si]);
1298 		_si++;
1299 		ctxt.z->_flags |= 1 << (_al - 1);
1300 	} while (!scumm_stricmp(_tokens[_si++], "|"));
1301 }
1302 
parseZone(ZoneList & list,char * name)1303 void LocationParser_ns::parseZone(ZoneList &list, char *name) {
1304 	debugC(5, kDebugParser, "parseZone(name: %s)", name);
1305 
1306 	if (_vm->_location.findZone(name)) {
1307 		_zoneProg++;
1308 		_script->skip("endzone");
1309 		return;
1310 	}
1311 
1312 	ZonePtr z(new Zone);
1313 	_zoneProg++;
1314 
1315 	Common::strlcpy(z->_name, name, ZONENAME_LENGTH);
1316 
1317 	ctxt.z = z;
1318 
1319 	list.push_front(z);
1320 
1321 	_parser->pushTables(&_locationZoneParsers, _locationZoneStmt);
1322 
1323 	return;
1324 }
1325 
1326 
1327 
1328 
parseGetData(ZonePtr z)1329 void LocationParser_ns::parseGetData(ZonePtr z) {
1330 	TypeData *data = &z->u;
1331 	if (!scumm_stricmp(_tokens[0], "file")) {
1332 		GfxObj *obj = _vm->_gfx->loadGet(_tokens[1]);
1333 		obj->frame = 0;
1334 		obj->x = z->getX();
1335 		obj->y = z->getY();
1336 		obj->_prog = _zoneProg;
1337 
1338 		// WORKAROUND for script bug #2969913
1339 		// The katana object has the same default z index (kGfxObjGetZ or -100)
1340 		// as the cripta object (the safe) - a script bug.
1341 		// Game scripts do not set an explicit z for the katana (as it isn't an
1342 		// animation), but rather rely on the draw order to draw it over the
1343 		// safe. In this particular case, the safe is added to the scene after
1344 		// the katana, thus it is drawn over the katana. We explicitly set the
1345 		// z index of the katana to be higher than the safe, so that the katana
1346 		// is drawn correctly over it.
1347 		// This is a regression from the graphics rewrite (commits be2c5d3,
1348 		// 3c2c16c and 44906f5).
1349 		if (!scumm_stricmp(obj->getName(), "katana"))
1350 			obj->z = 0;
1351 
1352 		bool visible = (z->_flags & kFlagsRemove) == 0;
1353 		_vm->_gfx->showGfxObj(obj, visible);
1354 		data->_gfxobj = obj;
1355 	} else
1356 	if (!scumm_stricmp(_tokens[0], "icon")) {
1357 		data->_getIcon = 4 + _vm->_objectsNames->lookup(_tokens[1]);
1358 	}
1359 }
1360 
parseExamineData(ZonePtr z)1361 void LocationParser_ns::parseExamineData(ZonePtr z) {
1362 	TypeData *data = &z->u;
1363 	if (!scumm_stricmp(_tokens[0], "file")) {
1364 		data->_filename = _tokens[1];
1365 	} else
1366 	if (!scumm_stricmp(_tokens[0], "desc")) {
1367 		data->_examineText = parseComment();
1368 	}
1369 }
1370 
parseDoorData(ZonePtr z)1371 void LocationParser_ns::parseDoorData(ZonePtr z) {
1372 	TypeData *data = &z->u;
1373 	if (!scumm_stricmp(_tokens[0], "slidetext")) {
1374 		_vm->_location._slideText[0] = _tokens[1];
1375 		_vm->_location._slideText[1] = _tokens[2];
1376 	} else
1377 	if (!scumm_stricmp(_tokens[0], "location")) {
1378 		data->_doorLocation = _tokens[1];
1379 	} else
1380 	if (!scumm_stricmp(_tokens[0], "file")) {
1381 		GfxObj *obj = _vm->_gfx->loadDoor(_tokens[1]);
1382 		obj->frame = z->_flags & kFlagsClosed ? 0 : 1;
1383 		obj->x = z->getX();
1384 		obj->y = z->getY();
1385 		_vm->_gfx->showGfxObj(obj, true);
1386 		data->_gfxobj = obj;
1387 	} else
1388 	if (!scumm_stricmp(_tokens[0],	"startpos")) {
1389 		data->_doorStartPos.x = atoi(_tokens[1]);
1390 		data->_doorStartPos.y = atoi(_tokens[2]);
1391 		data->_doorStartFrame = atoi(_tokens[3]);
1392 	}
1393 }
1394 
parseMergeData(ZonePtr z)1395 void LocationParser_ns::parseMergeData(ZonePtr z) {
1396 	TypeData *data = &z->u;
1397 	if (!scumm_stricmp(_tokens[0], "obj1")) {
1398 		data->_mergeObj1 = 4 + _vm->_objectsNames->lookup(_tokens[1]);
1399 	} else
1400 	if (!scumm_stricmp(_tokens[0], "obj2")) {
1401 		data->_mergeObj2 = 4 + _vm->_objectsNames->lookup(_tokens[1]);
1402 	} else
1403 	if (!scumm_stricmp(_tokens[0], "newobj")) {
1404 		data->_mergeObj3 = 4 + _vm->_objectsNames->lookup(_tokens[1]);
1405 	}
1406 }
1407 
parseHearData(ZonePtr z)1408 void LocationParser_ns::parseHearData(ZonePtr z) {
1409 	TypeData *data = &z->u;
1410 	if (!scumm_stricmp(_tokens[0], "sound")) {
1411 		data->_filename = _tokens[1];
1412 		data->_hearChannel = atoi(_tokens[2]);
1413 	} else
1414 	if (!scumm_stricmp(_tokens[0], "freq")) {
1415 		data->_hearFreq = atoi(_tokens[1]);
1416 	}
1417 }
1418 
parseSpeakData(ZonePtr z)1419 void LocationParser_ns::parseSpeakData(ZonePtr z) {
1420 	TypeData *data = &z->u;
1421 	if (!scumm_stricmp(_tokens[0], "file")) {
1422 		data->_filename = _tokens[1];
1423 	} else
1424 	if (!scumm_stricmp(_tokens[0], "Dialogue")) {
1425 		data->_speakDialogue = parseDialogue();
1426 	}
1427 }
1428 
parseNoneData(ZonePtr z)1429 void LocationParser_ns::parseNoneData(ZonePtr z) {
1430 	// "None" zones should have no content, but some
1431 	// inconsistently define their command list after
1432 	// the TYPE marker. This routine catches these
1433 	// command lists that would be lost otherwise.
1434 	if (!scumm_stricmp(_tokens[0], "commands")) {
1435 		parseCommands(z->_commands);
1436 		ctxt.endcommands = false;
1437 		do {
1438 			_script->readLineToken(true);
1439 			_parser->parseStatement();
1440 		} while (!ctxt.endcommands);
1441 
1442 		// no need to parse one more line here, as
1443 		// it is done by the caller
1444 	}
1445 }
1446 
1447 typedef void (LocationParser_ns::*ZoneTypeParser)(ZonePtr);
1448 static ZoneTypeParser parsers[] = {
1449 	0,	// no type
1450 	&LocationParser_ns::parseExamineData,
1451 	&LocationParser_ns::parseDoorData,
1452 	&LocationParser_ns::parseGetData,
1453 	&LocationParser_ns::parseMergeData,
1454 	0,	// taste
1455 	&LocationParser_ns::parseHearData,
1456 	0,	// feel
1457 	&LocationParser_ns::parseSpeakData,
1458 	&LocationParser_ns::parseNoneData,
1459 	0,	// trap
1460 	0,	// you
1461 	0	// command
1462 };
1463 
parseZoneTypeBlock(ZonePtr z)1464 void LocationParser_ns::parseZoneTypeBlock(ZonePtr z) {
1465 	debugC(7, kDebugParser, "parseZoneTypeBlock(name: %s, type: %x)", z->_name, z->_type);
1466 
1467 	ZoneTypeParser p = parsers[ACTIONTYPE(z)];
1468 	do {
1469 		if (p) {
1470 			(this->*p)(z);
1471 		}
1472 		_script->readLineToken(true);
1473 	} while (scumm_stricmp(_tokens[0], "endzone") && scumm_stricmp(_tokens[0], "endanimation"));
1474 	debugC(7, kDebugParser, "parseZoneTypeBlock() done");
1475 }
1476 
1477 
1478 } // namespace Parallaction
1479