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