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/config-manager.h"
24 #include "common/endian.h"
25 #include "lure/luredefs.h"
26 #include "lure/debugger.h"
27 #include "lure/decode.h"
28 #include "lure/game.h"
29 #include "lure/res.h"
30 #include "lure/res_struct.h"
31 #include "lure/room.h"
32 #include "lure/scripts.h"
33 #include "lure/strings.h"
34
35 namespace Lure {
36
Debugger()37 Debugger::Debugger(): GUI::Debugger() {
38 registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
39 registerCmd("enter", WRAP_METHOD(Debugger, cmd_enterRoom));
40 registerCmd("rooms", WRAP_METHOD(Debugger, cmd_listRooms));
41 registerCmd("fields", WRAP_METHOD(Debugger, cmd_listFields));
42 registerCmd("setfield", WRAP_METHOD(Debugger, cmd_setField));
43 registerCmd("queryfield", WRAP_METHOD(Debugger, cmd_queryField));
44 registerCmd("give", WRAP_METHOD(Debugger, cmd_giveItem));
45 registerCmd("hotspots", WRAP_METHOD(Debugger, cmd_hotspots));
46 registerCmd("hotspot", WRAP_METHOD(Debugger, cmd_hotspot));
47 registerCmd("room", WRAP_METHOD(Debugger, cmd_room));
48 registerCmd("showanim", WRAP_METHOD(Debugger, cmd_showAnim));
49 registerCmd("strings", WRAP_METHOD(Debugger, cmd_saveStrings));
50 registerCmd("debug", WRAP_METHOD(Debugger, cmd_debug));
51 registerCmd("script", WRAP_METHOD(Debugger, cmd_script));
52 }
53
strToInt(const char * s)54 static int strToInt(const char *s) {
55 if (!*s)
56 // No string at all
57 return 0;
58 else if (strcmp(s, "player") == 0)
59 return PLAYER_ID;
60 else if (strcmp(s, "ratpouch") == 0)
61 return RATPOUCH_ID;
62 else if (toupper(s[strlen(s) - 1]) != 'H')
63 // Standard decimal string
64 return atoi(s);
65
66 // Hexadecimal string
67 int result = 0;
68 const char *p = s;
69 char ch;
70 while ((ch = toupper(*p++)) != 'H') {
71 if ((ch >= '0') && (ch <= '9'))
72 result = (result << 4) + (ch - '0');
73 else if ((ch >= 'A') && (ch <= 'F'))
74 result = (result << 4) + (ch - 'A' + 10);
75 else
76 break;
77 }
78 return result;
79 }
80
cmd_enterRoom(int argc,const char ** argv)81 bool Debugger::cmd_enterRoom(int argc, const char **argv) {
82 Resources &res = Resources::getReference();
83 Room &room = Room::getReference();
84 uint remoteFlag = 0;
85
86 if (argc > 1) {
87 int roomNumber = strToInt(argv[1]);
88
89 // Validate that it's an existing room
90 if (res.getRoom(roomNumber) == NULL) {
91 debugPrintf("specified number was not a valid room\n");
92 return true;
93 }
94
95 if (argc > 2) {
96 remoteFlag = strToInt(argv[2]);
97 }
98
99 room.leaveRoom();
100 room.setRoomNumber(roomNumber);
101 if (!remoteFlag)
102 res.getActiveHotspot(PLAYER_ID)->setRoomNumber(roomNumber);
103
104 detach();
105 return false;
106 }
107
108 debugPrintf("Syntax: room <roomnum> [<remoteview>]\n");
109 debugPrintf("A non-zero value for reomteview will change the room without ");
110 debugPrintf("moving the player.\n");
111 return true;
112 }
113
cmd_listRooms(int argc,const char ** argv)114 bool Debugger::cmd_listRooms(int argc, const char **argv) {
115 RoomDataList &rooms = Resources::getReference().roomData();
116 StringData &strings = StringData::getReference();
117 char buffer[MAX_DESC_SIZE];
118 int ctr = 0;
119
120 debugPrintf("Available rooms are:\n");
121 for (RoomDataList::iterator i = rooms.begin(); i != rooms.end(); ++i) {
122 RoomData const &room = **i;
123 // Explictly note the second drawbridge room as "Alt"
124 if (room.roomNumber == 49) {
125 strings.getString(47, buffer);
126 strcat(buffer, " (alt)");
127 } else {
128 strings.getString(room.roomNumber, buffer);
129 }
130
131 debugPrintf("#%d - %s", room.roomNumber, buffer);
132
133 if (++ctr % 3 == 0) debugPrintf("\n");
134 else {
135 // Write out spaces between columns
136 int numSpaces = 25 - strlen(buffer) - (room.roomNumber >= 10 ? 2 : 1);
137 char *s = buffer;
138 while (numSpaces-- > 0) *s++ = ' ';
139 *s = '\0';
140 debugPrintf("%s", buffer);
141 }
142 }
143 debugPrintf("\n");
144 debugPrintf("Current room: %d\n", Room::getReference().roomNumber());
145
146 return true;
147 }
148
cmd_listFields(int argc,const char ** argv)149 bool Debugger::cmd_listFields(int argc, const char **argv) {
150 ValueTableData &fields = Resources::getReference().fieldList();
151
152 for (int ctr = 0; ctr < fields.size(); ++ctr) {
153 debugPrintf("(%-2d): %-5d", ctr, fields.getField(ctr));
154 if (!((ctr + 1) % 7))
155 debugPrintf("\n");
156 }
157 debugPrintf("\n");
158 return true;
159 }
160
cmd_setField(int argc,const char ** argv)161 bool Debugger::cmd_setField(int argc, const char **argv) {
162 ValueTableData &fields = Resources::getReference().fieldList();
163
164 if (argc >= 3) {
165 int fieldNum = strToInt(argv[1]);
166 uint16 value = strToInt(argv[2]);
167
168 if ((fieldNum < 0) || (fieldNum >= fields.size())) {
169 // Invalid field number
170 debugPrintf("Invalid field number specified\n");
171 } else {
172 // Set the field value
173 fields.setField(fieldNum, value);
174 }
175 } else {
176 debugPrintf("Syntax: setfield <field_number> <value>\n");
177 }
178
179 return true;
180 }
181
cmd_queryField(int argc,const char ** argv)182 bool Debugger::cmd_queryField(int argc, const char **argv) {
183 ValueTableData &fields = Resources::getReference().fieldList();
184
185 if (argc > 1) {
186 int fieldNum = strToInt(argv[1]);
187 if ((fieldNum < 0) || (fieldNum >= fields.size())) {
188 // Invalid field number
189 debugPrintf("Invalid field number specified\n");
190 } else {
191 // Get the field value
192 debugPrintf("Field %d is %d (%xh)\n", fieldNum,
193 fields.getField(fieldNum), fields.getField(fieldNum));
194 }
195 } else {
196 debugPrintf("Syntax: queryfield <field_num>\n");
197 }
198
199 return true;
200 }
201
cmd_giveItem(int argc,const char ** argv)202 bool Debugger::cmd_giveItem(int argc, const char **argv) {
203 Resources &res = Resources::getReference();
204 uint16 itemNum;
205 uint16 charNum = PLAYER_ID;
206 HotspotData *charHotspot, *itemHotspot;
207
208 if (argc >= 2) {
209 itemNum = strToInt(argv[1]);
210
211 if (argc == 3)
212 charNum = strToInt(argv[2]);
213
214 itemHotspot = res.getHotspot(itemNum);
215 charHotspot = res.getHotspot(charNum);
216
217 if (itemHotspot == NULL) {
218 debugPrintf("The specified item does not exist\n");
219 } else if (itemNum < 0x408) {
220 debugPrintf("The specified item number is not an object\n");
221 } else if ((charNum < PLAYER_ID) || (charNum >= 0x408) ||
222 (charHotspot == NULL)) {
223 debugPrintf("The specified character does not exist");
224 } else {
225 // Set the item's room number to be the destination character
226 itemHotspot->roomNumber = charNum;
227 }
228 } else {
229 debugPrintf("Syntax: give <item_id> [<character_id>]\n");
230 }
231
232 return true;
233 }
234
cmd_hotspots(int argc,const char ** argv)235 bool Debugger::cmd_hotspots(int argc, const char **argv) {
236 Resources &res = Resources::getReference();
237 StringData &strings = StringData::getReference();
238 Room &room = Room::getReference();
239 char buffer[MAX_DESC_SIZE];
240
241 if (argc > 1) {
242 if (strcmp(argv[1], "active") == 0) {
243 // Loop for displaying active hotspots
244 HotspotList::iterator i;
245 for (i = res.activeHotspots().begin(); i != res.activeHotspots().end(); ++i) {
246 Hotspot const &hotspot = **i;
247
248 if (hotspot.nameId() == 0) strcpy(buffer, "none");
249 else strings.getString(hotspot.nameId(), buffer);
250
251 debugPrintf("%4xh - %s pos=(%d,%d,%d)\n", hotspot.hotspotId(), buffer,
252 hotspot.x(), hotspot.y(), hotspot.roomNumber());
253 }
254 } else {
255 // Presume it's a room's hotspots
256 uint16 roomNumber = (argc >= 3) ? strToInt(argv[2]) : room.roomNumber();
257
258 HotspotDataList::iterator i;
259 for (i = res.hotspotData().begin(); i != res.hotspotData().end(); ++i) {
260 HotspotData const &hotspot = **i;
261
262 if (hotspot.roomNumber == roomNumber) {
263 if (hotspot.nameId == 0) strcpy(buffer, "none");
264 else strings.getString(hotspot.nameId, buffer);
265
266 debugPrintf("%4xh - %s pos=(%d,%d,%d)\n", hotspot.hotspotId, buffer,
267 hotspot.startX, hotspot.startY, hotspot.roomNumber);
268 }
269 }
270 }
271
272 } else {
273 debugPrintf("Syntax: hotspots ['active' | ['room' | 'room' '<room_number>']]\n");
274 debugPrintf("Gives a list of all the currently active hotspots, or the hotspots\n");
275 debugPrintf("present in either the current room or a designated one\n");
276 }
277
278 return true;
279 }
280
cmd_hotspot(int argc,const char ** argv)281 bool Debugger::cmd_hotspot(int argc, const char **argv) {
282 Resources &res = Resources::getReference();
283 StringData &strings = StringData::getReference();
284 StringList &stringList = res.stringList();
285 char buffer[MAX_DESC_SIZE];
286 HotspotData *hs;
287 Hotspot *h;
288
289 if (argc < 2) {
290 debugPrintf("hotspot <hotspot_id> ['paths' | 'schedule' | 'actions' | 'activate' | 'deactivate' | 'setpos']\n");
291 return true;
292 }
293 hs = res.getHotspot(strToInt(argv[1]));
294 if (!hs) {
295 debugPrintf("Unknown hotspot specified\n");
296 return true;
297 }
298
299 h = res.getActiveHotspot(hs->hotspotId);
300 if (argc == 2) {
301 // Show the hotspot properties
302 strings.getString(hs->nameId, buffer);
303 debugPrintf("name = %d - %s, descs = (%d,%d)\n", hs->nameId, buffer,
304 hs->descId, hs->descId2);
305 debugPrintf("actions = %xh, offset = %xh\n", hs->actions, hs->actionsOffset);
306 debugPrintf("flags = %xh, layer = %d\n", hs->flags, hs->layer);
307 debugPrintf("position = %d,%d,%d\n", hs->startX, hs->startY, hs->roomNumber);
308 debugPrintf("size = %d,%d, alt = %d,%d, yCorrection = %d\n",
309 hs->width, hs->height, hs->widthCopy, hs->heightCopy, hs->yCorrection);
310 debugPrintf("Talk bubble offset = %d,%d\n", hs->talkX, hs->talkY);
311 debugPrintf("load offset = %xh, script load = %d\n", hs->loadOffset, hs->scriptLoadFlag);
312 debugPrintf("Animation Id = %xh, Color offset = %d\n", hs->animRecordId, hs->colorOffset);
313 debugPrintf("Talk Script offset = %xh, Tick Script offset = %xh\n",
314 hs->talkScriptOffset, hs->tickScriptOffset);
315 debugPrintf("Tick Proc offset = %xh\n", hs->tickProcId);
316 debugPrintf("Tick timeout = %d\n", hs->tickTimeout);
317 debugPrintf("Character mode = %d, delay ctr = %d, pause ctr = %d\n",
318 hs->characterMode, hs->delayCtr, hs->pauseCtr);
319
320 if (h != NULL) {
321 debugPrintf("Frame Number = %d of %d\n", h->frameNumber(), h->numFrames());
322 debugPrintf("Persistent = %s\n", h->persistant() ? "true" : "false");
323 }
324
325 } else if (strcmp(argv[2], "actions") == 0) {
326 // List the action set for the character
327 for (int action = GET; action <= EXAMINE; ++action) {
328 uint16 offset = res.getHotspotAction(hs->actionsOffset, (Action) action);
329 const char *actionStr = stringList.getString(action);
330
331 if (offset >= 0x8000) {
332 debugPrintf("%s - Message %xh\n", actionStr, offset & 0x7ff);
333 } else if (offset != 0) {
334 debugPrintf("%s - Script %xh\n", actionStr, offset);
335 }
336 }
337 } else if (strcmp(argv[2], "activate") == 0) {
338 // Activate the hotspot
339 res.activateHotspot(hs->hotspotId);
340 hs->flags &= ~HOTSPOTFLAG_MENU_EXCLUSION;
341 debugPrintf("Activated\n");
342
343 } else if (strcmp(argv[2], "deactivate") == 0) {
344 // Deactivate the hotspot
345 res.deactivateHotspot(hs->hotspotId);
346 hs->flags |= HOTSPOTFLAG_MENU_EXCLUSION;
347 debugPrintf("Deactivated\n");
348
349 } else {
350 if (strcmp(argv[2], "schedule") == 0) {
351 // List any current schedule for the character
352 debugPrintf("%s", hs->npcSchedule.getDebugInfo().c_str());
353 }
354 if (!h)
355 debugPrintf("The specified hotspot is not currently active\n");
356 else if (strcmp(argv[2], "paths") == 0) {
357 // List any paths for a charcter
358 debugPrintf("%s", h->pathFinder().getDebugInfo().c_str());
359 }
360 else if (strcmp(argv[2], "pixels") == 0) {
361 // List the pixel data for the hotspot
362 HotspotAnimData &pData = h->anim();
363 debugPrintf("Record Id = %xh\n", pData.animRecordId);
364 debugPrintf("Flags = %d\n", pData.flags);
365 debugPrintf("Frames: up=%d down=%d left=%d right=%d\n",
366 pData.upFrame, pData.downFrame, pData.leftFrame, pData.rightFrame);
367 debugPrintf("Current frame = %d of %d\n", h->frameNumber(), h->numFrames());
368 }
369 else if (strcmp(argv[2], "setpos") == 0) {
370 // Set the hotspot position
371 if (argc >= 5)
372 h->setPosition(strToInt(argv[3]), strToInt(argv[4]));
373 if (argc >= 6)
374 h->setRoomNumber(strToInt(argv[5]));
375 debugPrintf("Done.\n");
376 }
377 }
378
379 debugPrintf("\n");
380 return true;
381 }
382
383 const char *directionList[5] = {"UP", "DOWN", "LEFT", "RIGHT", "NONE"};
384
cmd_room(int argc,const char ** argv)385 bool Debugger::cmd_room(int argc, const char **argv) {
386 Resources &res = Resources::getReference();
387 StringData &strings = StringData::getReference();
388 char buffer[MAX_DESC_SIZE];
389
390 if (argc < 2) {
391 debugPrintf("room <room_number>\n");
392 return true;
393 }
394 int roomNumber = strToInt(argv[1]);
395 RoomData *room = res.getRoom(roomNumber);
396 if (!room) {
397 debugPrintf("Unknown room specified\n");
398 return true;
399 }
400
401 // Show the room details
402 strings.getString(roomNumber, buffer);
403 debugPrintf("room #%d - %s\n", roomNumber, buffer);
404 strings.getString(room->descId, buffer);
405 debugPrintf("%s\n", buffer);
406 debugPrintf("Horizontal clipping = %d->%d walk area=(%d,%d)-(%d,%d)\n",
407 room->clippingXStart, room->clippingXEnd,
408 room->walkBounds.left, room->walkBounds.top,
409 room->walkBounds.right, room->walkBounds.bottom);
410
411 debugPrintf("Exit hotspots:");
412 RoomExitHotspotList &exits = room->exitHotspots;
413 if (exits.empty())
414 debugPrintf(" none\n");
415 else {
416 RoomExitHotspotList::iterator i;
417 for (i = exits.begin(); i != exits.end(); ++i) {
418 RoomExitHotspotData const &rec = **i;
419
420 debugPrintf("\nArea - (%d,%d)-(%d,%d) Room=%d Cursor=%d Hotspot=%xh",
421 rec.xs, rec.ys, rec.xe, rec.ye, rec.destRoomNumber, rec.cursorNum, rec.hotspotId);
422 }
423
424 debugPrintf("\n");
425 }
426
427 debugPrintf("Room exits:");
428 if (room->exits.empty())
429 debugPrintf(" none\n");
430 else {
431 RoomExitList::iterator i2;
432 for (i2 = room->exits.begin(); i2 != room->exits.end(); ++i2) {
433 RoomExitData const &rec2 = **i2;
434
435 debugPrintf("\nExit - (%d,%d)-(%d,%d) Dest=%d,(%d,%d) Dir=%s Sequence=%xh",
436 rec2.xs, rec2.ys, rec2.xe, rec2.ye, rec2.roomNumber,
437 rec2.x, rec2.y, directionList[rec2.direction], rec2.sequenceOffset);
438 }
439
440 debugPrintf("\n");
441 }
442
443 return true;
444 }
445
cmd_showAnim(int argc,const char ** argv)446 bool Debugger::cmd_showAnim(int argc, const char **argv) {
447 Resources &res = Resources::getReference();
448 if (argc < 2) {
449 debugPrintf("showAnim animId [[frame_width frame_height] | list]\n");
450 return true;
451 }
452
453 // Get the animation Id
454 int animId = strToInt(argv[1]);
455 HotspotAnimData *data = res.getAnimation(animId);
456 if (data == NULL) {
457 debugPrintf("No such animation Id exists\n");
458 return true;
459 }
460
461 // Figure out the total size of the animation - this will be used for guestimating
462 // frame sizes, or validating that a specified frame size is correct
463 MemoryBlock *src = Disk::getReference().getEntry(data->animId);
464
465 int numFrames = READ_LE_UINT16(src->data());
466 uint16 *headerEntry = (uint16 *) (src->data() + 2);
467 assert((numFrames >= 1) && (numFrames < 100));
468
469 // Calculate total needed size for output and create memory block to hold it
470 uint32 totalSize = 0;
471 for (uint16 ctr = 0; ctr < numFrames; ++ctr, ++headerEntry) {
472 totalSize += (READ_LE_UINT16(headerEntry) + 31) / 32;
473 }
474 totalSize = (totalSize + 0x81) << 4;
475 MemoryBlock *dest = Memory::allocate(totalSize);
476
477 uint32 srcStart = (numFrames + 1) * sizeof(uint16) + 6;
478 uint32 destSize = AnimationDecoder::decode_data(src, dest, srcStart) - 0x40;
479
480 // Figure out the frame size
481 int frameSize;
482
483 if ((data->flags & PIXELFLAG_HAS_TABLE) != 0) {
484 // Table based animation, so get frame size from frame 1 offset
485 frameSize = READ_LE_UINT16(src->data());
486 } else {
487 // Get frame size from dividing uncompressed size by number of frames
488 frameSize = destSize / numFrames;
489 }
490
491 // Free up the data
492 delete src;
493 delete dest;
494
495 int width, height;
496
497 if (argc == 4) {
498 // Width and height specified
499 width = strToInt(argv[2]);
500 height = strToInt(argv[3]);
501
502 if ((width * height) != (frameSize * 2)) {
503 debugPrintf("Warning: Total size = %d, Frame size (%d,%d) * %d frames = %d bytes\n",
504 destSize, width, height, numFrames, width * height * numFrames / 2);
505 }
506 } else {
507 // Guestimate a frame size
508 frameSize = destSize / numFrames;
509
510 // Figure out the approximate starting point of a width 3/4 the frame size
511 width = frameSize * 3 / 4;
512
513 bool descFlag = (argc == 3);
514 if (descFlag) debugPrintf("Target size = %d\n", frameSize * 2);
515
516 while ((width > 0) && (descFlag || (((frameSize * 2) % width) != 0))) {
517 if (((frameSize * 2) % width) == 0)
518 debugPrintf("Frame size (%d,%d) found\n", width, frameSize * 2 / width);
519 --width;
520 }
521
522 if (argc == 3) {
523 debugPrintf("Done\n");
524 return true;
525 } else if (width == 0) {
526 debugPrintf("Total size = %d, # frames = %d, frame Size = %d - No valid frame dimensions\n",
527 destSize, numFrames, frameSize);
528 return true;
529 }
530
531 height = (frameSize * 2) / width;
532 debugPrintf("# frames = %d, guestimated frame size = (%d,%d)\n",
533 numFrames, width, height);
534 }
535
536 // Bottle object is used as a handy hotspot holder that doesn't have any
537 // tick proc behavior that we need to worry about
538 Hotspot *hotspot = res.activateHotspot(BOTTLE_HOTSPOT_ID);
539 hotspot->setLayer(0xfe);
540 hotspot->setSize(width, height);
541
542 Hotspot *player = res.activateHotspot(PLAYER_ID);
543 hotspot->setColorOffset(player->resource()->colorOffset);
544
545 hotspot->setAnimation(animId);
546
547 debugPrintf("Done\n");
548 return true;
549 }
550
cmd_saveStrings(int argc,const char ** argv)551 bool Debugger::cmd_saveStrings(int argc, const char **argv) {
552 if (argc != 2) {
553 debugPrintf("strings <stringId>\n");
554 return true;
555 }
556
557 StringData &strings = StringData::getReference();
558
559 char *buffer = (char *)malloc(32768);
560 if (!buffer) {
561 debugPrintf("Cannot allocate strings buffer\n");
562 return true;
563 }
564
565 uint16 id = strToInt(argv[1]);
566 strings.getString(id, buffer);
567 debugPrintf("%s\n", buffer);
568
569 /* Commented out code for saving all text strings - note that 0x1000 is chosen
570 * arbitrarily, so there'll be a bunch of garbage at the end, or the game will crash
571
572 // Save all the strings to a text file - this
573
574 FILE *f = fopen("strings.txt", "w");
575
576 for (int index = 0; index < 0x1000; ++index) {
577 strings.getString(index, buffer);
578 fprintf(f, "%.4xh - %s\n", index, buffer);
579 }
580
581 fclose(f);
582
583 debugPrintf("Done\n");
584 */
585
586 free(buffer);
587
588 return true;
589 }
590
cmd_debug(int argc,const char ** argv)591 bool Debugger::cmd_debug(int argc, const char **argv) {
592 Game &game = Game::getReference();
593 Room &room = Room::getReference();
594
595 if ((argc == 2) && (strcmp(argv[1], "on") == 0)) {
596 debugPrintf("debug keys are on\n");
597 game.debugFlag() = true;
598
599 } else if ((argc == 2) && (strcmp(argv[1], "off") == 0)) {
600 debugPrintf("debug keys are off\n");
601 game.debugFlag() = false;
602 room.setShowInfo(false);
603
604 } else {
605 debugPrintf("debug [on | off]]\n");
606 }
607
608 return true;
609 }
610
cmd_script(int argc,const char ** argv)611 bool Debugger::cmd_script(int argc, const char **argv) {
612 if (argc < 2) {
613 debugPrintf("script <script number> [param 1] [param 2] [param 3] [exit flag]\n");
614 return true;
615 }
616
617 int scriptNumber = strToInt(argv[1]);
618 if ((scriptNumber < 0) || (scriptNumber > 66)) {
619 debugPrintf("An invalid script number was specified\n");
620 return true;
621 }
622
623 uint16 param1 = 0, param2 = 0, param3 = 0;
624 if (argc >= 3)
625 param1 = strToInt(argv[2]);
626 if (argc >= 4)
627 param2 = strToInt(argv[3]);
628 if (argc >= 5)
629 param3 = strToInt(argv[4]);
630
631 Script::executeMethod(scriptNumber, param1, param2, param3);
632 debugPrintf("Script executed\n");
633 return true;
634 }
635
636 } // End of namespace Lure
637