1 /*
2 * Copyright 2011-2013 Arx Libertatis Team (see the AUTHORS file)
3 *
4 * This file is part of Arx Libertatis.
5 *
6 * Arx Libertatis is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Arx Libertatis is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Arx Libertatis. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "script/ScriptUtils.h"
21
22 #include <set>
23
24 #include "game/Entity.h"
25 #include "graphics/data/Mesh.h"
26
27 using std::string;
28
29 namespace script {
30
isWhitespace(char c)31 static inline bool isWhitespace(char c) {
32 return (((unsigned char)c) <= 32 || c == '(' || c == ')');
33 }
34
loadUnlocalized(const std::string & str)35 string loadUnlocalized(const std::string & str) {
36
37 // if the section name has the qualifying brackets "[]", cut them off
38 if(!str.empty() && str[0] == '[' && str[str.length() - 1] == ']') {
39 return str.substr(1, str.length() - 2);
40 }
41
42 return str;
43 }
44
Context(EERIE_SCRIPT * script,size_t pos,Entity * entity,ScriptMessage msg)45 Context::Context(EERIE_SCRIPT * script, size_t pos, Entity * entity, ScriptMessage msg)
46 : script(script), pos(pos), entity(entity), message(msg) { }
47
getStringVar(const string & var) const48 string Context::getStringVar(const string & var) const {
49 return GetVarValueInterpretedAsText(var, getMaster(), entity);
50 }
51
52 #define ScriptParserWarning Logger(__FILE__,__LINE__, isSuppressed(*this, "?") ? Logger::Debug : Logger::Warning) << ScriptContextPrefix(*this) << ": "
53
getCommand(bool skipNewlines)54 std::string Context::getCommand(bool skipNewlines) {
55
56 const char * esdat = script->data;
57
58 skipWhitespace(skipNewlines);
59
60 string word;
61
62 // now take chars until it finds a space or unused char
63 for(; pos != script->size && !isWhitespace(esdat[pos]); pos++) {
64
65 char c = esdat[pos];
66 if(c == '"') {
67 ScriptParserWarning << "unexpected '\"' in command name";
68 } else if(c == '~') {
69 ScriptParserWarning << "unexpected '~' in command name";
70 } else if(c == '\n') {
71 break;
72 } else if(c == '/' && pos + 1 != script->size && esdat[pos + 1] == '/') {
73 pos = std::find(esdat + pos + 2, esdat + script->size, '\n') - esdat;
74 if(!word.empty()) {
75 break;
76 }
77 skipWhitespace(skipNewlines), pos--;
78 } else {
79 word.push_back(c);
80 }
81 }
82
83 return word;
84 }
85
getWord()86 string Context::getWord() {
87
88 skipWhitespace();
89
90 if(pos >= script->size) {
91 return string();
92 }
93
94 const char * esdat = script->data;
95
96 bool tilde = false; // number of tildes
97
98 string word;
99 string var;
100
101 if(pos != script->size && esdat[pos] == '"') {
102
103 for(pos++; pos != script->size && esdat[pos] != '"'; pos++) {
104 if(esdat[pos] == '\n') {
105 if(tilde) {
106 ScriptParserWarning << "unmatched '\"' before end of line";
107 }
108 return word;
109 } else if(esdat[pos] == '~') {
110 if(tilde) {
111 word += GetVarValueInterpretedAsText(var, getMaster(), getEntity());
112 var.clear();
113 }
114 tilde = !tilde;
115 } else if(tilde) {
116 var.push_back(esdat[pos]);
117 } else {
118 word.push_back(esdat[pos]);
119 }
120 }
121
122 if(pos != script->size) {
123 pos++;
124 } else {
125 ScriptParserWarning << "unmatched '\"'";
126 }
127
128 } else {
129
130 // now take chars until it finds a space or unused char
131 for(; pos != script->size && !isWhitespace(esdat[pos]); pos++) {
132
133 if(esdat[pos] == '"') {
134 ScriptParserWarning << "unexpected '\"' inside token";
135 } else if(esdat[pos] == '~') {
136 if(tilde) {
137 word += GetVarValueInterpretedAsText(var, getMaster(), getEntity());
138 var.clear();
139 }
140 tilde = !tilde;
141 } else if(tilde) {
142 var.push_back(esdat[pos]);
143 } else if(esdat[pos] == '/' && pos + 1 != script->size && esdat[pos + 1] == '/') {
144 pos = std::find(esdat + pos + 2, esdat + script->size, '\n') - esdat;
145 break;
146 } else {
147 word.push_back(esdat[pos]);
148 }
149
150 }
151
152 }
153
154 if(tilde) {
155 ScriptParserWarning << "unmatched '~'";
156 }
157
158 return word;
159 }
160
skipWord()161 void Context::skipWord() {
162
163 skipWhitespace();
164
165 const char * esdat = script->data;
166
167 if(pos != script->size && esdat[pos] == '"') {
168
169 for(pos++; pos != script->size && esdat[pos] != '"'; pos++) {
170 if(esdat[pos] == '\n') {
171 ScriptParserWarning << "missing '\"' before end of line";
172 return;
173 }
174 }
175
176 if(pos != script->size) {
177 pos++;
178 } else {
179 ScriptParserWarning << "unmatched '\"'";
180 }
181
182 } else {
183
184 // now take chars until it finds a space or unused char
185 for(; pos != script->size && !isWhitespace(esdat[pos]); pos++) {
186 if(esdat[pos] == '"') {
187 ScriptParserWarning << "unexpected '\"' inside token";
188 } else if(esdat[pos] == '/' && pos + 1 != script->size && esdat[pos + 1] == '/') {
189 pos = std::find(esdat + pos + 2, esdat + script->size, '\n') - esdat;
190 break;
191 }
192 }
193
194 }
195 }
196
skipWhitespace(bool skipNewlines)197 void Context::skipWhitespace(bool skipNewlines) {
198
199 const char * esdat = script->data;
200
201 // First ignores spaces & unused chars
202 for(; pos != script->size && isWhitespace(esdat[pos]); pos++) {
203 if(!skipNewlines && esdat[pos] == '\n') {
204 return;
205 }
206 }
207 }
208
getFlags()209 string Context::getFlags() {
210
211 skipWhitespace();
212
213 if(pos < script->size && script->data[pos] == '-') {
214 return getWord();
215 }
216
217 return string();
218 }
219
getFloat()220 float Context::getFloat() {
221 return getFloatVar(getWord());
222 }
223
getBool()224 bool Context::getBool() {
225
226 string word = getWord();
227
228 return (word == "on" || word == "yes");
229 }
230
getFloatVar(const std::string & name) const231 float Context::getFloatVar(const std::string & name) const {
232 return GetVarValueInterpretedAsFloat(name, getMaster(), entity);
233 }
234
skipCommand()235 size_t Context::skipCommand() {
236
237 skipWhitespace();
238
239 const char * esdat = script->data;
240
241 if(pos == script->size || esdat[pos] == '\n') {
242 return (size_t)-1;
243 }
244
245 size_t oldpos = pos;
246
247 if(esdat[pos] == '/' && pos + 1 != script->size && esdat[pos + 1] == '/') {
248 oldpos = (size_t)-1;
249 pos += 2;
250 }
251
252 pos = std::find(esdat + pos, esdat + script->size, '\n') - esdat;
253
254 return oldpos;
255 }
256
jumpToLabel(const string & target,bool substack)257 bool Context::jumpToLabel(const string & target, bool substack) {
258
259 if(substack) {
260 stack.push_back(pos);
261 }
262
263 long targetpos = FindScriptPos(script, ">>" + target);
264 if(targetpos == -1) {
265 return false;
266 }
267
268 pos = targetpos + target.length() + 2;
269 return true;
270 }
271
returnToCaller()272 bool Context::returnToCaller() {
273
274 if(stack.empty()) {
275 return false;
276 }
277
278 pos = stack.back();
279 stack.pop_back();
280 return true;
281 }
282
skipStatement()283 void Context::skipStatement() {
284
285 string word = getCommand();
286 if(pos == script->size) {
287 ScriptParserWarning << "missing statement before end of script";
288 return;
289 }
290
291 if(word == "{") {
292 long brackets = 1;
293 while(brackets > 0) {
294
295 if(script->data[pos] == '\n') {
296 pos++;
297 }
298 word = getWord(); // TODO should not evaluate ~var~
299 if(pos == script->size) {
300 ScriptParserWarning << "missing '}' before end of script";
301 return;
302 }
303
304 if(word == "{") {
305 brackets++;
306 } else if(word == "}") {
307 brackets--;
308 }
309 }
310 } else {
311 skipCommand();
312 }
313
314 skipWhitespace(true);
315 size_t oldpos = pos;
316 word = getCommand();
317 if(word != "else") {
318 pos = oldpos;
319 }
320 }
321
322 namespace {
323
324 typedef std::set<string> SuppressedCommands;
325 typedef std::map<string, SuppressedCommands> SuppressionsForFile;
326 typedef std::map<size_t, SuppressionsForFile> SuppressionsForPos;
327
328 size_t suppressionCount = 0;
329 SuppressionsForPos suppressions;
330 SuppressionsForPos blockSuppressions;
331
suppress(const string & script,size_t pos,const string & command)332 void suppress(const string & script, size_t pos, const string & command) {
333 suppressionCount++;
334 suppressions[pos][script].insert(command);
335 }
336
suppressBlockEnd(const string & script,size_t pos,const string & command)337 void suppressBlockEnd(const string & script, size_t pos, const string & command) {
338 suppressionCount++;
339 blockSuppressions[pos][script].insert(command);
340 }
341
contains(const SuppressionsForPos & list,const Context & context,const string & command)342 bool contains(const SuppressionsForPos & list, const Context & context, const string & command) {
343
344 SuppressionsForPos::const_iterator i0 = list.find(context.getPosition());
345 if(i0 == list.end()) {
346 return false;
347 }
348
349 SuppressionsForFile::const_iterator i1 = i0->second.find(context.getEntity() ? ((context.getScript() == &context.getEntity()->script) ? context.getEntity()->short_name() : context.getEntity()->long_name()) : "unknown");
350 if(i1 == i0->second.end()) {
351 return false;
352 }
353
354 return (i1->second.find(command) != i1->second.end());
355 }
356
357 }
358
initSuppressions()359 size_t initSuppressions() {
360
361 suppressBlockEnd("camera_0027", 1140, "}"); // '}' should be commented out!
362
363 suppressBlockEnd("black_thing_0002", 1075, "on"); // missing '}' and accept/refuse
364
365 suppressBlockEnd("chest_metal_0103", 626, "on"); // missing '}' and accept/refuse
366
367 suppressBlockEnd("chest_metal_0104", 667, "on"); // missing '}' and accept/refuse
368
369 suppressBlockEnd("goblin_base_0021", 617, "on"); // missing '}'
370
371 suppressBlockEnd("goblin_base_0031", 974, "on"); // missing '}'
372
373 suppressBlockEnd("lever_0028", 402, "}"); // extranous '}'
374
375 // TODO(broken-scripts)
376 // TODO move to external file
377
378 suppress("akbaa_phase2", 13884, "play"); // missing sound files 'akbaa_strike1' to 'akbaa_strike3', should be 'akbaa_strike'
379 suppress("akbaa_phase2", 19998, "play"); // sound number is sonetimes too high; missing 'akbaa_hail1', should be 'akbaa_hail'
380 suppress("akbaa_phase2", 18549, "playanim"); // animation 'grunt' not loaded
381
382 suppress("akbaa_tentacle", 2432, "on"); // unknown command 'on' (bad newline!)
383
384 suppress("axe_2handed", 26, "settwohanded"); // obsolete command
385
386 suppress("black_thing", 3703, "play"); // variable is never set
387
388 suppress("camera_0072", 269, "goto"); // missing label 'dialogue7_2'
389
390 suppress("camera_0076", 2139, ""); // missing accept/refuse/return/goto/gosub before end of script
391
392 suppress("black_thing_0003", 4360, "setevent"); // unsupported event: "eat"
393 suppress("black_thing_0003", 4388, "setevent"); // unsupported event: "no_more_eat"
394 suppress("black_thing_0003", 4411, "setevent"); // unsupported event: "no_eat"
395 suppress("black_thing_0003", 4709, "behvaior"); // unknown command 'behvaior', should be 'behavior'
396
397 suppress("chest_metal_0011", 78, "inventory add"); // missing object: "graph/obj3d/interactive/items/magic/dragon_bone_powder/dragon_bone_powder.teo" (should be 'powder_dragon_bone/dragon_bone_powder'?)
398
399 suppress("chest_metal_0012", 389, "inventory add"); // missing object: "graph/obj3d/interactive/items/magic/dragon_bone_powder/dragon_bone_powder.teo" (should be 'powder_dragon_bone/dragon_bone_powder'?)
400
401 suppress("chest_metal_0020", 54, "inventory add"); // missing object: "graph/obj3d/interactive/items/provisions/candle/candle.teo" (should be 'candle/candel'?)
402 suppress("chest_metal_0020", 99, "inventory add"); // missing object: "graph/obj3d/interactive/items/provisions/candle/candle.teo" (should be 'candle/candel'?)
403 suppress("chest_metal_0020", 149, "inventory add"); // missing object: "graph/obj3d/interactive/items/magic/ring_darkaa/ring_darkaa.teo" (should be 'ring_daarka/ring_daarka'?)
404
405 suppress("chest_metal_0029", 224, "inventory add"); // missing object: "graph/obj3d/interactive/items/provisions/candle/candle.teo" (should be 'candle/candel'?)
406 suppress("chest_metal_0029", 317, "inventory add"); // missing object: "graph/obj3d/interactive/items/provisions/candle/candle.teo" (should be 'candle/candel'?)
407 suppress("chest_metal_0029", 461, "inventory add"); // missing object: "graph/obj3d/interactive/items/provisions/candle/candle.teo" (should be 'candle/candel'?)
408 suppress("chest_metal_0029", 557, "inventory add"); // missing object: "graph/obj3d/interactive/items/provisions/candle/candle.teo" (should be 'candle/candel'?)
409 suppress("chest_metal_0029", 650, "inventory add"); // missing object: "graph/obj3d/interactive/items/provisions/candle/candle.teo" (should be 'candle/candel'?)
410
411 suppress("chest_metal_0045", 242, "inventory addfromscene"); // bad target ident: "magic\\potion_life\\potion_life"
412
413 suppress("chest_metal_0095", 143, "inventory add"); // missing object: "graph/obj3d/interactive/items/armor/legging_leatherac/legging_leatherac.teo" (should be 'legging_leather_ac'?)
414
415 suppress("chest_metal_0100", 629, "inventory add"); // missing object: "graph/obj3d/interactive/items/magic/dragon_bone_powder/dragon_bone_powder.teo" (should be 'powder_dragon_bone/dragon_bone_powder'?)
416 suppress("chest_metal_0100", 693, "inventory add"); // missing object: "graph/obj3d/interactive/items/magic/dragon_bone_powder/dragon_bone_powder.teo" (should be 'powder_dragon_bone/dragon_bone_powder'?)
417
418 suppress("chicken_base", 2037, "gosub"); // missing label 'save_behavior'
419 suppress("chicken_base", 2410, "}"); // missing accept/refuse before end of event block
420
421 suppress("corpse_0003", 399, "inventory addfromscene"); // bad target ident: "magic\\potion_life\\potion_life" (should be 'inventory add'?)
422
423 suppress("corpse_0006", 172, "inventory add"); // missing object: "graph/obj3d/interactive/items/armor/helmet_leather/helmet_leather.teo"
424
425 suppress("corpse_0084", 274, "inventory add"); // missing object: "graph/obj3d/interactive/items/weapons/chest_leather_ac/chest_leather_ac.teo"
426
427 suppress("demon", 3571, "loadanim"); // missing animation 'demon_fight_left_start'
428 suppress("demon", 3634, "loadanim"); // missing animation 'demon_fight_left_cycle'
429 suppress("demon", 3698, "loadanim"); // missing animation 'demon_fight_left_strike'
430 suppress("demon", 3762, "loadanim"); // missing animation 'demon_fight_right_start'
431 suppress("demon", 3826, "loadanim"); // missing animation 'demon_fight_right_cycle'
432 suppress("demon", 3891, "loadanim"); // missing animation 'demon_fight_right_strike'
433 suppress("demon", 18479, "play"); // sound number is sometimes too high
434
435 suppress("diamond", 139, "play"); // unknown flag -e (ignored) note: fix_inter/diamond_inwall/diamond.asl!
436
437 suppress("dog", 19669, "play"); // sound number is sometimes too high
438
439 suppress("dog_0011", 31, "playanim"); // animation 'action2' not loaded
440
441 suppress("door_orbiplanax_chest", 371, "if"); // unknown operator '==1' (should be '== 1'), interpreted as constant true
442
443 suppress("dragon_ice", 9029, "setevent"); // unsupported event 'agression', should be 'aggression'
444
445 suppress("dragon_ice_0001", 93, "loadanim"); // missing animation: "dragon_talk_head"
446 suppress("dragon_ice_0001", 3687, "playanim"); // animation 'action9' not loaded
447
448 suppress("dragon's_lair_ice_wall", 41, "satangular"); // unknown command 'satangular', should be setangular
449
450 suppress("dwarf_little_crusher_0001", 204, "?"); // 'playanim' only takes one parameter
451 suppress("dwarf_little_crusher_0001", 228, "?"); // 'playanim' only takes one parameter
452
453 suppress("dwarf_little_crusher_0002", 201, "?"); // 'playanim' only takes one parameter
454 suppress("dwarf_little_crusher_0002", 225, "?"); // 'playanim' only takes one parameter
455
456 suppress("dwarf_little_crusher_0003", 113, "?"); // 'playanim' only takes one parameter
457 suppress("dwarf_little_crusher_0003", 137, "?"); // 'playanim' only takes one parameter
458
459 suppress("emerald_inwall", 136, "play"); // unknown flag -e (ignored)
460
461 suppress("fake_golden_snake", 185, "setinternalname"); // obsolete command (ignored)
462
463 suppress("flour_bag", 41, "collison"); // unknown command 'collison', should be collision
464
465 suppress("gem_inwall", 114, "play"); // unknown flag -e (ignored)
466
467 suppress("goblin_base", 30010, "goto"); // missing label "main_alert"
468
469 suppress("goblin_base_0009", 1455, "setevent"); // unsupported event: combine
470
471 suppress("goblin_base_0034", 771, "detach"); // object mug_full_0003 already destroyed
472
473 suppress("goblin_base_0041", 3063, "if"); // unknown operator '==1' (should be '== 1'), interpreted as constant true
474
475 suppress("goblin_base_0048", 632, "setevent"); // unsupported event: combine
476
477 suppress("goblin_base_0046", 2924, "if"); // unknown operator '=>' (should be '>='?), interpreted as constant true
478
479 suppress("gold_chunk_inwall", 144, "play"); // unknown flag -e (ignored)
480
481 suppress("golden_snake", 156, "setinternalname"); // obsolete command
482
483 suppress("hammer_club", 66, "settwohanded"); // obsolete command
484
485 suppress("human_base", 5872, "loadanim"); // bad animation id: 'bae_ready', should be 'bare_ready'
486 suppress("human_base", 13711, "loadanim"); // missing animation "child_get_hit", should be "child_hit"?
487 suppress("human_base", 13751, "loadanim"); // missing animation "child_get_hit", should be "child_hit"?
488 suppress("human_base", 39089, "teleport"); // variable dying_marker not set
489 suppress("human_base", 45586, "goto"); // missing label "main_alert"
490
491 suppress("human_base_0006", 83, "playanim"); // animation 'wait' not loaded yet
492
493 suppress("human_base_0012", 1519, "goto"); // missing label 'stop'
494
495 suppress("human_base_0016", 7142, "setcontrolledzone"); // unknown zone 'calpale_beer', should be 'calpal_beer'?
496 suppress("human_base_0016", 1270, "inventory addfromscene"); // unknown target 'key_calpale_0003' already taken by player?
497
498 suppress("human_base_0022", 10108, "behaviormoveto"); // unknown command 'behaviormoveto', should be 'behavior move_to'
499
500 suppress("human_base_0025", 732, "detach"); // object mug_full_0002 already destroyed
501
502 suppress("human_base_0041", 4279, "if"); // missing space between oprateor '==' and argument
503
504 suppress("human_base_0051", 5396, "/"); // unknown command, should be '//' instead of '/ /'
505
506 suppress("human_base_0051", 6083, "set"); // bad variable name: "waiting"
507
508 suppress("human_base_0046", 679, "goto"); // missing label 'next_step02', should be 'next_step01'?
509
510 suppress("human_base_0079", 239, "inventory add"); // missing object: "graph/obj3d/interactive/items/armor/chest_leatherac/chest_leatherac.teo" (should be 'chest_leather_ac'?)
511 suppress("human_base_0079", 303, "inventory add"); // missing object: "graph/obj3d/interactive/items/armor/leggings_leatherac/leggings_leatherac.teo" (should be 'legging_leather_ac'?)
512
513 suppress("human_base_0082", 24114, "on"); // unknown command 'on' (bad linebreak!)
514 suppress("human_base_0082", 24141, "hide"); // unknown command 'hide' (bad linebreak!)
515
516 suppress("human_base_0085", 426, "loadanim"); // missing animation 'human_noraml_sit_out', should be 'human_normal_sit_out'?
517
518 suppress("human_base_0086", 189, "if"); // unknown operator '==1' (should be '== 1')
519 suppress("human_base_0086", 787, "loadanim"); // missing animation 'human_noraml_sit_out', should be 'human_normal_sit_out'?
520
521 suppress("human_base_0095", 722, "setcontrolledzone"); // unknown zone 'maria_shop'
522
523 suppress("human_base_0099", 997, "errata"); // unknown command 'errata', should be 'goto errata'
524
525 suppress("human_base_0114", 6541, "teleport"); // unknown target 'marker_0327'
526
527 suppress("human_base_0118", 101, "collisions"); // unknown command 'collisions', should be 'collision'
528
529 suppress("human_base_0119", 179, "collisions"); // unknown command 'collisions', should be 'collision'
530
531 suppress("human_base_0120", 101, "collisions"); // unknown command 'collisions', should be 'collision'
532
533 suppress("human_base_0121", 135, "collisions"); // unknown command 'collisions', should be 'collision'
534
535 suppress("human_base_0122", 350, "collisions"); // unknown command 'collisions', should be 'collision'
536
537 suppress("human_base_0135", 939, "detroy"); // unknown command 'detroy', should be 'destroy'
538
539 suppress("human_base_0136", 995, "detroy"); // unknown command 'detroy', should be 'destroy'
540
541 suppress("human_base_0137", 992, "detroy"); // unknown command 'detroy', should be 'destroy'
542
543 suppress("human_base_0138", 2439, "setcontrolledzone"); // unknown zone 'shani_flee'
544
545 suppress("human_base_0174", 136, "play"); // missing sound file 'loop_crypt1l', should be 'ambiance/loop_crypt1l'
546
547 suppress("jail_wood_grid", 152, "set"); // bad variable name: "material"
548
549 suppress("lamp_goblin2_0003", 737, "no"); // unknown command 'no' should be 'nop'?
550
551 suppress("lava_event01_0004", 277, "action1"); // unknown command 'action1' (missing space in '200 playanim')
552
553 suppress("light_door", 422, "set"); // bad variable name: "durability"
554
555 suppress("light_door_0019", 105, "setspeakpitch"); // setspeakpitch only applies to NPCs
556
557 suppress("light_door_0020", 230, "setspeakpitch"); // setspeakpitch only applies to NPCs
558
559 suppress("light_door_0021", 234, "setspeakpitch"); // setspeakpitch only applies to NPCs
560
561 suppress("light_door_0029", 88, "setspeakpitch"); // setspeakpitch only applies to NPCs
562
563 suppress("light_door_0030", 162, "setevent"); // unsupported event: "npc_open"
564 suppress("light_door_0030", 488, "setevent"); // unsupported event: "npc_open"
565 suppress("light_door_0030", 717, "setevent"); // unsupported event: "npc_open"
566
567 suppress("light_door_0100", 69, "setspeakpitch"); // setspeakpitch only applies to NPCs
568
569 suppress("light_door_0102", 88, "setspeakpitch"); // setspeakpitch only applies to NPCs
570
571 suppress("light_door_0106", 110, "setcontrolledzone"); // unknown zone 'city_entrance'
572
573 suppress("light_door_0121", 88, "setspeakpitch"); // setspeakpitch only applies to NPCs
574
575 suppress("lockpicks", 462, "play"); // missing sound file 'brokenweapon.wav', should be 'broken_weapon'
576
577 suppress("long_sword_recovery", 591, "setequip"); // unknown flag '-s' (ignored)
578
579 suppress("marker_0025", 288, "sendevent"); // unknown zone 'cooking' (should be 'cook_gary'?)
580
581 suppress("marker_0247", 44, "setcontrolledzone"); // unknown zone 'level3_zone4'
582
583 suppress("marker_0811", 536, "worldface"); // unknown command 'worldface', should be 'worldfade'
584
585 suppress("metal_chunk_inwall", 143, "play"); // unknown flag -e (ignored)
586
587 suppress("metal_grid_0008", 338, "}"); // missing accept/refuse before end of event block
588
589 suppress("mithril_chunk_inwall", 144, "play"); // unknown flag -e (ignored)
590
591 suppress("morning_glory", 971, "playanim"); // animation 'action1' not loaded
592
593 suppress("orb_crypt", 76, "setsteal"); // setsteal only applies to items
594
595 suppress("pig", 2409, "}"); // missing accept/refuse before end of event block
596
597 suppress("player", 7725, "loadanim"); // bad animation id: "cast_hold"
598 suppress("player", 8463, "loadanim"); // bad animation id: "lean_left_cycle"
599 suppress("player", 8531, "loadanim"); // bad animation id: "lean_left_out"
600 suppress("player", 8666, "loadanim"); // bad animation id: "lean_right_cycle"
601 suppress("player", 8733, "loadanim"); // bad animation id: "lean_right_out"
602 suppress("player", 9284, "loadanim"); // missing animation "human_death_cool"
603 suppress("player", 9558, "loadanim"); // missing animation "human_talk_happyneutral_headonly"
604 suppress("player", 18044, "play"); // missing sound file 'bell', should be 'arx_bell'
605
606 suppress("porticullis_0039", 806, "setevent"); // unsupported event: "custom"
607
608 suppress("porticullis_0049", 231, "?"); // missing '}' before end of script
609 suppress("porticullis_0049", 231, ""); // missing accept / refuse / return before script end
610
611 suppress("pressurepad_gob_0029", 74, "goto"); // missing label 'stress'
612
613 suppress("public_notice_0011", 965, "magicoff"); // unknown command 'magicoff', should be 'magic off'
614
615 suppress("rat_base", 17145, "play"); // sound number is sometimes too high
616
617 suppress("rat_base_0059", 62, "behavior"); // unknown behavior 'firendly', should be 'friendly'
618 suppress("rat_base_0059", 160, "behavior"); // unknown behavior 'firendly', should be 'friendly'
619
620 suppress("ratman_base", 22834, "goto"); // missing label "main_alert"
621
622 suppress("ratman_base_0024", 608, "goto"); // missing label 'test'
623
624 suppress("ratman_base_0026", 712, "setevent"); // unsupported event: "detect_player"
625
626 suppress("rock_akbaa", 135, "setinternalname"); // obsolete command 'setinternalname'
627
628 suppress("ruby_inwall", 135, "play"); // unknown flag -e (ignored)
629
630 suppress("sausagev", 12376, "inventory playeraddfromscene"); // unknown target 'note_0015'
631
632 suppress("secret_door_council_2b", 609, "}"); // extraneous '}'
633
634 suppress("shiny_orb", 103, "setinternalname"); // obsolete command
635
636 suppress("snake_woman_base", 26358, "goto"); // missing label 'main_alert'
637
638 suppress("snake_woman_base_0004", 1660, "goto"); // unreachable code after goto
639
640 suppress("snake_woman_base_0007", 1138, "goto"); // missing label 'short'
641
642 suppress("snake_woman_base_0008", 16149, "goto"); // missing label 'dialogue5_2'
643
644 suppress("snake_woman_base_0010", 122, "collions"); // unknown command 'collions', should be 'collision'
645
646 suppress("snake_woman_base_0015", 113, "setevent"); // unsupported event: "misc_reflection"
647
648 suppress("snake_woman_base_0016", 138, "setevent"); // unsupported event: "misc_reflection"
649
650 suppress("spider_base_0024", 660, "play"); // missing sound file 'spider_stress'
651 suppress("spider_base_0024", 858, "play"); // missing sound file 'spider_stress'
652
653 suppress("sword_2handed_meteor_enchant_0001", 48, "}"); // missing accept/refuse before end of event block
654
655 suppress("sword_mx", 458, "halo"); // unknown flag -a (ignored)
656
657 suppress("sylib", 832, "timer"); // unknown flag -t (ignored)
658
659 suppress("timed_lever_0033", 1027, "-smf"); // command wrongly interpreted as event (script parser limitation)
660
661 suppress("timed_lever_0052", 648, "-smf"); // command wrongly interpreted as event (script parser limitation)
662
663 suppress("torch_rotating_0004", 68, "?"); // 'playanim' only takes one parameter
664 suppress("torch_rotating_0004", 88, "?"); // 'playanim' only takes one parameter
665 suppress("torch_rotating_0004", 89, "rotatingtorchdown"); // 'playanim' only takes one parameter
666
667 suppress("torch_rotating_0005", 68, "?"); // 'playanim' only takes one parameter
668 suppress("torch_rotating_0005", 88, "?"); // 'playanim' only takes one parameter
669 suppress("torch_rotating_0005", 89, "rotatingtorchdown"); // 'playanim' only takes one parameter
670
671 suppress("training_dummy", 174, "play"); // missing sound file "wooddoorhit", closest match is "door_wood_hit"
672
673 suppress("troll_base", 5107, "loadanim"); // missing animation: "troll_fight_ready_toponly"
674 suppress("troll_base", 5175, "loadanim"); // missing animation: "troll_fight_unready_toponly"
675 suppress("troll_base", 19054, "goto"); // missing label "main_alert"
676
677 suppress("undead_base_0039", 102, "}"); // missing accept/refuse before end of event block
678
679 suppress("undead_base_0046", 110, "playanim"); // animation 'wait' not loaded yet
680
681 suppress("wall_breakable", 523, "}"); // missing accept/refuse before end of event block
682
683 suppress("wrat_base", 17152, "play"); // sound number is sometimes too high
684
685 suppress("y_mx", 3106, "loadanim"); // bad animation id: 'bae_ready', should be 'bare_ready'
686
687 class FakeCommand : public Command {
688
689 public:
690
691 explicit FakeCommand(const string & name) : Command(name) { }
692
693 Result execute(Context & context) {
694 ARX_UNUSED(context);
695 return Success;
696 }
697
698 };
699
700 /* 'playanim' only takes one parameter
701 * dwarf_little_crusher_0001:229
702 * dwarf_little_crusher_0002:226
703 * dwarf_little_crusher_0003:138
704 * need to use fake command so other commands on same line get executed!
705 */
706 ScriptEvent::registerCommand(new FakeCommand("dwarflittlecrusherup"));
707
708 return suppressionCount;
709 }
710
isSuppressed(const Context & context,const string & command)711 bool isSuppressed(const Context & context, const string & command) {
712 return contains(suppressions, context, command);
713 }
714
isBlockEndSuprressed(const Context & context,const string & command)715 bool isBlockEndSuprressed(const Context & context, const string & command) {
716 return contains(blockSuppressions, context, command);
717 }
718
719 }
720