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/endian.h"
24 #include "common/util.h"
25 #include "common/textconsole.h"
26 #include "common/translation.h"
27
28 #include "sword1/logic.h"
29 #include "sword1/text.h"
30 #include "sword1/sound.h"
31 #include "sword1/eventman.h"
32 #include "sword1/menu.h"
33 #include "sword1/router.h"
34 #include "sword1/screen.h"
35 #include "sword1/mouse.h"
36 #include "sword1/sword1.h"
37 #include "sword1/music.h"
38 #include "sword1/swordres.h"
39 #include "sword1/animation.h"
40
41 #include "sword1/debug.h"
42
43 #include "gui/message.h"
44
45 namespace Sword1 {
46
47 #define MAX_STACK_SIZE 10
48 #define SCRIPT_VERSION 13
49 #define LAST_FRAME 999
50
51 uint32 Logic::_scriptVars[NUM_SCRIPT_VARS];
52
Logic(SwordEngine * vm,ObjectMan * pObjMan,ResMan * resMan,Screen * pScreen,Mouse * pMouse,Sound * pSound,Music * pMusic,Menu * pMenu,OSystem * system,Audio::Mixer * mixer)53 Logic::Logic(SwordEngine *vm, ObjectMan *pObjMan, ResMan *resMan, Screen *pScreen, Mouse *pMouse, Sound *pSound, Music *pMusic, Menu *pMenu, OSystem *system, Audio::Mixer *mixer)
54 : _rnd("sword1") {
55
56 _vm = vm;
57 _objMan = pObjMan;
58 _resMan = resMan;
59 _screen = pScreen;
60 _mouse = pMouse;
61 _music = pMusic;
62 _sound = pSound;
63 _menu = pMenu;
64 _textMan = NULL;
65 _screen->useTextManager(_textMan);
66 _router = new Router(_objMan, _resMan);
67 _eventMan = NULL;
68 _system = system;
69 _mixer = mixer;
70
71 setupMcodeTable();
72 }
73
~Logic()74 Logic::~Logic() {
75 delete _textMan;
76 delete _router;
77 delete _eventMan;
78 }
79
initialize()80 void Logic::initialize() {
81 memset(_scriptVars, 0, NUM_SCRIPT_VARS * sizeof(uint32));
82 for (uint8 cnt = 0; cnt < NON_ZERO_SCRIPT_VARS; cnt++)
83 _scriptVars[_scriptVarInit[cnt][0]] = _scriptVarInit[cnt][1];
84 if (SwordEngine::_systemVars.isDemo)
85 _scriptVars[PLAYINGDEMO] = 1;
86
87 delete _eventMan;
88 _eventMan = new EventManager();
89
90 delete _textMan;
91 _textMan = new Text(_objMan, _resMan,
92 (SwordEngine::_systemVars.language == BS1_CZECH) ? true : false);
93 _screen->useTextManager(_textMan);
94 _textRunning = _speechRunning = false;
95 _speechFinished = true;
96 }
97
newScreen(uint32 screen)98 void Logic::newScreen(uint32 screen) {
99 Object *compact = (Object *)_objMan->fetchObject(PLAYER);
100
101 // work around script bug #911508
102 if (((screen == 25) || (_scriptVars[SCREEN] == 25)) && (_scriptVars[SAND_FLAG] == 4)) {
103 Object *cpt = _objMan->fetchObject(SAND_25);
104 Object *george = _objMan->fetchObject(PLAYER);
105 if (george->o_place == HOLDING_REPLICA_25) // is george holding the replica in his hands?
106 fnFullSetFrame(cpt, SAND_25, IMPFLRCDT, IMPFLR, 0, 0, 0, 0); // empty impression in floor
107 else
108 fnFullSetFrame(cpt, SAND_25, IMPPLSCDT, IMPPLS, 0, 0, 0, 0); // impression filled with plaster
109 }
110
111 // work around, at screen 69 in psx version TOP menu gets stuck at disabled, fix it at next screen (71)
112 if ((screen == 71) && (SwordEngine::isPsx()))
113 _scriptVars[TOP_MENU_DISABLED] = 0;
114
115 if (SwordEngine::_systemVars.justRestoredGame) { // if we've just restored a game - we want George to be exactly as saved
116 fnAddHuman(NULL, 0, 0, 0, 0, 0, 0, 0);
117 if (_scriptVars[GEORGE_WALKING]) { // except that if George was walking when we saveed the game
118 fnStandAt(compact, PLAYER, _scriptVars[CHANGE_X], _scriptVars[CHANGE_Y], _scriptVars[CHANGE_DIR], _scriptVars[CHANGE_STANCE], 0, 0);
119 fnIdle(compact, PLAYER, 0, 0, 0, 0, 0, 0);
120 _scriptVars[GEORGE_WALKING] = 0;
121 }
122 SwordEngine::_systemVars.justRestoredGame = 0;
123 _music->startMusic(_scriptVars[CURRENT_MUSIC], 1);
124 } else { // if we haven't just restored a game, set George to stand, etc
125 compact->o_screen = _scriptVars[NEW_SCREEN]; //move the mega/player at this point between screens
126 fnStandAt(compact, PLAYER, _scriptVars[CHANGE_X], _scriptVars[CHANGE_Y], _scriptVars[CHANGE_DIR], _scriptVars[CHANGE_STANCE], 0, 0);
127 fnChangeFloor(compact, PLAYER, _scriptVars[CHANGE_PLACE], 0, 0, 0, 0, 0);
128 }
129 }
130
engine()131 void Logic::engine() {
132 debug(8, "\n\nNext logic cycle");
133 _eventMan->serviceGlobalEventList();
134
135 for (uint16 sectCnt = 0; sectCnt < TOTAL_SECTIONS; sectCnt++) {
136 if (_objMan->sectionAlive(sectCnt)) {
137 uint32 numCpts = _objMan->fetchNoObjects(sectCnt);
138 for (uint32 cptCnt = 0; cptCnt < numCpts; cptCnt++) {
139 uint32 currentId = sectCnt * ITM_PER_SEC + cptCnt;
140 Object *compact = _objMan->fetchObject(currentId);
141
142 if (compact->o_status & STAT_LOGIC) { // does the object want to be processed?
143 if (compact->o_status & STAT_EVENTS) {
144 //subscribed to the global-event-switcher? and in logic mode
145 switch (compact->o_logic) {
146 case LOGIC_pause_for_event:
147 case LOGIC_idle:
148 case LOGIC_AR_animate:
149 _eventMan->checkForEvent(compact);
150 break;
151 }
152 }
153 debug(7, "Logic::engine: handling compact %d (%X)", currentId, currentId);
154 processLogic(compact, currentId);
155 compact->o_sync = 0; // syncs are only available for 1 cycle.
156 }
157
158 if ((uint32)compact->o_screen == _scriptVars[SCREEN]) {
159 if (compact->o_status & STAT_FORE)
160 _screen->addToGraphicList(0, currentId);
161 if (compact->o_status & STAT_SORT)
162 _screen->addToGraphicList(1, currentId);
163 if (compact->o_status & STAT_BACK)
164 _screen->addToGraphicList(2, currentId);
165
166 if (compact->o_status & STAT_MOUSE)
167 _mouse->addToList(currentId, compact);
168 }
169 }
170 }
171 }
172 //_collision->checkCollisions();
173
174 }
175
processLogic(Object * compact,uint32 id)176 void Logic::processLogic(Object *compact, uint32 id) {
177 int logicRet;
178 do {
179 switch (compact->o_logic) {
180 case LOGIC_idle:
181 logicRet = 0;
182 break;
183 case LOGIC_pause:
184 case LOGIC_pause_for_event:
185 if (compact->o_pause) {
186 compact->o_pause--;
187 logicRet = 0;
188 } else {
189 compact->o_logic = LOGIC_script;
190 logicRet = 1;
191 }
192 break;
193 case LOGIC_quit:
194 compact->o_logic = LOGIC_script;
195 logicRet = 0;
196 break;
197 case LOGIC_wait_for_sync:
198 if (compact->o_sync) {
199 logicRet = 1;
200 compact->o_logic = LOGIC_script;
201 } else
202 logicRet = 0;
203 break;
204 case LOGIC_choose:
205 _scriptVars[CUR_ID] = id;
206 logicRet = _menu->logicChooser(compact);
207 break;
208 case LOGIC_wait_for_talk:
209 logicRet = logicWaitTalk(compact);
210 break;
211 case LOGIC_start_talk:
212 logicRet = logicStartTalk(compact);
213 break;
214 case LOGIC_script:
215 _scriptVars[CUR_ID] = id;
216 logicRet = scriptManager(compact, id);
217 break;
218 case LOGIC_new_script:
219 compact->o_tree.o_script_pc[compact->o_tree.o_script_level] = _newScript;
220 compact->o_tree.o_script_id[compact->o_tree.o_script_level] = _newScript;
221 compact->o_logic = LOGIC_script;
222 logicRet = 1;
223 break;
224 case LOGIC_AR_animate:
225 logicRet = logicArAnimate(compact, id);
226 break;
227 case LOGIC_restart:
228 compact->o_tree.o_script_pc[compact->o_tree.o_script_level] = compact->o_tree.o_script_id[compact->o_tree.o_script_level];
229 compact->o_logic = LOGIC_script;
230 logicRet = 1;
231 break;
232 case LOGIC_bookmark:
233 memcpy(&(compact->o_tree.o_script_level), &(compact->o_bookmark.o_script_level), sizeof(ScriptTree));
234 if (id == GMASTER_79) {
235 // workaround for ending script.
236 // GMASTER_79 is not prepared for mega_interact receiving INS_quit
237 fnSuicide(compact, id, 0, 0, 0, 0, 0, 0);
238 logicRet = 0;
239 } else {
240 compact->o_logic = LOGIC_script;
241 logicRet = 1;
242 }
243 break;
244 case LOGIC_speech:
245 logicRet = speechDriver(compact);
246 break;
247 case LOGIC_full_anim:
248 logicRet = fullAnimDriver(compact);
249 break;
250 case LOGIC_anim:
251 logicRet = animDriver(compact);
252 break;
253
254 default:
255 error("Fatal error: compact %d's logic == %X", id, compact->o_logic);
256 break;
257 }
258 } while (logicRet);
259 }
260
logicWaitTalk(Object * compact)261 int Logic::logicWaitTalk(Object *compact) {
262 Object *target = _objMan->fetchObject(compact->o_down_flag);
263
264 if (target->o_status & STAT_TALK_WAIT) {
265 compact->o_logic = LOGIC_script;
266 return 1;
267 } else {
268 return 0;
269 }
270 }
271
logicStartTalk(Object * compact)272 int Logic::logicStartTalk(Object *compact) {
273 Object *target = _objMan->fetchObject(compact->o_down_flag); //holds id of person we're waiting for
274 if (target->o_status & STAT_TALK_WAIT) { //response?
275 compact->o_logic = LOGIC_script; //back to script again
276 return SCRIPT_CONT;
277 }
278 if (_eventMan->eventValid(compact->o_down_flag))
279 return SCRIPT_STOP; //event still valid - keep waiting
280 //the event has gone - so back to script with error code
281 compact->o_down_flag = 0;
282 compact->o_logic = LOGIC_script;
283 return SCRIPT_CONT;
284 }
285
logicArAnimate(Object * compact,uint32 id)286 int Logic::logicArAnimate(Object *compact, uint32 id) {
287 WalkData *route;
288 int32 walkPc;
289 if ((_scriptVars[GEORGE_WALKING] == 0) && (id == PLAYER))
290 _scriptVars[GEORGE_WALKING] = 1;
291
292 compact->o_resource = compact->o_walk_resource;
293 compact->o_status |= STAT_SHRINK;
294 route = compact->o_route;
295
296 walkPc = compact->o_walk_pc;
297 compact->o_frame = route[walkPc].frame;
298 compact->o_dir = route[walkPc].dir;
299 compact->o_xcoord = route[walkPc].x;
300 compact->o_ycoord = route[walkPc].y;
301 compact->o_anim_x = compact->o_xcoord;
302 compact->o_anim_y = compact->o_ycoord;
303
304 if (((_scriptVars[GEORGE_WALKING] == 2) && (walkPc > 5) && (id == PLAYER) &&
305 (route[walkPc - 1].step == 5) && (route[walkPc].step == 0)) ||
306 ((_scriptVars[GEORGE_WALKING] == 3) && (id == PLAYER))) {
307
308 compact->o_frame = 96 + compact->o_dir; //reset
309 if ((compact->o_dir != 2) && (compact->o_dir != 6)) { // on verticals and diagonals stand where george is
310 compact->o_xcoord = route[walkPc - 1].x;
311 compact->o_ycoord = route[walkPc - 1].y;
312 compact->o_anim_x = compact->o_xcoord;
313 compact->o_anim_y = compact->o_ycoord;
314 }
315 compact->o_logic = LOGIC_script;
316 compact->o_down_flag = 0; //0 means error
317 _scriptVars[GEORGE_WALKING] = 0;
318 route[compact->o_walk_pc + 1].frame = 512; //end of sequence
319 if (_scriptVars[MEGA_ON_GRID] == 2)
320 _scriptVars[MEGA_ON_GRID] = 0;
321 }
322 compact->o_walk_pc++;
323
324 if (route[compact->o_walk_pc].frame == 512) { //end of sequence
325 compact->o_logic = LOGIC_script;
326 if (((_scriptVars[GEORGE_WALKING] == 2) || (_scriptVars[GEORGE_WALKING] == 1)) &&
327 (id == PLAYER)) {
328 _scriptVars[GEORGE_WALKING] = 0;
329 if (_scriptVars[MEGA_ON_GRID] == 2)
330 _scriptVars[MEGA_ON_GRID] = 0;
331 }
332 }
333 return 0;
334 }
335
speechDriver(Object * compact)336 int Logic::speechDriver(Object *compact) {
337 if ((!_speechClickDelay) && (_mouse->testEvent() & BS1L_BUTTON_DOWN))
338 _speechFinished = true;
339 if (_speechClickDelay)
340 _speechClickDelay--;
341
342 if (_speechRunning) {
343 if (_sound->speechFinished())
344 _speechFinished = true;
345 } else {
346 if (!compact->o_speech_time)
347 _speechFinished = true;
348 else
349 compact->o_speech_time--;
350 }
351 if (_speechFinished) {
352 if (_speechRunning)
353 _sound->stopSpeech();
354 compact->o_logic = LOGIC_script;
355 if (_textRunning) {
356 _textMan->releaseText(compact->o_text_id);
357 _objMan->fetchObject(compact->o_text_id)->o_status = 0; // kill compact linking text sprite
358 }
359 _speechRunning = _textRunning = false;
360 _speechFinished = true;
361 }
362 if (compact->o_anim_resource) {
363 uint8 *animData = ((uint8 *)_resMan->openFetchRes(compact->o_anim_resource)) + sizeof(Header);
364 int32 numFrames = _resMan->readUint32(animData);
365 animData += 4;
366 compact->o_anim_pc++; // go to next frame of anim
367
368 if (_speechFinished || (compact->o_anim_pc >= numFrames) ||
369 (_speechRunning && (_sound->amISpeaking() == 0)))
370 compact->o_anim_pc = 0; //set to frame 0, closed mouth
371
372 AnimUnit *animPtr = (AnimUnit *)(animData + sizeof(AnimUnit) * compact->o_anim_pc);
373 if (!(compact->o_status & STAT_SHRINK)) {
374 compact->o_anim_x = _resMan->getUint32(animPtr->animX);
375 compact->o_anim_y = _resMan->getUint32(animPtr->animY);
376 }
377 compact->o_frame = _resMan->getUint32(animPtr->animFrame);
378 _resMan->resClose(compact->o_anim_resource);
379 }
380 return 0;
381 }
382
fullAnimDriver(Object * compact)383 int Logic::fullAnimDriver(Object *compact) {
384 if (compact->o_sync) { // return to script immediately if we've received a sync
385 compact->o_logic = LOGIC_script;
386 return 1;
387 }
388 uint8 *data = ((uint8 *)_resMan->openFetchRes(compact->o_anim_resource)) + sizeof(Header);
389 uint32 numFrames = _resMan->readUint32(data);
390 data += 4;
391 AnimUnit *animPtr = (AnimUnit *)(data + compact->o_anim_pc * sizeof(AnimUnit));
392
393 compact->o_anim_x = compact->o_xcoord = _resMan->getUint32(animPtr->animX);
394 compact->o_anim_y = compact->o_ycoord = _resMan->getUint32(animPtr->animY);
395 compact->o_frame = _resMan->getUint32(animPtr->animFrame);
396
397 compact->o_anim_pc++;
398 if (compact->o_anim_pc == (int)numFrames)
399 compact->o_logic = LOGIC_script;
400
401 _resMan->resClose(compact->o_anim_resource);
402 return 0;
403 }
404
animDriver(Object * compact)405 int Logic::animDriver(Object *compact) {
406 if (compact->o_sync) {
407 compact->o_logic = LOGIC_script;
408 return 1;
409 }
410 uint8 *data = ((uint8 *)_resMan->openFetchRes(compact->o_anim_resource)) + sizeof(Header);
411 uint32 numFrames = _resMan->readUint32(data);
412 AnimUnit *animPtr = (AnimUnit *)(data + 4 + compact->o_anim_pc * sizeof(AnimUnit));
413
414 if (!(compact->o_status & STAT_SHRINK)) {
415 compact->o_anim_x = _resMan->getUint32(animPtr->animX);
416 compact->o_anim_y = _resMan->getUint32(animPtr->animY);
417 }
418
419 compact->o_frame = _resMan->getUint32(animPtr->animFrame);
420 compact->o_anim_pc++;
421 if (compact->o_anim_pc == (int)numFrames)
422 compact->o_logic = LOGIC_script;
423
424 _resMan->resClose(compact->o_anim_resource);
425 return 0;
426 }
427
updateScreenParams()428 void Logic::updateScreenParams() {
429 Object *compact = (Object *)_objMan->fetchObject(PLAYER);
430 _screen->setScrolling((int16)(compact->o_xcoord - _scriptVars[FEET_X]),
431 (int16)(compact->o_ycoord - _scriptVars[FEET_Y]));
432 }
433
scriptManager(Object * compact,uint32 id)434 int Logic::scriptManager(Object *compact, uint32 id) {
435 int ret;
436 do {
437 uint32 level = compact->o_tree.o_script_level;
438 uint32 script = compact->o_tree.o_script_id[level];
439 Debug::interpretScript(id, level, script, compact->o_tree.o_script_pc[level] & ITM_ID);
440 ret = interpretScript(compact, id, _resMan->lockScript(script), script, compact->o_tree.o_script_pc[level] & ITM_ID);
441 _resMan->unlockScript(script);
442 if (!ret) {
443 if (compact->o_tree.o_script_level)
444 compact->o_tree.o_script_level--;
445 else
446 error("ScriptManager: basescript %d for cpt %d ended", script, id);
447 } else
448 compact->o_tree.o_script_pc[level] = ret;
449 } while (!ret);
450 return 1;
451 //Logic continues - but the script must have changed logic mode
452 //this is a radical change from S2.0 where once a script finished there
453 //was no more processing for that object on that cycle - the Logic_engine terminated.
454 //This meant that new logics that needed immediate action got a first call from the
455 //setup function. This was a bit tweeky. This technique ensures that the script is a
456 //totally seamless concept that takes up zero cycle time. The only downside is that
457 //an FN_quit becomes slightly more convoluted, but so what you might ask.
458 }
459
runMouseScript(Object * cpt,int32 scriptId)460 void Logic::runMouseScript(Object *cpt, int32 scriptId) {
461 Header *script = _resMan->lockScript(scriptId);
462 debug(9, "running mouse script %d", scriptId);
463 interpretScript(cpt, _scriptVars[SPECIAL_ITEM], script, scriptId, scriptId);
464 _resMan->unlockScript(scriptId);
465 }
466
interpretScript(Object * compact,int id,Header * scriptModule,int scriptBase,int scriptNum)467 int Logic::interpretScript(Object *compact, int id, Header *scriptModule, int scriptBase, int scriptNum) {
468 int32 *scriptCode = (int32 *)(((uint8 *)scriptModule) + sizeof(Header));
469 int32 stack[MAX_STACK_SIZE];
470 int32 stackIdx = 0;
471 int32 offset;
472 int32 pc;
473 if (memcmp(scriptModule->type, "Script", 6))
474 error("Invalid script module");
475 if (scriptModule->version != SCRIPT_VERSION)
476 error("Illegal script version");
477 if (scriptNum < 0)
478 error("negative script number");
479 if ((uint32)scriptNum >= scriptModule->decomp_length)
480 error("Script number out of bounds");
481
482 if (scriptNum < scriptCode[0])
483 pc = scriptCode[scriptNum + 1];
484 else
485 pc = scriptNum;
486 int32 startOfScript = scriptCode[(scriptBase & ITM_ID) + 1];
487
488 int32 a, b, c, d, e, f;
489 int mCodeReturn = 0;
490 int32 mCodeNumber = 0, mCodeArguments = 0;
491 uint32 varNum = 0;
492 while (1) {
493 assert((stackIdx >= 0) && (stackIdx <= MAX_STACK_SIZE));
494 switch (scriptCode[pc++]) {
495 case IT_MCODE:
496 a = b = c = d = e = f = 0;
497 mCodeNumber = scriptCode[pc++];
498 mCodeArguments = scriptCode[pc++];
499 switch (mCodeArguments) {
500 case 6: f = stack[--stackIdx]; // fall through
501 case 5: e = stack[--stackIdx]; // fall through
502 case 4: d = stack[--stackIdx]; // fall through
503 case 3: c = stack[--stackIdx]; // fall through
504 case 2: b = stack[--stackIdx]; // fall through
505 case 1: a = stack[--stackIdx]; // fall through
506 case 0:
507 Debug::callMCode(mCodeNumber, mCodeArguments, a, b, c, d, e, f);
508 mCodeReturn = (this->*_mcodeTable[mCodeNumber])(compact, id, a, b, c, d, e, f);
509 break;
510 default:
511 warning("mcode[%d]: too many arguments(%d)", mCodeNumber, mCodeArguments);
512 }
513 if (mCodeReturn == 0)
514 return pc;
515 break;
516 case IT_PUSHNUMBER:
517 debug(9, "IT_PUSH: %d", scriptCode[pc]);
518 stack[stackIdx++] = scriptCode[pc++];
519 break;
520 case IT_PUSHVARIABLE:
521 debug(9, "IT_PUSHVARIABLE: ScriptVar[%d] => %d", scriptCode[pc], _scriptVars[scriptCode[pc]]);
522 varNum = scriptCode[pc++];
523 if (SwordEngine::_systemVars.isDemo && SwordEngine::isWindows()) {
524 if (varNum >= 397) // BS1 Demo has different number of script variables
525 varNum++;
526 if (varNum >= 699)
527 varNum++;
528 }
529 stack[stackIdx++] = _scriptVars[varNum];
530 break;
531 case IT_NOTEQUAL:
532 stackIdx--;
533 debug(9, "IT_NOTEQUAL: RESULT = %d", stack[stackIdx - 1] != stack[stackIdx]);
534 stack[stackIdx - 1] = (stack[stackIdx - 1] != stack[stackIdx]);
535 break;
536 case IT_ISEQUAL:
537 stackIdx--;
538 debug(9, "IT_ISEQUAL: RESULT = %d", stack[stackIdx - 1] == stack[stackIdx]);
539 stack[stackIdx - 1] = (stack[stackIdx - 1] == stack[stackIdx]);
540 break;
541 case IT_PLUS:
542 stackIdx--;
543 debug(9, "IT_PLUS: RESULT = %d", stack[stackIdx - 1] + stack[stackIdx]);
544 stack[stackIdx - 1] = (stack[stackIdx - 1] + stack[stackIdx]);
545 break;
546 case IT_TIMES:
547 stackIdx--;
548 debug(9, "IT_TIMES: RESULT = %d", stack[stackIdx - 1] * stack[stackIdx]);
549 stack[stackIdx - 1] = (stack[stackIdx - 1] * stack[stackIdx]);
550 break;
551 case IT_ANDAND:
552 stackIdx--;
553 debug(9, "IT_ANDAND: RESULT = %d", stack[stackIdx - 1] && stack[stackIdx]);
554 stack[stackIdx - 1] = (stack[stackIdx - 1] && stack[stackIdx]);
555 break;
556 case IT_OROR: // ||
557 stackIdx--;
558 debug(9, "IT_OROR: RESULT = %d", stack[stackIdx - 1] || stack[stackIdx]);
559 stack[stackIdx - 1] = (stack[stackIdx - 1] || stack[stackIdx]);
560 break;
561 case IT_LESSTHAN:
562 stackIdx--;
563 debug(9, "IT_LESSTHAN: RESULT = %d", stack[stackIdx - 1] < stack[stackIdx]);
564 stack[stackIdx - 1] = (stack[stackIdx - 1] < stack[stackIdx]);
565 break;
566 case IT_NOT:
567 debug(9, "IT_NOT: RESULT = %d", stack[stackIdx - 1] ? 0 : 1);
568 if (stack[stackIdx - 1])
569 stack[stackIdx - 1] = 0;
570 else
571 stack[stackIdx - 1] = 1;
572 break;
573 case IT_MINUS:
574 stackIdx--;
575 debug(9, "IT_MINUS: RESULT = %d", stack[stackIdx - 1] - stack[stackIdx]);
576 stack[stackIdx - 1] = (stack[stackIdx - 1] - stack[stackIdx]);
577 break;
578 case IT_AND:
579 stackIdx--;
580 debug(9, "IT_AND: RESULT = %d", stack[stackIdx - 1] & stack[stackIdx]);
581 stack[stackIdx - 1] = (stack[stackIdx - 1] & stack[stackIdx]);
582 break;
583 case IT_OR:
584 stackIdx--;
585 debug(9, "IT_OR: RESULT = %d", stack[stackIdx - 1] | stack[stackIdx]);
586 stack[stackIdx - 1] = (stack[stackIdx - 1] | stack[stackIdx]);
587 break;
588 case IT_GTE:
589 stackIdx--;
590 debug(9, "IT_GTE: RESULT = %d", stack[stackIdx - 1] >= stack[stackIdx]);
591 stack[stackIdx - 1] = (stack[stackIdx - 1] >= stack[stackIdx]);
592 break;
593 case IT_LTE:
594 stackIdx--;
595 debug(9, "IT_LTE: RESULT = %d", stack[stackIdx - 1] <= stack[stackIdx]);
596 stack[stackIdx - 1] = (stack[stackIdx - 1] <= stack[stackIdx]);
597 break;
598 case IT_DEVIDE:
599 stackIdx--;
600 debug(9, "IT_DEVIDE: RESULT = %d", stack[stackIdx - 1] / stack[stackIdx]);
601 stack[stackIdx - 1] = (stack[stackIdx - 1] / stack[stackIdx]);
602 break;
603 case IT_GT:
604 stackIdx--;
605 debug(9, "IT_GT: RESULT = %d", stack[stackIdx - 1] > stack[stackIdx]);
606 stack[stackIdx - 1] = (stack[stackIdx - 1] > stack[stackIdx]);
607 break;
608 case IT_SCRIPTEND:
609 debug(9, "IT_SCRIPTEND");
610 return 0;
611 case IT_POPVAR: // pop a variable
612 debug(9, "IT_POPVAR: ScriptVars[%d] = %d", scriptCode[pc], stack[stackIdx - 1]);
613 varNum = scriptCode[pc++];
614 if (SwordEngine::_systemVars.isDemo && SwordEngine::isWindows()) {
615 if (varNum >= 397) // BS1 Demo has different number of script variables
616 varNum++;
617 if (varNum >= 699)
618 varNum++;
619 }
620 _scriptVars[varNum] = stack[--stackIdx];
621 break;
622 case IT_POPLONGOFFSET:
623 offset = scriptCode[pc++];
624 debug(9, "IT_POPLONGOFFSET: Cpt[%d] = %d", offset, stack[stackIdx - 1]);
625 *((int32 *)((uint8 *)compact + offset)) = stack[--stackIdx];
626 break;
627 case IT_PUSHLONGOFFSET:
628 offset = scriptCode[pc++];
629 debug(9, "IT_PUSHLONGOFFSET: PUSH Cpt[%d] (==%d)", offset, *((int32 *)((uint8 *)compact + offset)));
630 stack[stackIdx++] = *((int32 *)((uint8 *)compact + offset));
631 break;
632 case IT_SKIPONFALSE:
633 debug(9, "IT_SKIPONFALSE: %d (%s)", scriptCode[pc], (stack[stackIdx - 1] ? "IS TRUE (NOT SKIPPED)" : "IS FALSE (SKIPPED)"));
634 if (stack[--stackIdx])
635 pc++;
636 else
637 pc += scriptCode[pc];
638 break;
639 case IT_SKIP:
640 debug(9, "IT_SKIP: %d", scriptCode[pc]);
641 pc += scriptCode[pc];
642 break;
643 case IT_SWITCH: // The mega switch statement
644 debug(9, "IT_SWITCH: [SORRY, NO DEBUG INFO]");
645 {
646 int switchValue = stack[--stackIdx];
647 int switchCount = scriptCode[pc++];
648 int doneSwitch = 0;
649
650 for (int cnt = 0; (cnt < switchCount) && (doneSwitch == 0); cnt++) {
651 if (switchValue == scriptCode[pc]) {
652 pc += scriptCode[pc + 1];
653 doneSwitch = 1;
654 } else
655 pc += 2;
656 }
657 if (doneSwitch == 0)
658 pc += scriptCode[pc];
659 }
660 break;
661 case IT_SKIPONTRUE: // skip if expression true
662 debug(9, "IT_SKIPONTRUE: %d (%s)", scriptCode[pc], (stack[stackIdx - 1] ? "IS TRUE (SKIPPED)" : "IS FALSE (NOT SKIPPED)"));
663 stackIdx--;
664 if (stack[stackIdx])
665 pc += scriptCode[pc];
666 else
667 pc++;
668 break;
669 case IT_PRINTF:
670 debug(0, "IT_PRINTF(%d)", stack[stackIdx]);
671 break;
672 case IT_RESTARTSCRIPT:
673 debug(9, "IT_RESTARTSCRIPT");
674 pc = startOfScript;
675 break;
676 case IT_POPWORDOFFSET:
677 offset = scriptCode[pc++];
678 debug(9, "IT_POPWORDOFFSET: Cpt[%d] = %d", offset, stack[stackIdx - 1] & 0xFFFF);
679 *((int32 *)((uint8 *)compact + offset)) = stack[--stackIdx] & 0xffff;
680 break;
681 case IT_PUSHWORDOFFSET:
682 offset = scriptCode[pc++];
683 debug(9, "IT_PUSHWORDOFFSET: PUSH Cpt[%d] == %d", offset, (*((int32 *)((uint8 *)compact + offset))) & 0xffff);
684 stack[stackIdx++] = (*((int32 *)((uint8 *)compact + offset))) & 0xffff;
685 break;
686 default:
687 error("Invalid operator %d", scriptCode[pc - 1]);
688 return 0; // for compilers that don't support NORETURN
689 }
690 }
691 }
692
setupMcodeTable()693 void Logic::setupMcodeTable() {
694 static const BSMcodeTable mcodeTable[100] = {
695 &Logic::fnBackground,
696 &Logic::fnForeground,
697 &Logic::fnSort,
698 &Logic::fnNoSprite,
699 &Logic::fnMegaSet,
700 &Logic::fnAnim,
701 &Logic::fnSetFrame,
702 &Logic::fnFullAnim,
703 &Logic::fnFullSetFrame,
704 &Logic::fnFadeDown,
705 &Logic::fnFadeUp,
706 &Logic::fnCheckFade,
707 &Logic::fnSetSpritePalette,
708 &Logic::fnSetWholePalette,
709 &Logic::fnSetFadeTargetPalette,
710 &Logic::fnSetPaletteToFade,
711 &Logic::fnSetPaletteToCut,
712 &Logic::fnPlaySequence,
713 &Logic::fnIdle,
714 &Logic::fnPause,
715 &Logic::fnPauseSeconds,
716 &Logic::fnQuit,
717 &Logic::fnKillId,
718 &Logic::fnSuicide,
719 &Logic::fnNewScript,
720 &Logic::fnSubScript,
721 &Logic::fnRestartScript,
722 &Logic::fnSetBookmark,
723 &Logic::fnGotoBookmark,
724 &Logic::fnSendSync,
725 &Logic::fnWaitSync,
726 &Logic::cfnClickInteract,
727 &Logic::cfnSetScript,
728 &Logic::cfnPresetScript,
729 &Logic::fnInteract,
730 &Logic::fnIssueEvent,
731 &Logic::fnCheckForEvent,
732 &Logic::fnWipeHands,
733 &Logic::fnISpeak,
734 &Logic::fnTheyDo,
735 &Logic::fnTheyDoWeWait,
736 &Logic::fnWeWait,
737 &Logic::fnChangeSpeechText,
738 &Logic::fnTalkError,
739 &Logic::fnStartTalk,
740 &Logic::fnCheckForTextLine,
741 &Logic::fnAddTalkWaitStatusBit,
742 &Logic::fnRemoveTalkWaitStatusBit,
743 &Logic::fnNoHuman,
744 &Logic::fnAddHuman,
745 &Logic::fnBlankMouse,
746 &Logic::fnNormalMouse,
747 &Logic::fnLockMouse,
748 &Logic::fnUnlockMouse,
749 &Logic::fnSetMousePointer,
750 &Logic::fnSetMouseLuggage,
751 &Logic::fnMouseOn,
752 &Logic::fnMouseOff,
753 &Logic::fnChooser,
754 &Logic::fnEndChooser,
755 &Logic::fnStartMenu,
756 &Logic::fnEndMenu,
757 &Logic::cfnReleaseMenu,
758 &Logic::fnAddSubject,
759 &Logic::fnAddObject,
760 &Logic::fnRemoveObject,
761 &Logic::fnEnterSection,
762 &Logic::fnLeaveSection,
763 &Logic::fnChangeFloor,
764 &Logic::fnWalk,
765 &Logic::fnTurn,
766 &Logic::fnStand,
767 &Logic::fnStandAt,
768 &Logic::fnFace,
769 &Logic::fnFaceXy,
770 &Logic::fnIsFacing,
771 &Logic::fnGetTo,
772 &Logic::fnGetToError,
773 &Logic::fnGetPos,
774 &Logic::fnGetGamepadXy,
775 &Logic::fnPlayFx,
776 &Logic::fnStopFx,
777 &Logic::fnPlayMusic,
778 &Logic::fnStopMusic,
779 &Logic::fnInnerSpace,
780 &Logic::fnRandom,
781 &Logic::fnSetScreen,
782 &Logic::fnPreload,
783 &Logic::fnCheckCD,
784 &Logic::fnRestartGame,
785 &Logic::fnQuitGame,
786 &Logic::fnDeathScreen,
787 &Logic::fnSetParallax,
788 &Logic::fnTdebug,
789 &Logic::fnRedFlash,
790 &Logic::fnBlueFlash,
791 &Logic::fnYellow,
792 &Logic::fnGreen,
793 &Logic::fnPurple,
794 &Logic::fnBlack
795 };
796
797 _mcodeTable = mcodeTable;
798 }
799
fnBackground(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)800 int Logic::fnBackground(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
801
802 cpt->o_status &= ~(STAT_FORE | STAT_SORT);
803 cpt->o_status |= STAT_BACK;
804 return SCRIPT_CONT;
805 }
806
fnForeground(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)807 int Logic::fnForeground(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
808 cpt->o_status &= ~(STAT_BACK | STAT_SORT);
809 cpt->o_status |= STAT_FORE;
810 return SCRIPT_CONT;
811 }
812
fnSort(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)813 int Logic::fnSort(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
814 cpt->o_status &= ~(STAT_BACK | STAT_FORE);
815 cpt->o_status |= STAT_SORT;
816 return SCRIPT_CONT;
817 }
818
fnNoSprite(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)819 int Logic::fnNoSprite(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
820 cpt->o_status &= ~(STAT_BACK | STAT_FORE | STAT_SORT);
821 return SCRIPT_CONT;
822 }
823
fnMegaSet(Object * cpt,int32 id,int32 walk_data,int32 spr,int32 e,int32 f,int32 z,int32 x)824 int Logic::fnMegaSet(Object *cpt, int32 id, int32 walk_data, int32 spr, int32 e, int32 f, int32 z, int32 x) {
825 cpt->o_mega_resource = walk_data;
826 cpt->o_walk_resource = spr;
827 return SCRIPT_CONT;
828 }
829
fnAnim(Object * cpt,int32 id,int32 cdt,int32 spr,int32 e,int32 f,int32 z,int32 x)830 int Logic::fnAnim(Object *cpt, int32 id, int32 cdt, int32 spr, int32 e, int32 f, int32 z, int32 x) {
831 AnimSet *animTab;
832
833 if (cdt && (!spr)) {
834 animTab = (AnimSet *)((uint8 *)_resMan->openFetchRes(cdt) + sizeof(Header));
835 animTab += cpt->o_dir;
836
837 cpt->o_anim_resource = _resMan->getUint32(animTab->cdt);
838 cpt->o_resource = _resMan->getUint32(animTab->spr);
839 _resMan->resClose(cdt);
840 } else {
841 cpt->o_anim_resource = cdt;
842 cpt->o_resource = spr;
843 }
844 if ((cpt->o_anim_resource == 0) || (cpt->o_resource == 0))
845 error("fnAnim called width (%d/%d) => (%d/%d)", cdt, spr, cpt->o_anim_resource, cpt->o_resource);
846
847 FrameHeader *frameHead = _resMan->fetchFrame(_resMan->openFetchRes(cpt->o_resource), 0);
848 if (frameHead->offsetX || frameHead->offsetY) { // boxed mega anim?
849 cpt->o_status |= STAT_SHRINK;
850 cpt->o_anim_x = cpt->o_xcoord; // set anim coords to 'feet' coords - only need to do this once
851 cpt->o_anim_y = cpt->o_ycoord;
852 } else {
853 // Anim_driver sets anim coords to cdt coords for every frame of a loose anim
854 cpt->o_status &= ~STAT_SHRINK;
855 }
856 _resMan->resClose(cpt->o_resource);
857
858 cpt->o_logic = LOGIC_anim;
859 cpt->o_anim_pc = 0;
860 cpt->o_sync = 0;
861 return SCRIPT_STOP;
862 }
863
fnSetFrame(Object * cpt,int32 id,int32 cdt,int32 spr,int32 frameNo,int32 f,int32 z,int32 x)864 int Logic::fnSetFrame(Object *cpt, int32 id, int32 cdt, int32 spr, int32 frameNo, int32 f, int32 z, int32 x) {
865
866 AnimUnit *animPtr;
867
868 uint8 *data = (uint8 *)_resMan->openFetchRes(cdt);
869 data += sizeof(Header);
870 if (frameNo == LAST_FRAME)
871 frameNo = _resMan->readUint32(data) - 1;
872
873 data += 4;
874 animPtr = (AnimUnit *)(data + frameNo * sizeof(AnimUnit));
875
876 cpt->o_anim_x = _resMan->getUint32(animPtr->animX);
877 cpt->o_anim_y = _resMan->getUint32(animPtr->animY);
878 cpt->o_frame = _resMan->getUint32(animPtr->animFrame);
879
880 cpt->o_resource = spr;
881 cpt->o_status &= ~STAT_SHRINK;
882 _resMan->resClose(cdt);
883 return SCRIPT_CONT;
884 }
885
fnFullAnim(Object * cpt,int32 id,int32 anim,int32 graphic,int32 e,int32 f,int32 z,int32 x)886 int Logic::fnFullAnim(Object *cpt, int32 id, int32 anim, int32 graphic, int32 e, int32 f, int32 z, int32 x) {
887 cpt->o_logic = LOGIC_full_anim;
888
889 cpt->o_anim_pc = 0;
890 cpt->o_anim_resource = anim;
891 cpt->o_resource = graphic;
892 cpt->o_status &= ~STAT_SHRINK;
893 cpt->o_sync = 0;
894 return SCRIPT_STOP;
895 }
896
fnFullSetFrame(Object * cpt,int32 id,int32 cdt,int32 spr,int32 frameNo,int32 f,int32 z,int32 x)897 int Logic::fnFullSetFrame(Object *cpt, int32 id, int32 cdt, int32 spr, int32 frameNo, int32 f, int32 z, int32 x) {
898 uint8 *data = (uint8 *)_resMan->openFetchRes(cdt) + sizeof(Header);
899
900 if (frameNo == LAST_FRAME)
901 frameNo = _resMan->readUint32(data) - 1;
902 data += 4;
903
904 AnimUnit *animPtr = (AnimUnit *)(data + sizeof(AnimUnit) * frameNo);
905 cpt->o_anim_x = cpt->o_xcoord = _resMan->getUint32(animPtr->animX);
906 cpt->o_anim_y = cpt->o_ycoord = _resMan->getUint32(animPtr->animY);
907 cpt->o_frame = _resMan->getUint32(animPtr->animFrame);
908
909 cpt->o_resource = spr;
910 cpt->o_status &= ~STAT_SHRINK;
911
912 _resMan->resClose(cdt);
913 return SCRIPT_CONT;
914 }
915
fnFadeDown(Object * cpt,int32 id,int32 speed,int32 d,int32 e,int32 f,int32 z,int32 x)916 int Logic::fnFadeDown(Object *cpt, int32 id, int32 speed, int32 d, int32 e, int32 f, int32 z, int32 x) {
917 _screen->fadeDownPalette();
918 return SCRIPT_CONT;
919 }
920
fnFadeUp(Object * cpt,int32 id,int32 speed,int32 d,int32 e,int32 f,int32 z,int32 x)921 int Logic::fnFadeUp(Object *cpt, int32 id, int32 speed, int32 d, int32 e, int32 f, int32 z, int32 x) {
922 _screen->fadeUpPalette();
923 return SCRIPT_CONT;
924 }
925
fnCheckFade(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)926 int Logic::fnCheckFade(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
927 _scriptVars[RETURN_VALUE] = (uint8)_screen->stillFading();
928 return SCRIPT_CONT;
929 }
930
fnSetSpritePalette(Object * cpt,int32 id,int32 spritePal,int32 d,int32 e,int32 f,int32 z,int32 x)931 int Logic::fnSetSpritePalette(Object *cpt, int32 id, int32 spritePal, int32 d, int32 e, int32 f, int32 z, int32 x) {
932 _screen->fnSetPalette(184, 72, spritePal, false);
933 return SCRIPT_CONT;
934 }
935
fnSetWholePalette(Object * cpt,int32 id,int32 spritePal,int32 d,int32 e,int32 f,int32 z,int32 x)936 int Logic::fnSetWholePalette(Object *cpt, int32 id, int32 spritePal, int32 d, int32 e, int32 f, int32 z, int32 x) {
937 _screen->fnSetPalette(0, 256, spritePal, false);
938 return SCRIPT_CONT;
939 }
940
fnSetFadeTargetPalette(Object * cpt,int32 id,int32 spritePal,int32 d,int32 e,int32 f,int32 z,int32 x)941 int Logic::fnSetFadeTargetPalette(Object *cpt, int32 id, int32 spritePal, int32 d, int32 e, int32 f, int32 z, int32 x) {
942 _screen->fnSetPalette(0, 184, spritePal, true);
943 return SCRIPT_CONT;
944 }
945
fnSetPaletteToFade(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)946 int Logic::fnSetPaletteToFade(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
947 SwordEngine::_systemVars.wantFade = true;
948 return SCRIPT_CONT;
949 }
950
fnSetPaletteToCut(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)951 int Logic::fnSetPaletteToCut(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
952 SwordEngine::_systemVars.wantFade = false;
953 return SCRIPT_CONT;
954 }
955
fnPlaySequence(Object * cpt,int32 id,int32 sequenceId,int32 d,int32 e,int32 f,int32 z,int32 x)956 int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int32 e, int32 f, int32 z, int32 x) {
957
958 // A cutscene usually (always?) means the room will change. In the
959 // meantime, we don't want any looping sound effects still playing.
960 _sound->quitScreen();
961
962 MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _resMan, _system);
963 if (player) {
964 _screen->clearScreen();
965 if (player->load(sequenceId))
966 player->play();
967 delete player;
968 }
969 return SCRIPT_CONT;
970 }
971
fnIdle(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)972 int Logic::fnIdle(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
973 cpt->o_tree.o_script_level = 0; // force to level 0
974 cpt->o_logic = LOGIC_idle;
975 return SCRIPT_STOP;
976 }
977
fnPause(Object * cpt,int32 id,int32 pause,int32 d,int32 e,int32 f,int32 z,int32 x)978 int Logic::fnPause(Object *cpt, int32 id, int32 pause, int32 d, int32 e, int32 f, int32 z, int32 x) {
979 cpt->o_pause = pause;
980 cpt->o_logic = LOGIC_pause;
981 return SCRIPT_STOP;
982 }
983
fnPauseSeconds(Object * cpt,int32 id,int32 pause,int32 d,int32 e,int32 f,int32 z,int32 x)984 int Logic::fnPauseSeconds(Object *cpt, int32 id, int32 pause, int32 d, int32 e, int32 f, int32 z, int32 x) {
985 cpt->o_pause = pause * FRAME_RATE;
986 cpt->o_logic = LOGIC_pause;
987 return SCRIPT_STOP;
988 }
989
fnQuit(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)990 int Logic::fnQuit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
991 cpt->o_logic = LOGIC_quit;
992 return SCRIPT_STOP;
993 }
994
fnKillId(Object * cpt,int32 id,int32 target,int32 d,int32 e,int32 f,int32 z,int32 x)995 int Logic::fnKillId(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
996 Object *targetObj = _objMan->fetchObject(target);
997 targetObj->o_status = 0;
998 return SCRIPT_CONT;
999 }
1000
fnSuicide(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1001 int Logic::fnSuicide(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1002 cpt->o_status = 0;
1003 cpt->o_logic = LOGIC_quit;
1004 return SCRIPT_STOP;
1005 }
1006
fnNewScript(Object * cpt,int32 id,int32 script,int32 d,int32 e,int32 f,int32 z,int32 x)1007 int Logic::fnNewScript(Object *cpt, int32 id, int32 script, int32 d, int32 e, int32 f, int32 z, int32 x) {
1008 cpt->o_logic = LOGIC_new_script;
1009 _newScript = script;
1010 return SCRIPT_STOP;
1011 }
1012
fnSubScript(Object * cpt,int32 id,int32 script,int32 d,int32 e,int32 f,int32 z,int32 x)1013 int Logic::fnSubScript(Object *cpt, int32 id, int32 script, int32 d, int32 e, int32 f, int32 z, int32 x) {
1014 cpt->o_tree.o_script_level++;
1015 if (cpt->o_tree.o_script_level == TOTAL_script_levels)
1016 error("Compact %d: script level exceeded in fnSubScript", id);
1017 cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = script;
1018 cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = script;
1019 return SCRIPT_STOP;
1020 }
1021
fnRestartScript(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1022 int Logic::fnRestartScript(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1023 cpt->o_logic = LOGIC_restart;
1024 return SCRIPT_STOP;
1025 }
1026
fnSetBookmark(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1027 int Logic::fnSetBookmark(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1028 memcpy(&cpt->o_bookmark.o_script_level, &cpt->o_tree.o_script_level, sizeof(ScriptTree));
1029 return SCRIPT_CONT;
1030 }
1031
fnGotoBookmark(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1032 int Logic::fnGotoBookmark(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1033 cpt->o_logic = LOGIC_bookmark;
1034 return SCRIPT_STOP;
1035 }
1036
fnSendSync(Object * cpt,int32 id,int32 sendId,int32 syncValue,int32 e,int32 f,int32 z,int32 x)1037 int Logic::fnSendSync(Object *cpt, int32 id, int32 sendId, int32 syncValue, int32 e, int32 f, int32 z, int32 x) {
1038 Object *target = _objMan->fetchObject(sendId);
1039 target->o_sync = syncValue;
1040 return SCRIPT_CONT;
1041 }
1042
fnWaitSync(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1043 int Logic::fnWaitSync(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1044 cpt->o_logic = LOGIC_wait_for_sync;
1045 return SCRIPT_STOP;
1046 }
1047
cfnClickInteract(Object * cpt,int32 id,int32 target,int32 d,int32 e,int32 f,int32 z,int32 x)1048 int Logic::cfnClickInteract(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
1049 Object *tar = _objMan->fetchObject(target);
1050 cpt = _objMan->fetchObject(PLAYER);
1051 cpt->o_tree.o_script_level = 0;
1052 cpt->o_tree.o_script_pc[0] = tar->o_interact;
1053 cpt->o_tree.o_script_id[0] = tar->o_interact;
1054 cpt->o_logic = LOGIC_script;
1055 return SCRIPT_STOP;
1056 }
1057
cfnSetScript(Object * cpt,int32 id,int32 target,int32 script,int32 e,int32 f,int32 z,int32 x)1058 int Logic::cfnSetScript(Object *cpt, int32 id, int32 target, int32 script, int32 e, int32 f, int32 z, int32 x) {
1059 Object *tar = _objMan->fetchObject(target);
1060 tar->o_tree.o_script_level = 0;
1061 tar->o_tree.o_script_pc[0] = script;
1062 tar->o_tree.o_script_id[0] = script;
1063 tar->o_logic = LOGIC_script;
1064 return SCRIPT_CONT;
1065 }
1066
cfnPresetScript(Object * cpt,int32 id,int32 target,int32 script,int32 e,int32 f,int32 z,int32 x)1067 int Logic::cfnPresetScript(Object *cpt, int32 id, int32 target, int32 script, int32 e, int32 f, int32 z, int32 x) {
1068 Object *tar = _objMan->fetchObject(target);
1069 tar->o_tree.o_script_level = 0;
1070 tar->o_tree.o_script_pc[0] = script;
1071 tar->o_tree.o_script_id[0] = script;
1072 if (tar->o_logic == LOGIC_idle)
1073 tar->o_logic = LOGIC_script;
1074 return SCRIPT_CONT;
1075 }
1076
fnInteract(Object * cpt,int32 id,int32 target,int32 d,int32 e,int32 f,int32 z,int32 x)1077 int Logic::fnInteract(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
1078 Object *tar = _objMan->fetchObject(target);
1079 cpt->o_place = tar->o_place;
1080
1081 Object *floorObject = _objMan->fetchObject(tar->o_place);
1082 cpt->o_scale_a = floorObject->o_scale_a;
1083 cpt->o_scale_b = floorObject->o_scale_b;
1084
1085 cpt->o_tree.o_script_level++;
1086 cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = tar->o_interact;
1087 cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = tar->o_interact;
1088
1089 return SCRIPT_STOP;
1090 }
1091
fnIssueEvent(Object * cpt,int32 id,int32 event,int32 delay,int32 e,int32 f,int32 z,int32 x)1092 int Logic::fnIssueEvent(Object *cpt, int32 id, int32 event, int32 delay, int32 e, int32 f, int32 z, int32 x) {
1093 _eventMan->fnIssueEvent(cpt, id, event, delay);
1094 return SCRIPT_CONT;
1095 }
1096
fnCheckForEvent(Object * cpt,int32 id,int32 pause,int32 d,int32 e,int32 f,int32 z,int32 x)1097 int Logic::fnCheckForEvent(Object *cpt, int32 id, int32 pause, int32 d, int32 e, int32 f, int32 z, int32 x) {
1098 return _eventMan->fnCheckForEvent(cpt, id, pause);
1099 }
1100
fnWipeHands(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1101 int Logic::fnWipeHands(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1102 _scriptVars[OBJECT_HELD] = 0;
1103 _mouse->setLuggage(0, 0);
1104 _menu->refresh(MENU_TOP);
1105 return SCRIPT_CONT;
1106 }
1107
fnISpeak(Object * cpt,int32 id,int32 cdt,int32 textNo,int32 spr,int32 f,int32 z,int32 x)1108 int Logic::fnISpeak(Object *cpt, int32 id, int32 cdt, int32 textNo, int32 spr, int32 f, int32 z, int32 x) {
1109 _speechClickDelay = 3;
1110 if (((textNo & ~1) == 0x3f0012) && (!cdt) && (!spr)) {
1111 cdt = GEOSTDLCDT; // workaround for missing animation when examining
1112 spr = GEOSTDL; // the conductor on the train roof
1113 }
1114 cpt->o_logic = LOGIC_speech;
1115
1116 // first setup the talk animation
1117 if (cdt && (!spr)) { // if 'cdt' is non-zero but 'spr' is zero - 'cdt' is an anim table tag
1118 AnimSet *animTab = (AnimSet *)((uint8 *)_resMan->openFetchRes(cdt) + sizeof(Header));
1119 animTab += cpt->o_dir;
1120
1121 cpt->o_anim_resource = _resMan->getUint32(animTab->cdt);
1122 if (animTab->cdt)
1123 cpt->o_resource = _resMan->getUint32(animTab->spr);
1124 _resMan->resClose(cdt);
1125 } else {
1126 cpt->o_anim_resource = cdt;
1127 if (cdt)
1128 cpt->o_resource = spr;
1129 }
1130 cpt->o_anim_pc = 0; // start anim from first frame
1131 if (cpt->o_anim_resource) {
1132 if (!cpt->o_resource)
1133 error("ID %d: Can't run anim with cdt=%d, spr=%d", id, cdt, spr);
1134
1135 FrameHeader *frameHead = _resMan->fetchFrame(_resMan->openFetchRes(cpt->o_resource), 0);
1136 if (frameHead->offsetX && frameHead->offsetY) { // is this a boxed mega?
1137 cpt->o_status |= STAT_SHRINK;
1138 cpt->o_anim_x = cpt->o_xcoord;
1139 cpt->o_anim_y = cpt->o_ycoord;
1140 } else
1141 cpt->o_status &= ~STAT_SHRINK;
1142
1143 _resMan->resClose(cpt->o_resource);
1144 }
1145 if (SwordEngine::_systemVars.playSpeech)
1146 _speechRunning = _sound->startSpeech(textNo >> 16, textNo & 0xFFFF);
1147 else
1148 _speechRunning = false;
1149 _speechFinished = false;
1150 if (SwordEngine::_systemVars.showText || (!_speechRunning)) {
1151 _textRunning = true;
1152
1153 char *text = _objMan->lockText(textNo);
1154 cpt->o_speech_time = strlen(text) + 5;
1155 uint32 textCptId = _textMan->lowTextManager((uint8 *)text, cpt->o_speech_width, (uint8)cpt->o_speech_pen);
1156 _objMan->unlockText(textNo);
1157
1158 Object *textCpt = _objMan->fetchObject(textCptId);
1159 textCpt->o_screen = cpt->o_screen;
1160 textCpt->o_target = textCptId;
1161
1162 // the graphic is a property of Text, so we don't lock/unlock it.
1163 uint16 textSpriteWidth = _resMan->getUint16(_textMan->giveSpriteData(textCpt->o_target)->width);
1164 uint16 textSpriteHeight = _resMan->getUint16(_textMan->giveSpriteData(textCpt->o_target)->height);
1165
1166 cpt->o_text_id = textCptId;
1167
1168 // now set text coords, above the player, usually
1169
1170 #define TEXT_MARGIN 3 // distance kept from edges of screen
1171 #define ABOVE_HEAD 20 // distance kept above talking sprite
1172 uint16 textX, textY;
1173 if (((id == GEORGE) || ((id == NICO) && (_scriptVars[SCREEN] == 10))) && (!cpt->o_anim_resource)) {
1174 // if George is doing Voice-Over text (centered at the bottom of the screen)
1175 textX = _scriptVars[SCROLL_OFFSET_X] + 128 + (640 / 2) - textSpriteWidth / 2;
1176 textY = _scriptVars[SCROLL_OFFSET_Y] + 128 + 400;
1177 } else {
1178 if ((id == GEORGE) && (_scriptVars[SCREEN] == 79))
1179 textX = cpt->o_mouse_x2; // move it off george's head
1180 else
1181 textX = (cpt->o_mouse_x1 + cpt->o_mouse_x2) / 2 - textSpriteWidth / 2;
1182
1183 textY = cpt->o_mouse_y1 - textSpriteHeight - ABOVE_HEAD;
1184 }
1185 // now ensure text is within visible screen
1186 uint16 textLeftMargin, textRightMargin, textTopMargin, textBottomMargin;
1187 textLeftMargin = SCREEN_LEFT_EDGE + TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_X];
1188 textRightMargin = SCREEN_RIGHT_EDGE - TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_X] - textSpriteWidth;
1189 textTopMargin = SCREEN_TOP_EDGE + TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_Y];
1190 textBottomMargin = SCREEN_BOTTOM_EDGE - TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_Y] - textSpriteHeight;
1191
1192 textCpt->o_anim_x = textCpt->o_xcoord = CLIP<uint16>(textX, textLeftMargin, textRightMargin);
1193 textCpt->o_anim_y = textCpt->o_ycoord = CLIP<uint16>(textY, textTopMargin, textBottomMargin);
1194 }
1195 return SCRIPT_STOP;
1196 }
1197
1198 //send instructions to mega in conversation with player
1199 //the instruction is interpreted by the script mega_interact
fnTheyDo(Object * cpt,int32 id,int32 tar,int32 instruc,int32 param1,int32 param2,int32 param3,int32 x)1200 int Logic::fnTheyDo(Object *cpt, int32 id, int32 tar, int32 instruc, int32 param1, int32 param2, int32 param3, int32 x) {
1201 Object *target;
1202 target = _objMan->fetchObject(tar);
1203 target->o_down_flag = instruc; // instruction for the mega
1204 target->o_ins1 = param1;
1205 target->o_ins2 = param2;
1206 target->o_ins3 = param3;
1207 return SCRIPT_CONT;
1208 }
1209
1210 //send an instruction to mega we're talking to and wait
1211 //until it has finished before returning to script
fnTheyDoWeWait(Object * cpt,int32 id,int32 tar,int32 instruc,int32 param1,int32 param2,int32 param3,int32 x)1212 int Logic::fnTheyDoWeWait(Object *cpt, int32 id, int32 tar, int32 instruc, int32 param1, int32 param2, int32 param3, int32 x) {
1213 // workaround for scriptbug #928791: Freeze at hospital
1214 // in at least one game version, a script forgets to set sam_returning back to zero
1215 if ((tar == SAM) && (instruc == INS_talk) && (param2 == 2162856))
1216 _scriptVars[SAM_RETURNING] = 0;
1217 Object *target = _objMan->fetchObject(tar);
1218 target->o_down_flag = instruc; // instruction for the mega
1219 target->o_ins1 = param1;
1220 target->o_ins2 = param2;
1221 target->o_ins3 = param3;
1222 target->o_status &= ~STAT_TALK_WAIT;
1223
1224 cpt->o_logic = LOGIC_wait_for_talk;
1225 cpt->o_down_flag = tar;
1226 return SCRIPT_STOP;
1227 }
1228
fnWeWait(Object * cpt,int32 id,int32 tar,int32 d,int32 e,int32 f,int32 z,int32 x)1229 int Logic::fnWeWait(Object *cpt, int32 id, int32 tar, int32 d, int32 e, int32 f, int32 z, int32 x) {
1230 Object *target = _objMan->fetchObject(tar);
1231 target->o_status &= ~STAT_TALK_WAIT;
1232
1233 cpt->o_logic = LOGIC_wait_for_talk;
1234 cpt->o_down_flag = tar;
1235
1236 return SCRIPT_STOP;
1237 }
1238
fnChangeSpeechText(Object * cpt,int32 id,int32 tar,int32 width,int32 pen,int32 f,int32 z,int32 x)1239 int Logic::fnChangeSpeechText(Object *cpt, int32 id, int32 tar, int32 width, int32 pen, int32 f, int32 z, int32 x) {
1240 Object *target = _objMan->fetchObject(tar);
1241 target->o_speech_width = width;
1242 target->o_speech_pen = pen;
1243 return SCRIPT_STOP;
1244 }
1245
1246 //mega_interact has received an instruction it does not understand -
1247 //The game is halted for debugging. Maybe we'll remove this later.
fnTalkError(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1248 int Logic::fnTalkError(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1249 error("fnTalkError for id %d, instruction %d", id, cpt->o_down_flag);
1250 return SCRIPT_STOP; // for compilers that don't support NORETURN
1251 }
1252
fnStartTalk(Object * cpt,int32 id,int32 target,int32 d,int32 e,int32 f,int32 z,int32 x)1253 int Logic::fnStartTalk(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
1254 cpt->o_down_flag = target;
1255 cpt->o_logic = LOGIC_start_talk;
1256 return SCRIPT_STOP;
1257 }
1258
fnCheckForTextLine(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1259 int Logic::fnCheckForTextLine(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1260 _scriptVars[RETURN_VALUE] = _objMan->fnCheckForTextLine(id);
1261 return SCRIPT_CONT;
1262 }
1263
fnAddTalkWaitStatusBit(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1264 int Logic::fnAddTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1265 cpt->o_status |= STAT_TALK_WAIT;
1266 return SCRIPT_CONT;
1267 }
1268
fnRemoveTalkWaitStatusBit(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1269 int Logic::fnRemoveTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1270 cpt->o_status &= ~STAT_TALK_WAIT;
1271 return SCRIPT_CONT;
1272 }
1273
fnNoHuman(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1274 int Logic::fnNoHuman(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1275 _mouse->fnNoHuman();
1276 return SCRIPT_CONT;
1277 }
1278
fnAddHuman(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1279 int Logic::fnAddHuman(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1280 _mouse->fnAddHuman();
1281 return SCRIPT_CONT;
1282 }
1283
fnBlankMouse(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1284 int Logic::fnBlankMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1285 _mouse->fnBlankMouse();
1286 return SCRIPT_CONT;
1287 }
1288
fnNormalMouse(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1289 int Logic::fnNormalMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1290 _mouse->fnNormalMouse();
1291 return SCRIPT_CONT;
1292 }
1293
fnLockMouse(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1294 int Logic::fnLockMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1295 _mouse->fnLockMouse();
1296 return SCRIPT_CONT;
1297 }
1298
fnUnlockMouse(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1299 int Logic::fnUnlockMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1300 _mouse->fnUnlockMouse();
1301 return SCRIPT_CONT;
1302 }
1303
fnSetMousePointer(Object * cpt,int32 id,int32 tag,int32 rate,int32 e,int32 f,int32 z,int32 x)1304 int Logic::fnSetMousePointer(Object *cpt, int32 id, int32 tag, int32 rate, int32 e, int32 f, int32 z, int32 x) {
1305 _mouse->setPointer(tag, rate);
1306 return SCRIPT_CONT;
1307 }
1308
fnSetMouseLuggage(Object * cpt,int32 id,int32 tag,int32 rate,int32 e,int32 f,int32 z,int32 x)1309 int Logic::fnSetMouseLuggage(Object *cpt, int32 id, int32 tag, int32 rate, int32 e, int32 f, int32 z, int32 x) {
1310 _mouse->setLuggage(tag, rate);
1311 return SCRIPT_CONT;
1312 }
1313
fnMouseOn(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1314 int Logic::fnMouseOn(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1315 cpt->o_status |= STAT_MOUSE;
1316 return SCRIPT_CONT;
1317 }
1318
fnMouseOff(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1319 int Logic::fnMouseOff(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1320 cpt->o_status &= ~STAT_MOUSE;
1321 return SCRIPT_CONT;
1322 }
1323
fnChooser(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1324 int Logic::fnChooser(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1325 _menu->fnChooser(cpt);
1326 return SCRIPT_STOP;
1327 }
1328
fnEndChooser(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1329 int Logic::fnEndChooser(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1330 _menu->fnEndChooser();
1331 return SCRIPT_CONT;
1332 }
1333
fnStartMenu(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1334 int Logic::fnStartMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1335 _menu->fnStartMenu();
1336 return SCRIPT_CONT;
1337 }
1338
fnEndMenu(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1339 int Logic::fnEndMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1340 _menu->fnEndMenu();
1341 return SCRIPT_CONT;
1342 }
1343
cfnReleaseMenu(Object * cpt,int32 id,int32 c,int32 d,int32 e,int32 f,int32 z,int32 x)1344 int Logic::cfnReleaseMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
1345 _menu->cfnReleaseMenu();
1346 return SCRIPT_STOP;
1347 }
1348
fnAddSubject(Object * cpt,int32 id,int32 sub,int32 d,int32 e,int32 f,int32 z,int32 x)1349 int Logic::fnAddSubject(Object *cpt, int32 id, int32 sub, int32 d, int32 e, int32 f, int32 z, int32 x) {
1350 _menu->fnAddSubject(sub);
1351 return SCRIPT_CONT;
1352 }
1353
fnAddObject(Object * cpt,int32 id,int32 objectNo,int32 d,int32 e,int32 f,int32 z,int32 x)1354 int Logic::fnAddObject(Object *cpt, int32 id, int32 objectNo, int32 d, int32 e, int32 f, int32 z, int32 x) {
1355 _scriptVars[POCKET_1 + objectNo - 1] = 1; // basically means: carrying object objectNo = true;
1356 return SCRIPT_CONT;
1357 }
1358
fnRemoveObject(Object * cpt,int32 id,int32 objectNo,int32 d,int32 e,int32 f,int32 z,int32 x)1359 int Logic::fnRemoveObject(Object *cpt, int32 id, int32 objectNo, int32 d, int32 e, int32 f, int32 z, int32 x) {
1360 _scriptVars[POCKET_1 + objectNo - 1] = 0;
1361 return SCRIPT_CONT;
1362 }
1363
fnEnterSection(Object * cpt,int32 id,int32 screen,int32 d,int32 e,int32 f,int32 z,int32 x)1364 int Logic::fnEnterSection(Object *cpt, int32 id, int32 screen, int32 d, int32 e, int32 f, int32 z, int32 x) {
1365 if (screen >= TOTAL_SECTIONS)
1366 error("mega %d tried entering section %d", id, screen);
1367
1368 /* if (cpt->o_type == TYPE_PLAYER)
1369 ^= this was the original condition from the game sourcecode.
1370 not sure why it doesn't work*/
1371 if (id == PLAYER)
1372 _scriptVars[NEW_SCREEN] = screen;
1373 else
1374 cpt->o_screen = screen; // move the mega
1375 _objMan->megaEntering(screen);
1376 return SCRIPT_CONT;
1377 }
1378
fnLeaveSection(Object * cpt,int32 id,int32 oldScreen,int32 d,int32 e,int32 f,int32 z,int32 x)1379 int Logic::fnLeaveSection(Object *cpt, int32 id, int32 oldScreen, int32 d, int32 e, int32 f, int32 z, int32 x) {
1380 if (oldScreen >= TOTAL_SECTIONS)
1381 error("mega %d leaving section %d", id, oldScreen);
1382 _objMan->megaLeaving(oldScreen, id);
1383 return SCRIPT_CONT;
1384 }
1385
fnChangeFloor(Object * cpt,int32 id,int32 floor,int32 d,int32 e,int32 f,int32 z,int32 x)1386 int Logic::fnChangeFloor(Object *cpt, int32 id, int32 floor, int32 d, int32 e, int32 f, int32 z, int32 x) {
1387 cpt->o_place = floor;
1388 Object *floorCpt = _objMan->fetchObject(floor);
1389 cpt->o_scale_a = floorCpt->o_scale_a;
1390 cpt->o_scale_b = floorCpt->o_scale_b;
1391 return SCRIPT_CONT;
1392 }
1393
fnWalk(Object * cpt,int32 id,int32 x,int32 y,int32 dir,int32 stance,int32 a,int32 b)1394 int Logic::fnWalk(Object *cpt, int32 id, int32 x, int32 y, int32 dir, int32 stance, int32 a, int32 b) {
1395 if (stance > 0)
1396 dir = 9;
1397 cpt->o_walk_pc = 0;
1398 cpt->o_route[1].frame = 512; // end of sequence
1399 if (id == PLAYER)
1400 _router->setPlayerTarget(x, y, dir, stance);
1401
1402 int32 routeRes = _router->routeFinder(id, cpt, x, y, dir);
1403
1404 if (id == PLAYER) {
1405 if ((routeRes == 1) || (routeRes == 2)) {
1406 _scriptVars[MEGA_ON_GRID] = 0;
1407 _scriptVars[REROUTE_GEORGE] = 0;
1408 }
1409 }
1410 if ((routeRes == 1) || (routeRes == 2)) {
1411 cpt->o_down_flag = 1; // 1 means okay.
1412 // if both mouse buttons were pressed on an exit => skip george's walk
1413 if ((id == GEORGE) && (_mouse->testEvent() == MOUSE_BOTH_BUTTONS)) {
1414 int32 target = _scriptVars[CLICK_ID];
1415 // exceptions: compacts that use hand pointers but are not actually exits
1416 if ((target != LEFT_SCROLL_POINTER) && (target != RIGHT_SCROLL_POINTER) &&
1417 (target != FLOOR_63) && (target != ROOF_63) && (target != GUARD_ROOF_63) &&
1418 (target != LEFT_TREE_POINTER_71) && (target != RIGHT_TREE_POINTER_71)) {
1419
1420 target = _objMan->fetchObject(_scriptVars[CLICK_ID])->o_mouse_on;
1421 if ((target >= SCR_exit0) && (target <= SCR_exit9)) {
1422 fnStandAt(cpt, id, x, y, dir, stance, 0, 0);
1423 return SCRIPT_STOP;
1424 }
1425 }
1426 }
1427 cpt->o_logic = LOGIC_AR_animate;
1428 return SCRIPT_STOP;
1429 } else if (routeRes == 3)
1430 cpt->o_down_flag = 1; // pretend it was successful
1431 else
1432 cpt->o_down_flag = 0; // 0 means error
1433
1434 return SCRIPT_CONT;
1435 }
1436
fnTurn(Object * cpt,int32 id,int32 dir,int32 stance,int32 c,int32 d,int32 a,int32 b)1437 int Logic::fnTurn(Object *cpt, int32 id, int32 dir, int32 stance, int32 c, int32 d, int32 a, int32 b) {
1438 if (stance > 0)
1439 dir = 9;
1440 int route = _router->routeFinder(id, cpt, cpt->o_xcoord, cpt->o_ycoord, dir);
1441
1442 if (route)
1443 cpt->o_down_flag = 1; //1 means ok
1444 else
1445 cpt->o_down_flag = 0; //0 means error
1446
1447 cpt->o_logic = LOGIC_AR_animate;
1448 cpt->o_walk_pc = 0; //reset
1449
1450 return SCRIPT_STOP;
1451 }
1452
fnStand(Object * cpt,int32 id,int32 dir,int32 stance,int32 c,int32 d,int32 a,int32 b)1453 int Logic::fnStand(Object *cpt, int32 id, int32 dir, int32 stance, int32 c, int32 d, int32 a, int32 b) {
1454 if ((dir < 0) || (dir > 8)) {
1455 warning("fnStand:: invalid direction %d", dir);
1456 return SCRIPT_CONT;
1457 }
1458 if (dir == 8)
1459 dir = cpt->o_dir;
1460 cpt->o_resource = cpt->o_walk_resource;
1461 cpt->o_status |= STAT_SHRINK;
1462 cpt->o_anim_x = cpt->o_xcoord;
1463 cpt->o_anim_y = cpt->o_ycoord;
1464 cpt->o_frame = 96 + dir;
1465 cpt->o_dir = dir;
1466 return SCRIPT_STOP;
1467 }
1468
fnStandAt(Object * cpt,int32 id,int32 x,int32 y,int32 dir,int32 stance,int32 a,int32 b)1469 int Logic::fnStandAt(Object *cpt, int32 id, int32 x, int32 y, int32 dir, int32 stance, int32 a, int32 b) {
1470 if ((dir < 0) || (dir > 8)) {
1471 warning("fnStandAt:: invalid direction %d", dir);
1472 return SCRIPT_CONT;
1473 }
1474 if (dir == 8)
1475 dir = cpt->o_dir;
1476 cpt->o_xcoord = x;
1477 cpt->o_ycoord = y;
1478 return fnStand(cpt, id, dir, stance, 0, 0, 0, 0);
1479 }
1480
fnFace(Object * cpt,int32 id,int32 targetId,int32 b,int32 c,int32 d,int32 a,int32 z)1481 int Logic::fnFace(Object *cpt, int32 id, int32 targetId, int32 b, int32 c, int32 d, int32 a, int32 z) {
1482 Object *target = _objMan->fetchObject(targetId);
1483 int32 x, y;
1484 if ((target->o_type == TYPE_MEGA) || (target->o_type == TYPE_PLAYER)) {
1485 x = target->o_xcoord;
1486 y = target->o_ycoord;
1487 } else {
1488 x = (target->o_mouse_x1 + target->o_mouse_x2) / 2;
1489 y = target->o_mouse_y2;
1490 }
1491 int32 megaTarDir = whatTarget(cpt->o_xcoord, cpt->o_ycoord, x, y);
1492 fnTurn(cpt, id, megaTarDir, 0, 0, 0, 0, 0);
1493 return SCRIPT_STOP;
1494 }
1495
fnFaceXy(Object * cpt,int32 id,int32 x,int32 y,int32 c,int32 d,int32 a,int32 b)1496 int Logic::fnFaceXy(Object *cpt, int32 id, int32 x, int32 y, int32 c, int32 d, int32 a, int32 b) {
1497 int megaTarDir = whatTarget(cpt->o_xcoord, cpt->o_ycoord, x, y);
1498 fnTurn(cpt, id, megaTarDir, 0, 0, 0, 0, 0);
1499 return SCRIPT_STOP;
1500 }
1501
fnIsFacing(Object * cpt,int32 id,int32 targetId,int32 b,int32 c,int32 d,int32 a,int32 z)1502 int Logic::fnIsFacing(Object *cpt, int32 id, int32 targetId, int32 b, int32 c, int32 d, int32 a, int32 z) {
1503 Object *target = _objMan->fetchObject(targetId);
1504 int32 x, y, dir;
1505 if ((target->o_type == TYPE_MEGA) || (target->o_type == TYPE_PLAYER)) {
1506 x = target->o_xcoord;
1507 y = target->o_ycoord;
1508 dir = target->o_dir;
1509 } else
1510 error("fnIsFacing:: Target isn't a mega");
1511
1512 int32 lookDir = whatTarget(x, y, cpt->o_xcoord, cpt->o_ycoord);
1513 lookDir -= dir;
1514 lookDir = ABS(lookDir);
1515
1516 if (lookDir > 4)
1517 lookDir = 8 - lookDir;
1518
1519 _scriptVars[RETURN_VALUE] = lookDir;
1520 return SCRIPT_STOP;
1521 }
1522
fnGetTo(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1523 int Logic::fnGetTo(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1524 Object *place = _objMan->fetchObject(cpt->o_place);
1525
1526 cpt->o_tree.o_script_level++;
1527 cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = place->o_get_to_script;
1528 cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = place->o_get_to_script;
1529 return SCRIPT_STOP;
1530 }
1531
fnGetToError(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1532 int Logic::fnGetToError(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1533 debug(1, "fnGetToError: compact %d at place %d no get-to for target %d, click_id %d\n", id, cpt->o_place, cpt->o_target, _scriptVars[CLICK_ID]);
1534 return SCRIPT_CONT;
1535 }
1536
fnRandom(Object * compact,int32 id,int32 min,int32 max,int32 e,int32 f,int32 z,int32 x)1537 int Logic::fnRandom(Object *compact, int32 id, int32 min, int32 max, int32 e, int32 f, int32 z, int32 x) {
1538 _scriptVars[RETURN_VALUE] = _rnd.getRandomNumberRng(min, max);
1539 return SCRIPT_CONT;
1540 }
1541
fnGetPos(Object * cpt,int32 id,int32 targetId,int32 b,int32 c,int32 d,int32 z,int32 x)1542 int Logic::fnGetPos(Object *cpt, int32 id, int32 targetId, int32 b, int32 c, int32 d, int32 z, int32 x) {
1543 Object *target = _objMan->fetchObject(targetId);
1544 if ((target->o_type == TYPE_MEGA) || (target->o_type == TYPE_PLAYER)) {
1545 _scriptVars[RETURN_VALUE] = target->o_xcoord;
1546 _scriptVars[RETURN_VALUE_2] = target->o_ycoord;
1547 } else {
1548 _scriptVars[RETURN_VALUE] = (target->o_mouse_x1 + target->o_mouse_x2) / 2;
1549 _scriptVars[RETURN_VALUE_2] = target->o_mouse_y2;
1550 }
1551 _scriptVars[RETURN_VALUE_3] = target->o_dir;
1552
1553 int32 megaSeperation;
1554 if (targetId == DUANE)
1555 megaSeperation = 70; // George & Duane stand with feet 70 pixels apart when at full scale
1556 else if (targetId == BENOIR)
1557 megaSeperation = 61; // George & Benoir
1558 else
1559 megaSeperation = 42; // George & Nico/Goinfre stand with feet 42 pixels apart when at full scale
1560
1561 if (target->o_status & STAT_SHRINK) {
1562 int32 scale = (target->o_scale_a * target->o_ycoord + target->o_scale_b) / 256;
1563 _scriptVars[RETURN_VALUE_4] = (megaSeperation * scale) / 256;
1564 } else
1565 _scriptVars[RETURN_VALUE_4] = megaSeperation;
1566 return SCRIPT_CONT;
1567 }
1568
fnGetGamepadXy(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1569 int Logic::fnGetGamepadXy(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1570 // playstation only
1571 return SCRIPT_CONT;
1572 }
1573
fnPlayFx(Object * cpt,int32 id,int32 fxNo,int32 b,int32 c,int32 d,int32 z,int32 x)1574 int Logic::fnPlayFx(Object *cpt, int32 id, int32 fxNo, int32 b, int32 c, int32 d, int32 z, int32 x) {
1575 _scriptVars[RETURN_VALUE] = _sound->addToQueue(fxNo);
1576 return SCRIPT_CONT;
1577 }
1578
fnStopFx(Object * cpt,int32 id,int32 fxNo,int32 b,int32 c,int32 d,int32 z,int32 x)1579 int Logic::fnStopFx(Object *cpt, int32 id, int32 fxNo, int32 b, int32 c, int32 d, int32 z, int32 x) {
1580 _sound->fnStopFx(fxNo);
1581 //_sound->removeFromQueue(fxNo);
1582 return SCRIPT_CONT;
1583 }
1584
fnPlayMusic(Object * cpt,int32 id,int32 tuneId,int32 loopFlag,int32 c,int32 d,int32 z,int32 x)1585 int Logic::fnPlayMusic(Object *cpt, int32 id, int32 tuneId, int32 loopFlag, int32 c, int32 d, int32 z, int32 x) {
1586 if (tuneId == 153)
1587 return SCRIPT_CONT;
1588 if (loopFlag == LOOPED)
1589 _scriptVars[CURRENT_MUSIC] = tuneId; // so it gets restarted when saving & reloading
1590 else
1591 _scriptVars[CURRENT_MUSIC] = 0;
1592
1593 _music->startMusic(tuneId, loopFlag);
1594 return SCRIPT_CONT;
1595 }
1596
fnStopMusic(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1597 int Logic::fnStopMusic(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1598 _scriptVars[CURRENT_MUSIC] = 0;
1599 _music->fadeDown();
1600 return SCRIPT_CONT;
1601 }
1602
fnInnerSpace(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1603 int Logic::fnInnerSpace(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1604 error("fnInnerSpace() not working");
1605 return SCRIPT_STOP; // for compilers that don't support NORETURN
1606 }
1607
fnSetScreen(Object * cpt,int32 id,int32 target,int32 screen,int32 c,int32 d,int32 z,int32 x)1608 int Logic::fnSetScreen(Object *cpt, int32 id, int32 target, int32 screen, int32 c, int32 d, int32 z, int32 x) {
1609 _objMan->fetchObject(target)->o_screen = screen;
1610 return SCRIPT_CONT;
1611 }
1612
fnPreload(Object * cpt,int32 id,int32 resId,int32 b,int32 c,int32 d,int32 z,int32 x)1613 int Logic::fnPreload(Object *cpt, int32 id, int32 resId, int32 b, int32 c, int32 d, int32 z, int32 x) {
1614 _resMan->resOpen(resId);
1615 _resMan->resClose(resId);
1616 return SCRIPT_CONT;
1617 }
1618
fnCheckCD(Object * cpt,int32 id,int32 screen,int32 b,int32 c,int32 d,int32 z,int32 x)1619 int Logic::fnCheckCD(Object *cpt, int32 id, int32 screen, int32 b, int32 c, int32 d, int32 z, int32 x) {
1620 // only a dummy, here.
1621 // the check is done in the mainloop
1622 return SCRIPT_CONT;
1623 }
1624
fnRestartGame(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1625 int Logic::fnRestartGame(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1626 SwordEngine::_systemVars.forceRestart = true;
1627 cpt->o_logic = LOGIC_quit;
1628 return SCRIPT_STOP;
1629 }
1630
fnQuitGame(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1631 int Logic::fnQuitGame(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1632 if (SwordEngine::_systemVars.isDemo) {
1633 GUI::MessageDialog dialog(_("This is the end of the Broken Sword 1 Demo"), _("OK"), NULL);
1634 dialog.runModal();
1635 Engine::quitGame();
1636 } else
1637 error("fnQuitGame() called");
1638 return fnQuit(cpt, id, 0, 0, 0, 0, 0, 0);
1639 }
1640
fnDeathScreen(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1641 int Logic::fnDeathScreen(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1642
1643 if (_scriptVars[FINALE_OPTION_FLAG] == 4) // successful end of game!
1644 SwordEngine::_systemVars.controlPanelMode = CP_THEEND;
1645 else
1646 SwordEngine::_systemVars.controlPanelMode = CP_DEATHSCREEN;
1647
1648 cpt->o_logic = LOGIC_quit;
1649 return SCRIPT_STOP;
1650 }
1651
fnSetParallax(Object * cpt,int32 id,int32 screen,int32 resId,int32 c,int32 d,int32 z,int32 x)1652 int Logic::fnSetParallax(Object *cpt, int32 id, int32 screen, int32 resId, int32 c, int32 d, int32 z, int32 x) {
1653 _screen->fnSetParallax(screen, resId);
1654 return SCRIPT_CONT;
1655 }
1656
fnTdebug(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1657 int Logic::fnTdebug(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1658 debug(1, "Script TDebug id %d code %d, %d", id, a, b);
1659 return SCRIPT_CONT;
1660 }
1661
fnRedFlash(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1662 int Logic::fnRedFlash(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1663 _screen->fnFlash(FLASH_RED);
1664 return SCRIPT_CONT;
1665 }
1666
fnBlueFlash(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1667 int Logic::fnBlueFlash(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1668 _screen->fnFlash(FLASH_BLUE);
1669 return SCRIPT_CONT;
1670 }
1671
fnYellow(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1672 int Logic::fnYellow(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1673 _screen->fnFlash(BORDER_YELLOW);
1674 return SCRIPT_CONT;
1675 }
1676
fnGreen(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1677 int Logic::fnGreen(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1678 _screen->fnFlash(BORDER_GREEN);
1679 return SCRIPT_CONT;
1680 }
1681
fnPurple(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1682 int Logic::fnPurple(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1683 _screen->fnFlash(BORDER_PURPLE);
1684 return SCRIPT_CONT;
1685 }
1686
fnBlack(Object * cpt,int32 id,int32 a,int32 b,int32 c,int32 d,int32 z,int32 x)1687 int Logic::fnBlack(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
1688 _screen->fnFlash(BORDER_BLACK);
1689 return SCRIPT_CONT;
1690 }
1691
startPosCallFn(uint8 fnId,uint32 param1,uint32 param2,uint32 param3)1692 void Logic::startPosCallFn(uint8 fnId, uint32 param1, uint32 param2, uint32 param3) {
1693 Object *obj = NULL;
1694 switch (fnId) {
1695 case opcPlaySequence:
1696 fnPlaySequence(NULL, 0, param1, 0, 0, 0, 0, 0);
1697 break;
1698 case opcAddObject:
1699 fnAddObject(NULL, 0, param1, 0, 0, 0, 0, 0);
1700 break;
1701 case opcRemoveObject:
1702 fnRemoveObject(NULL, 0, param1, 0, 0, 0, 0, 0);
1703 break;
1704 case opcMegaSet:
1705 obj = _objMan->fetchObject(param1);
1706 fnMegaSet(obj, param1, param2, param3, 0, 0, 0, 0);
1707 break;
1708 case opcNoSprite:
1709 obj = _objMan->fetchObject(param1);
1710 fnNoSprite(obj, param1, param2, param3, 0, 0, 0, 0);
1711 break;
1712 default:
1713 error("Illegal fnCallfn argument %d", fnId);
1714 }
1715 }
1716
runStartScript(const uint8 * data)1717 void Logic::runStartScript(const uint8 *data) {
1718 // Here data is a static resource defined in staticres.cpp
1719 // It is always in little endian
1720 uint16 varId = 0;
1721 uint8 fnId = 0;
1722 uint32 param1 = 0;
1723 while (*data != opcSeqEnd) {
1724 switch (*data++) {
1725 case opcCallFn:
1726 fnId = *data++;
1727 param1 = *data++;
1728 startPosCallFn(fnId, param1, 0, 0);
1729 break;
1730 case opcCallFnLong:
1731 fnId = *data++;
1732 startPosCallFn(fnId, READ_LE_UINT32(data), READ_LE_UINT32(data + 4), READ_LE_UINT32(data + 8));
1733 data += 12;
1734 break;
1735 case opcSetVar8:
1736 varId = READ_LE_UINT16(data);
1737 _scriptVars[varId] = data[2];
1738 data += 3;
1739 break;
1740 case opcSetVar16:
1741 varId = READ_LE_UINT16(data);
1742 _scriptVars[varId] = READ_LE_UINT16(data + 2);
1743 data += 4;
1744 break;
1745 case opcSetVar32:
1746 varId = READ_LE_UINT16(data);
1747 _scriptVars[varId] = READ_LE_UINT32(data + 2);
1748 data += 6;
1749 break;
1750 case opcGeorge:
1751 _scriptVars[CHANGE_X] = READ_LE_UINT16(data + 0);
1752 _scriptVars[CHANGE_Y] = READ_LE_UINT16(data + 2);
1753 _scriptVars[CHANGE_DIR] = data[4];
1754 _scriptVars[CHANGE_PLACE] = READ_LE_UINT24(data + 5);
1755 data += 8;
1756 break;
1757 case opcRunStart:
1758 data = _startData[*data];
1759 break;
1760 case opcRunHelper:
1761 data = _helperData[*data];
1762 break;
1763 default:
1764 error("Unexpected opcode in StartScript");
1765 }
1766 }
1767 }
1768
startPositions(uint32 pos)1769 void Logic::startPositions(uint32 pos) {
1770 bool spainVisit2 = false;
1771 if ((pos >= 956) && (pos <= 962)) {
1772 spainVisit2 = true;
1773 pos -= 900;
1774 }
1775 if ((pos > 80) || (_startData[pos] == NULL))
1776 error("Starting in Section %d is not supported", pos);
1777
1778 Logic::_scriptVars[CHANGE_STANCE] = STAND;
1779 Logic::_scriptVars[GEORGE_CDT_FLAG] = GEO_TLK_TABLE;
1780
1781 runStartScript(_startData[pos]);
1782 if (spainVisit2)
1783 runStartScript(_helperData[HELP_SPAIN2]);
1784
1785 if (pos == 0)
1786 pos = 1;
1787 Object *compact = _objMan->fetchObject(PLAYER);
1788 fnEnterSection(compact, PLAYER, pos, 0, 0, 0, 0, 0); // (automatically opens the compact resource for that section)
1789 SwordEngine::_systemVars.controlPanelMode = CP_NORMAL;
1790 SwordEngine::_systemVars.wantFade = true;
1791 }
1792
1793 const uint32 Logic::_scriptVarInit[NON_ZERO_SCRIPT_VARS][2] = {
1794 { 42, 448}, { 43, 378}, { 51, 1}, { 92, 1}, { 147, 71}, { 201, 1},
1795 { 209, 1}, { 215, 1}, { 242, 2}, { 244, 1}, { 246, 3}, { 247, 1},
1796 { 253, 1}, { 297, 1}, { 398, 1}, { 508, 1}, { 605, 1}, { 606, 1},
1797 { 701, 1}, { 709, 1}, { 773, 1}, { 843, 1}, { 907, 1}, { 923, 1},
1798 { 966, 1}, { 988, 2}, {1058, 1}, {1059, 2}, {1060, 3}, {1061, 4},
1799 {1062, 5}, {1063, 6}, {1064, 7}, {1065, 8}, {1066, 9}, {1067, 10},
1800 {1068, 11}, {1069, 12}, {1070, 13}, {1071, 14}, {1072, 15}, {1073, 16},
1801 {1074, 17}, {1075, 18}, {1076, 19}, {1077, 20}, {1078, 21}, {1079, 22},
1802 {1080, 23}, {1081, 24}, {1082, 25}, {1083, 26}, {1084, 27}, {1085, 28},
1803 {1086, 29}, {1087, 30}, {1088, 31}, {1089, 32}, {1090, 33}, {1091, 34},
1804 {1092, 35}, {1093, 36}, {1094, 37}, {1095, 38}, {1096, 39}, {1097, 40},
1805 {1098, 41}, {1099, 42}, {1100, 43}, {1101, 44}, {1102, 48}, {1103, 45},
1806 {1104, 47}, {1105, 49}, {1106, 50}, {1107, 52}, {1108, 54}, {1109, 56},
1807 {1110, 57}, {1111, 58}, {1112, 59}, {1113, 60}, {1114, 61}, {1115, 62},
1808 {1116, 63}, {1117, 64}, {1118, 65}, {1119, 66}, {1120, 67}, {1121, 68},
1809 {1122, 69}, {1123, 71}, {1124, 72}, {1125, 73}, {1126, 74}
1810 };
1811
1812 } // End of namespace Sword1
1813