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