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 "mohawk/cursors.h"
24 #include "mohawk/myst.h"
25 #include "mohawk/myst_areas.h"
26 #include "mohawk/myst_card.h"
27 #include "mohawk/myst_graphics.h"
28 #include "mohawk/myst_state.h"
29 #include "mohawk/myst_sound.h"
30 #include "mohawk/video.h"
31 #include "mohawk/myst_stacks/stoneship.h"
32
33 #include "common/events.h"
34 #include "common/system.h"
35 #include "common/textconsole.h"
36
37 namespace Mohawk {
38 namespace MystStacks {
39
Stoneship(MohawkEngine_Myst * vm)40 Stoneship::Stoneship(MohawkEngine_Myst *vm) :
41 MystScriptParser(vm, kStoneshipStack),
42 _state(vm->_gameState->_stoneship) {
43 setupOpcodes();
44
45 _tunnelRunning = false;
46 _tunnelNextTime = 0;
47 _tunnelAlarmSound = 0;
48 _tunnelImagesCount = 0;
49
50 _state.lightState = 0;
51 _state.generatorDepletionTime = 0;
52 _state.generatorDuration = 0;
53 _cabinMystBookPresent = 0;
54 _siriusDrawerDrugsOpen = 0;
55 _chestDrawersOpen = 0;
56 _chestAchenarBottomDrawerClosed = 1;
57
58 _brotherDoorOpen = 0;
59
60 // Drop key
61 if (_state.trapdoorKeyState == 1)
62 _state.trapdoorKeyState = 2;
63
64 // Power is not available when loading
65 if (_state.sideDoorOpened)
66 _state.generatorPowerAvailable = 2;
67 else
68 _state.generatorPowerAvailable = 0;
69
70 _batteryCharging = false;
71 _batteryDepleting = false;
72 _batteryNextTime = 0;
73 _batteryLastCharge = 0;
74 _batteryGaugeRunning = false;
75 _batteryGauge = nullptr;
76
77 _hologramTurnedOn = 0;
78 _hologramDisplay = nullptr;
79 _hologramSelection = nullptr;
80 _hologramDisplayPos = 0;
81
82 _telescopeRunning = false;
83 _telescopePosition = 0;
84 _telescopePanorama = 0;
85 _telescopeOldMouse = 0;
86 _telescopeLighthouseOff = 0;
87 _telescopeLighthouseOn = 0;
88 _telescopeLighthouseState = false;
89 _telescopeNexTime = 0;
90
91 _cloudOrbMovie = nullptr;
92 _cloudOrbSound = 0;
93 _cloudOrbStopSound = 0;
94 }
95
~Stoneship()96 Stoneship::~Stoneship() {
97 }
98
setupOpcodes()99 void Stoneship::setupOpcodes() {
100 // "Stack-Specific" Opcodes
101 REGISTER_OPCODE(100, Stoneship, o_pumpTurnOff);
102 REGISTER_OPCODE(101, Stoneship, o_brotherDoorOpen);
103 REGISTER_OPCODE(102, Stoneship, o_cabinBookMovie);
104 REGISTER_OPCODE(103, Stoneship, o_drawerOpenSirius);
105 REGISTER_OPCODE(104, Stoneship, o_drawerClose);
106 REGISTER_OPCODE(105, Stoneship, o_telescopeStart);
107 REGISTER_OPCODE(106, Stoneship, o_telescopeMove);
108 REGISTER_OPCODE(107, Stoneship, o_telescopeStop);
109 REGISTER_OPCODE(108, Stoneship, o_generatorStart);
110 REGISTER_OPCODE(109, Stoneship, NOP);
111 REGISTER_OPCODE(110, Stoneship, o_generatorStop);
112 REGISTER_OPCODE(111, Stoneship, o_drawerOpenAchenar);
113 REGISTER_OPCODE(112, Stoneship, o_hologramPlayback);
114 REGISTER_OPCODE(113, Stoneship, o_hologramSelectionStart);
115 REGISTER_OPCODE(114, Stoneship, o_hologramSelectionMove);
116 REGISTER_OPCODE(115, Stoneship, o_hologramSelectionStop);
117 REGISTER_OPCODE(116, Stoneship, o_compassButton);
118 REGISTER_OPCODE(117, Stoneship, o_chestValveVideos);
119 REGISTER_OPCODE(118, Stoneship, o_chestDropKey);
120 REGISTER_OPCODE(119, Stoneship, o_trapLockOpen);
121 REGISTER_OPCODE(120, Stoneship, o_sideDoorsMovies);
122 REGISTER_OPCODE(121, Stoneship, o_cloudOrbEnter);
123 REGISTER_OPCODE(122, Stoneship, o_cloudOrbLeave);
124 REGISTER_OPCODE(125, Stoneship, o_drawerCloseOpened);
125
126 // "Init" Opcodes
127 REGISTER_OPCODE(200, Stoneship, o_hologramDisplay_init);
128 REGISTER_OPCODE(201, Stoneship, o_hologramSelection_init);
129 REGISTER_OPCODE(202, Stoneship, o_battery_init);
130 REGISTER_OPCODE(203, Stoneship, o_tunnelEnter_init);
131 REGISTER_OPCODE(204, Stoneship, o_batteryGauge_init);
132 REGISTER_OPCODE(205, Stoneship, o_tunnel_init);
133 REGISTER_OPCODE(206, Stoneship, o_tunnelLeave_init);
134 REGISTER_OPCODE(207, Stoneship, o_chest_init);
135 REGISTER_OPCODE(208, Stoneship, o_telescope_init);
136 REGISTER_OPCODE(209, Stoneship, o_achenarDrawers_init);
137 REGISTER_OPCODE(210, Stoneship, o_cloudOrb_init);
138
139 // "Exit" Opcodes
140 REGISTER_OPCODE(300, Stoneship, NOP);
141 }
142
disablePersistentScripts()143 void Stoneship::disablePersistentScripts() {
144 _batteryCharging = false;
145 _batteryDepleting = false;
146 _batteryGaugeRunning = false;
147 _telescopeRunning = false;
148 }
149
runPersistentScripts()150 void Stoneship::runPersistentScripts() {
151 if (_batteryCharging)
152 chargeBattery_run();
153
154 if (_telescopeRunning)
155 telescope_run();
156
157 if (_batteryGaugeRunning)
158 batteryGauge_run();
159
160 if (_batteryDepleting)
161 batteryDeplete_run();
162
163 if (_tunnelRunning)
164 tunnel_run();
165 }
166
getVar(uint16 var)167 uint16 Stoneship::getVar(uint16 var) {
168 switch(var) {
169 case 0: // Water Drained From Lighthouse / Right Button Of Pump
170 return _state.pumpState == 4;
171 case 1: // Water Drained From Tunnels To Brothers' Rooms / Middle Button Of Pump
172 return _state.pumpState == 2;
173 case 2: // Water Drained From Ship Cabin Tunnel / Left Button Of Pump
174 return _state.pumpState == 1;
175 case 3: // Lighthouse Chest Floating
176 return _state.pumpState != 4 && !_state.chestValveState && !_state.chestWaterState;
177 case 4: // Lighthouse State - Close Up
178 if (_state.pumpState == 4) {
179 return 1; // Drained
180 } else {
181 if (_state.chestValveState || _state.chestWaterState)
182 return 0; // Flooded
183 else
184 return 2; // Flooded, Chest Floating
185 }
186 case 5: // Lighthouse Trapdoor State
187 return _state.trapdoorState;
188 case 6: // Chest valve state
189 return _state.chestValveState;
190 case 7: // Lighthouse Chest Unlocked
191 return _state.chestOpenState;
192 case 8: // Lighthouse Chest Key Position
193 return _state.trapdoorKeyState;
194 case 11: // Lighthouse Key State
195 if (_state.chestOpenState) {
196 if (_state.trapdoorKeyState == 1)
197 return 1;
198 else if (_state.trapdoorKeyState == 2)
199 return 2;
200 else
201 return 3;
202 } else {
203 return 0;
204 }
205 case 12: // Trapdoor can be unlocked
206 return _state.trapdoorKeyState == 1 && _state.trapdoorState == 2;
207 case 13: // State Of Tunnels To Brothers' Rooms - Close Up
208 if (_state.generatorPowerAvailable != 1) {
209 if (_state.pumpState != 2)
210 return 0; // Dark, Flooded
211 else
212 return 1; // Dark, Drained
213 } else {
214 if (_state.pumpState != 2)
215 return 2; // Lit, Flooded
216 else
217 return 3; // Lit, Drained
218 }
219 case 14: // State Of Tunnels lights To Brothers' Rooms - Far
220 return _state.generatorPowerAvailable;
221 case 15: // Side Door in Tunnels To Brother's Rooms Open
222 if (_state.generatorPowerAvailable == 1)
223 return _state.sideDoorOpened;
224 else
225 return 0;
226 case 16: // Ship Chamber Light State
227 return _state.lightState;
228 case 17: // Sirrus' Room Drawer with Drugs Open
229 return _siriusDrawerDrugsOpen;
230 case 18: // Brother Room Door Open
231 return _brotherDoorOpen;
232 case 19: // Brother Room Door State
233 if (_brotherDoorOpen) {
234 if (_state.lightState)
235 return 2; // Open, Light On
236 else
237 return 1; // Open, Light Off
238 } else {
239 return 0; // Closed
240 }
241 case 20: // Ship Chamber Table/Book State
242 return _cabinMystBookPresent;
243 case 21: // Brothers Rooms' Chest Of Drawers Drawer State
244 return _chestDrawersOpen;
245 case 28: // Telescope Angle Position
246 return 0;
247 case 29: // Achenar's Room Rose/Skull Hologram Button Lit
248 return _hologramTurnedOn;
249 case 30: // Light State in Tunnel to Compass Rose Room
250 if (_state.generatorPowerAvailable == 1) {
251 if (_state.lightState)
252 return 0;
253 else
254 return 1;
255 } else {
256 return 2;
257 }
258 case 31: // Lighthouse Lamp Room Battery Pack Indicator Light
259 return batteryRemainingCharge() >= 10;
260 case 32: // Lighthouse Lamp Room Battery Pack Meter Level
261 return 0;
262 case 33: // State of Side Door in Tunnels to Compass Rose Room
263 if (_state.sideDoorOpened)
264 return 2;
265 else
266 return _state.generatorPowerAvailable == 1;
267 case 34: // Achenar's Room Drawer with Torn Note Closed
268 return _chestAchenarBottomDrawerClosed;
269 case 35: // Sirrus' Room Drawer #4 (Bottom) Open and Red Page State
270 if (_chestDrawersOpen == 4)
271 return getVar(102);
272 else
273 return 2;
274 case 36: // Ship Chamber Door State
275 if (_tempVar) {
276 if (_state.lightState)
277 return 2; // Open, Light On
278 else
279 return 1; // Open, Light Off
280 } else {
281 return 0; // Closed
282 }
283 case 102: // Red page
284 return !(_globals.redPagesInBook & 8) && (_globals.heldPage != kRedStoneshipPage);
285 case 103: // Blue page
286 return !(_globals.bluePagesInBook & 8) && (_globals.heldPage != kBlueStoneshipPage);
287 default:
288 return MystScriptParser::getVar(var);
289 }
290 }
291
toggleVar(uint16 var)292 void Stoneship::toggleVar(uint16 var) {
293 switch(var) {
294 case 0: // Water Drained From Lighthouse / Right Button Of Pump
295 if (_state.pumpState == 4)
296 _state.pumpState = 0;
297 else
298 _state.pumpState = 4;
299 break;
300 case 1: // Water Drained From Tunnels To Brothers' Rooms / Middle Button Of Pump
301 if (_state.pumpState == 2)
302 _state.pumpState = 0;
303 else
304 _state.pumpState = 2;
305 break;
306 case 2: // Water Drained From Ship Cabin Tunnel / Left Button Of Pump
307 if (_state.pumpState == 1)
308 _state.pumpState = 0;
309 else
310 _state.pumpState = 1;
311 break;
312 case 6: // Chest valve state
313 _state.chestValveState = (_state.chestValveState + 1) % 2;
314 break;
315 case 8: // Lighthouse Chest Key Position
316 if (_state.trapdoorKeyState) {
317 if (_state.trapdoorKeyState == 1)
318 _state.trapdoorKeyState = 2;
319 else
320 _state.trapdoorKeyState = 1;
321 }
322 break;
323 case 10: // Chest water state
324 _state.chestWaterState = 0;
325 break;
326 case 11:
327 if (_state.chestOpenState)
328 _state.trapdoorKeyState = _state.trapdoorKeyState != 1;
329 break;
330 case 20: // Ship Chamber Table/Book State
331 _cabinMystBookPresent = (_cabinMystBookPresent + 1) % 2;
332 break;
333 case 29: // Achenar's Room Rose/Skull Hologram Button Lit
334 _hologramTurnedOn = (_hologramTurnedOn + 1) % 2;
335 break;
336 case 102: // Red page
337 if (!(_globals.redPagesInBook & 8)) {
338 if (_globals.heldPage == kRedStoneshipPage)
339 _globals.heldPage = kNoPage;
340 else
341 _globals.heldPage = kRedStoneshipPage;
342 }
343 break;
344 case 103: // Blue page
345 if (!(_globals.bluePagesInBook & 8)) {
346 if (_globals.heldPage == kBlueStoneshipPage)
347 _globals.heldPage = kNoPage;
348 else
349 _globals.heldPage = kBlueStoneshipPage;
350 }
351 break;
352 default:
353 MystScriptParser::toggleVar(var);
354 break;
355 }
356 }
357
setVarValue(uint16 var,uint16 value)358 bool Stoneship::setVarValue(uint16 var, uint16 value) {
359 bool refresh = false;
360
361 switch (var) {
362 case 5: // Lighthouse Trapdoor State
363 _state.trapdoorState = value;
364 break;
365 case 7:
366 if (_state.chestOpenState != value)
367 _state.chestOpenState = value;
368 break;
369 case 8: // Lighthouse Chest Key Position
370 _state.trapdoorKeyState = value;
371 break;
372 case 15: // Side Door in Tunnels To Brother's Rooms Open
373 if (_state.sideDoorOpened != value) {
374 if (!value && _state.generatorPowerAvailable == 2)
375 _state.generatorPowerAvailable = 0;
376 _state.sideDoorOpened = value;
377 refresh = true;
378 }
379 break;
380 case 17: // Sirrus' Room Drawer with Drugs Open
381 if (_siriusDrawerDrugsOpen != value) {
382 _siriusDrawerDrugsOpen = value;
383 refresh = true;
384 }
385 break;
386 case 18: // Brother Room Door Open
387 if (_brotherDoorOpen != value) {
388 _brotherDoorOpen = value;
389 refresh = true;
390 }
391 break;
392 case 21: // Brothers Rooms' Chest Of Drawers Drawer State
393 if (_chestDrawersOpen != value) {
394 _chestDrawersOpen = value;
395 refresh = true;
396 }
397 break;
398 case 29: // Achenar's Room Rose/Skull Hologram Button Lit
399 _hologramTurnedOn = value;
400 break;
401 case 34: // Achenar's Room Drawer with Torn Note Closed
402 _chestAchenarBottomDrawerClosed = value;
403 break;
404 default:
405 refresh = MystScriptParser::setVarValue(var, value);
406 break;
407 }
408
409 return refresh;
410 }
411
o_pumpTurnOff(uint16 var,const ArgumentsArray & args)412 void Stoneship::o_pumpTurnOff(uint16 var, const ArgumentsArray &args) {
413 if (_state.pumpState) {
414 uint16 buttonVar = 0;
415
416 switch (_state.pumpState) {
417 case 1:
418 buttonVar = 2;
419 break;
420 case 2:
421 buttonVar = 1;
422 break;
423 case 4:
424 buttonVar = 0;
425 break;
426 default:
427 warning("Incorrect pump state");
428 }
429
430 for (uint i = 0; i < _vm->getCard()->_resources.size(); i++) {
431 MystArea *resource = _vm->getCard()->_resources[i];
432 if (resource->hasType(kMystAreaImageSwitch) && resource->getImageSwitchVar() == buttonVar) {
433 static_cast<MystAreaImageSwitch *>(resource)->drawConditionalDataToScreen(0, true);
434 break;
435 }
436 }
437 }
438 }
439
o_brotherDoorOpen(uint16 var,const ArgumentsArray & args)440 void Stoneship::o_brotherDoorOpen(uint16 var, const ArgumentsArray &args) {
441 _brotherDoorOpen = 1;
442 _vm->getCard()->redrawArea(19, 0);
443 animatedUpdate(args, 5);
444 }
445
o_cabinBookMovie(uint16 var,const ArgumentsArray & args)446 void Stoneship::o_cabinBookMovie(uint16 var, const ArgumentsArray &args) {
447 uint16 startTime = args[0];
448 uint16 endTime = args[1];
449
450 VideoEntryPtr book = _vm->playMovie("bkroom", kStoneshipStack);
451 book->moveTo(159, 99);
452 book->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));
453
454 _vm->waitUntilMovieEnds(book);
455 }
456
o_drawerOpenSirius(uint16 var,const ArgumentsArray & args)457 void Stoneship::o_drawerOpenSirius(uint16 var, const ArgumentsArray &args) {
458 MystAreaImageSwitch *drawer = _vm->getCard()->getResource<MystAreaImageSwitch>(args[0]);
459
460 if (drawer->getImageSwitchVar() == 35) {
461 drawer->drawConditionalDataToScreen(getVar(102), 0);
462 } else {
463 drawer->drawConditionalDataToScreen(0, 0);
464 }
465
466 TransitionType transition = kTransitionTopToBottom;
467 if (args.size() == 2 && args[1])
468 transition = kTransitionCopy;
469
470 _vm->_gfx->runTransition(transition, drawer->getRect(), 25, 5);
471 }
472
o_drawerClose(uint16 var,const ArgumentsArray & args)473 void Stoneship::o_drawerClose(uint16 var, const ArgumentsArray &args) {
474 drawerClose(args[0]);
475 }
476
o_telescopeStart(uint16 var,const ArgumentsArray & args)477 void Stoneship::o_telescopeStart(uint16 var, const ArgumentsArray &args) {
478 const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
479 _telescopeOldMouse = mouse.x;
480 _vm->_cursor->setCursor(700);
481 }
482
o_telescopeMove(uint16 var,const ArgumentsArray & args)483 void Stoneship::o_telescopeMove(uint16 var, const ArgumentsArray &args) {
484 MystAreaDrag *display = getInvokingResource<MystAreaDrag>();
485 const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
486
487 // Compute telescope position
488 _telescopePosition = (_telescopePosition - (mouse.x - _telescopeOldMouse) / 2 + 3240) % 3240;
489 _telescopeOldMouse = mouse.x;
490
491 // Copy image to screen
492 Common::Rect src = Common::Rect(_telescopePosition, 0, _telescopePosition + 112, 112);
493 _vm->_gfx->copyImageSectionToScreen(_telescopePanorama, src, display->getRect());
494
495 // Draw lighthouse
496 telescopeLighthouseDraw();
497 }
498
o_telescopeStop(uint16 var,const ArgumentsArray & args)499 void Stoneship::o_telescopeStop(uint16 var, const ArgumentsArray &args) {
500 _vm->refreshCursor();
501 }
502
o_generatorStart(uint16 var,const ArgumentsArray & args)503 void Stoneship::o_generatorStart(uint16 var, const ArgumentsArray &args) {
504 MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
505
506 uint16 soundId = handle->getList1(0);
507 if (soundId)
508 _vm->_sound->playEffect(soundId);
509
510 if (_state.generatorDuration)
511 _state.generatorDuration -= _vm->getTotalPlayTime() - _state.generatorDepletionTime;
512
513 // Start charging the battery
514 _batteryDepleting = false;
515 _batteryCharging = true;
516 _batteryNextTime = _vm->getTotalPlayTime() + 1000;
517
518 // Start handle movie
519 MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0));
520 movie->playMovie();
521
522 soundId = handle->getList2(0);
523 if (soundId)
524 _vm->_sound->playEffect(soundId, true);
525 }
526
o_generatorStop(uint16 var,const ArgumentsArray & args)527 void Stoneship::o_generatorStop(uint16 var, const ArgumentsArray &args) {
528 _batteryCharging = false;
529
530 if (_state.generatorDuration) {
531 // Clip battery power
532 if (_state.generatorDuration > 600000)
533 _state.generatorDuration = 600000;
534
535 // Start depleting power
536 _state.generatorDepletionTime = _vm->getTotalPlayTime() + _state.generatorDuration;
537 _state.generatorPowerAvailable = 1;
538 _batteryDepleting = true;
539 _batteryNextTime = _vm->getTotalPlayTime() + 60000;
540 }
541
542 // Pause handle movie
543 MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
544 MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0));
545 movie->pauseMovie(true);
546
547 uint16 soundId = handle->getList3(0);
548 if (soundId)
549 _vm->_sound->playEffect(soundId);
550 }
551
chargeBattery_run()552 void Stoneship::chargeBattery_run() {
553 uint32 time = _vm->getTotalPlayTime();
554
555 if (time > _batteryNextTime) {
556 _batteryNextTime = time + 1000;
557 _state.generatorDuration += 30000;
558 }
559 }
560
batteryRemainingCharge()561 uint16 Stoneship::batteryRemainingCharge() {
562 uint32 time = _vm->getTotalPlayTime();
563
564 if (_state.generatorDepletionTime > time) {
565 return (_state.generatorDepletionTime - time) / 7500;
566 } else {
567 return 0;
568 }
569 }
570
batteryDeplete_run()571 void Stoneship::batteryDeplete_run() {
572 uint32 time = _vm->getTotalPlayTime();
573
574 if (time > _batteryNextTime) {
575 if (_state.generatorDuration > 60000) {
576 _state.generatorDuration -= 60000;
577 _batteryNextTime = time + 60000;
578 } else { // Battery depleted
579 _state.generatorDuration = 0;
580 _state.generatorDepletionTime = 0;
581
582 if (_state.sideDoorOpened)
583 _state.generatorPowerAvailable = 2;
584 else
585 _state.generatorPowerAvailable = 0;
586
587 _batteryDepleting = false;
588 }
589 }
590 }
591
o_drawerOpenAchenar(uint16 var,const ArgumentsArray & args)592 void Stoneship::o_drawerOpenAchenar(uint16 var, const ArgumentsArray &args) {
593 MystAreaImageSwitch *drawer = _vm->getCard()->getResource<MystAreaImageSwitch>(args[0]);
594 drawer->drawConditionalDataToScreen(0, 0);
595 _vm->_gfx->runTransition(kTransitionTopToBottom, drawer->getRect(), 25, 5);
596 }
597
o_hologramPlayback(uint16 var,const ArgumentsArray & args)598 void Stoneship::o_hologramPlayback(uint16 var, const ArgumentsArray &args) {
599 // Used for Card 2013 (Achenar's Rose-Skull Hologram)
600 uint16 startPoint = args[0];
601 uint16 endPoint = args[1];
602 // uint16 direction = args[2];
603
604 _hologramDisplay->setBlocking(false);
605 VideoEntryPtr displayMovie = _hologramDisplay->playMovie();
606
607 if (_hologramTurnedOn) {
608 if (_hologramDisplayPos)
609 endPoint = _hologramDisplayPos;
610 displayMovie->setBounds(Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
611 } else {
612 displayMovie->setBounds(Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
613 }
614
615 _vm->waitUntilMovieEnds(displayMovie);
616 }
617
o_hologramSelectionStart(uint16 var,const ArgumentsArray & args)618 void Stoneship::o_hologramSelectionStart(uint16 var, const ArgumentsArray &args) {
619 //_vm->_cursor->setCursor(0);
620 }
621
o_hologramSelectionMove(uint16 var,const ArgumentsArray & args)622 void Stoneship::o_hologramSelectionMove(uint16 var, const ArgumentsArray &args) {
623 MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
624 const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
625
626 if (handle->getRect().contains(mouse)) {
627 int16 position = mouse.x - 143;
628 position = CLIP<int16>(position, 0, 242);
629
630 // Draw handle movie frame
631 uint16 selectionPos = position * 1500 / 243;
632
633 VideoEntryPtr handleMovie = _hologramSelection->playMovie();
634 _vm->_video->drawVideoFrame(handleMovie, Audio::Timestamp(0, selectionPos, 600));
635
636 _hologramDisplayPos = position * 1450 / 243 + 350;
637
638 // Draw display movie frame
639 if (_hologramTurnedOn) {
640 _hologramDisplay->setBlocking(false);
641 VideoEntryPtr displayMovie = _hologramDisplay->playMovie();
642 _vm->_video->drawVideoFrame(displayMovie, Audio::Timestamp(0, _hologramDisplayPos, 600));
643 }
644 }
645 }
646
o_hologramSelectionStop(uint16 var,const ArgumentsArray & args)647 void Stoneship::o_hologramSelectionStop(uint16 var, const ArgumentsArray &args) {
648 _vm->refreshCursor();
649 }
650
o_compassButton(uint16 var,const ArgumentsArray & args)651 void Stoneship::o_compassButton(uint16 var, const ArgumentsArray &args) {
652 // Used on Card 2111 (Compass Rose)
653 // Called when Button Clicked.
654 uint16 correctButton = args[0];
655
656 if (correctButton) {
657 // Correct Button -> Light On Logic
658 _state.lightState = 1;
659 } else {
660 // Wrong Button -> Power Failure Logic
661 _state.generatorPowerAvailable = 2;
662 _state.lightState = 0;
663 _state.generatorDepletionTime = 0;
664 _state.generatorDuration = 0;
665
666 _batteryDepleting = false;
667 }
668
669 o_redrawCard(var, args);
670 }
671
o_chestValveVideos(uint16 var,const ArgumentsArray & args)672 void Stoneship::o_chestValveVideos(uint16 var, const ArgumentsArray &args) {
673 _vm->_sound->playEffect(2132);
674
675 if (_state.chestValveState) {
676 // Valve closing
677 VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack);
678 valve->moveTo(97, 267);
679 valve->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 350, 600));
680
681 _vm->waitUntilMovieEnds(valve);
682 } else if (_state.chestWaterState) {
683 // Valve opening, spilling water
684 VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack);
685 valve->moveTo(97, 267);
686 valve->setBounds(Audio::Timestamp(0, 350, 600), Audio::Timestamp(0, 650, 600));
687
688 _vm->waitUntilMovieEnds(valve);
689
690 _vm->_sound->playEffect(3132);
691
692 for (uint i = 0; i < 25; i++) {
693 valve = _vm->playMovie("ligspig", kStoneshipStack);
694 valve->moveTo(97, 267);
695 valve->setBounds(Audio::Timestamp(0, 650, 600), Audio::Timestamp(0, 750, 600));
696 _vm->waitUntilMovieEnds(valve);
697 }
698
699 _vm->_sound->resumeBackground();
700 } else {
701 // Valve opening
702 VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack);
703 valve->moveTo(97, 267);
704 valve->seek(Audio::Timestamp(0, 350, 600));
705 valve->setRate(-1);
706
707 _vm->waitUntilMovieEnds(valve);
708 }
709 }
710
o_chestDropKey(uint16 var,const ArgumentsArray & args)711 void Stoneship::o_chestDropKey(uint16 var, const ArgumentsArray &args) {
712 // If holding Key to Lamp Room Trapdoor, drop to bottom of
713 // Lighthouse...
714 if (_state.trapdoorKeyState == 1) {
715 _vm->setMainCursor(_savedCursorId);
716 _state.trapdoorKeyState = 2;
717 }
718 }
719
o_trapLockOpen(uint16 var,const ArgumentsArray & args)720 void Stoneship::o_trapLockOpen(uint16 var, const ArgumentsArray &args) {
721 VideoEntryPtr lock = _vm->playMovie("openloc", kStoneshipStack);
722 lock->moveTo(187, 71);
723 lock->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 750, 600));
724 _vm->waitUntilMovieEnds(lock);
725
726 _vm->_sound->playEffect(2143);
727
728 lock = _vm->playMovie("openloc", kStoneshipStack);
729 lock->moveTo(187, 71);
730 lock->setBounds(Audio::Timestamp(0, 750, 600), Audio::Timestamp(0, 10000, 600));
731 _vm->waitUntilMovieEnds(lock);
732
733 if (_state.pumpState != 4)
734 _vm->_sound->playEffect(4143);
735 }
736
o_sideDoorsMovies(uint16 var,const ArgumentsArray & args)737 void Stoneship::o_sideDoorsMovies(uint16 var, const ArgumentsArray &args) {
738 // Used for Cards 2285, 2289, 2247, 2251 (Side Doors in Tunnels Down To Brothers Rooms)
739 uint16 movieId = args[0];
740
741 _vm->_cursor->hideCursor();
742 _vm->_sound->pauseBackground();
743
744 switch (movieId) {
745 case 0:
746 // Card 2251
747 _vm->playMovieBlocking("tunaup", kStoneshipStack, 149, 161);
748 break;
749 case 1:
750 // Card 2247
751 _vm->playMovieBlocking("tunadown", kStoneshipStack, 218, 150);
752 break;
753 case 2:
754 // Card 2289
755 _vm->playMovieBlocking("tuncup", kStoneshipStack, 259, 161);
756 break;
757 case 3:
758 // Card 2285
759 _vm->playMovieBlocking("tuncdown", kStoneshipStack, 166, 150);
760 break;
761 default:
762 warning("Opcode 120 MovieId Out Of Range");
763 break;
764 }
765
766 _vm->_sound->resumeBackground();
767 _vm->_cursor->showCursor();
768 }
769
o_cloudOrbEnter(uint16 var,const ArgumentsArray & args)770 void Stoneship::o_cloudOrbEnter(uint16 var, const ArgumentsArray &args) {
771 _vm->_sound->playEffect(_cloudOrbSound, true);
772 _cloudOrbMovie->playMovie();
773 }
774
o_cloudOrbLeave(uint16 var,const ArgumentsArray & args)775 void Stoneship::o_cloudOrbLeave(uint16 var, const ArgumentsArray &args) {
776 _cloudOrbMovie->pauseMovie(true);
777 _vm->_sound->playEffect(_cloudOrbStopSound);
778 _vm->_gfx->runTransition(kTransitionTopToBottom, getInvokingResource<MystArea>()->getRect(), 4, 0);
779 }
780
o_drawerCloseOpened(uint16 var,const ArgumentsArray & args)781 void Stoneship::o_drawerCloseOpened(uint16 var, const ArgumentsArray &args) {
782 uint16 drawerOpen = getVar(var);
783 if (drawerOpen)
784 drawerClose(args[0] + drawerOpen - 1);
785 }
786
drawerClose(uint16 drawer)787 void Stoneship::drawerClose(uint16 drawer) {
788 _chestDrawersOpen = 0;
789 _vm->getCard()->drawBackground();
790 _vm->getCard()->drawResourceImages();
791
792 MystArea *res = _vm->getCard()->getResource<MystArea>(drawer);
793 _vm->_gfx->runTransition(kTransitionBottomToTop, res->getRect(), 25, 5);
794 }
795
o_hologramDisplay_init(uint16 var,const ArgumentsArray & args)796 void Stoneship::o_hologramDisplay_init(uint16 var, const ArgumentsArray &args) {
797 _hologramDisplay = getInvokingResource<MystAreaVideo>();
798
799 _hologramDisplayPos = 0;
800 }
801
o_hologramSelection_init(uint16 var,const ArgumentsArray & args)802 void Stoneship::o_hologramSelection_init(uint16 var, const ArgumentsArray &args) {
803 _hologramSelection = getInvokingResource<MystAreaVideo>();
804 }
805
batteryGaugeUpdate()806 void Stoneship::batteryGaugeUpdate() {
807 uint16 charge = 0;
808
809 if (_state.generatorDepletionTime) {
810 charge = batteryRemainingCharge();
811 }
812
813 Common::Rect rect = _batteryGauge->getRect();
814
815 rect.top = rect.bottom - charge;
816
817 _batteryGauge->setRect(rect);
818 }
819
o_battery_init(uint16 var,const ArgumentsArray & args)820 void Stoneship::o_battery_init(uint16 var, const ArgumentsArray &args) {
821 // Used for Card 2160 (Lighthouse Battery Pack Closeup)
822 _batteryGauge = getInvokingResource<MystAreaImageSwitch>();
823
824 batteryGaugeUpdate();
825 }
826
o_tunnelEnter_init(uint16 var,const ArgumentsArray & args)827 void Stoneship::o_tunnelEnter_init(uint16 var, const ArgumentsArray &args) {
828 o_tunnel_init(var, args);
829
830 _tunnelRunning = true;
831 _tunnelNextTime = _vm->getTotalPlayTime() + 1500;
832 }
833
o_batteryGauge_init(uint16 var,const ArgumentsArray & args)834 void Stoneship::o_batteryGauge_init(uint16 var, const ArgumentsArray &args) {
835 _batteryLastCharge = batteryRemainingCharge();
836 _batteryGaugeRunning = true;
837 }
838
batteryGauge_run()839 void Stoneship::batteryGauge_run() {
840 uint16 batteryCharge = batteryRemainingCharge();
841
842 if (batteryCharge != _batteryLastCharge) {
843 batteryGaugeUpdate();
844
845 _batteryLastCharge = batteryCharge;
846
847 // Redraw card
848 _vm->getCard()->drawBackground();
849 _vm->getCard()->drawResourceImages();
850 _vm->_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
851 }
852 }
853
o_tunnel_init(uint16 var,const ArgumentsArray & args)854 void Stoneship::o_tunnel_init(uint16 var, const ArgumentsArray &args) {
855 _tunnelImagesCount = args[0];
856
857 assert(_tunnelImagesCount <= 2 && "Too many images");
858
859 for (uint i = 0; i < _tunnelImagesCount; i++) {
860 _tunnelImages[i] = args[i + 1];
861 }
862
863 _tunnelAlarmSound = args[args.size() - 1];
864
865 debugC(kDebugScript, "\timage count: %d", _tunnelImagesCount);
866 debugC(kDebugScript, "\tsoundIdAlarm: %d", _tunnelAlarmSound);
867 }
868
tunnel_run()869 void Stoneship::tunnel_run() {
870 uint32 time = _vm->getTotalPlayTime();
871
872 if (time > _tunnelNextTime) {
873 _tunnelNextTime = time + 1500;
874 if (_state.generatorPowerAvailable == 2) {
875 // Draw tunnel black
876 if (_tunnelImagesCount) {
877 _vm->_gfx->copyImageToScreen(_tunnelImages[1], Common::Rect(544, 333));
878 }
879
880 _vm->_sound->playEffect(_tunnelAlarmSound);
881
882 // Draw tunnel dark
883 if (_tunnelImagesCount) {
884 _vm->_gfx->copyImageToScreen(_tunnelImages[0], Common::Rect(544, 333));
885 }
886 }
887 }
888 }
889
o_tunnelLeave_init(uint16 var,const ArgumentsArray & args)890 void Stoneship::o_tunnelLeave_init(uint16 var, const ArgumentsArray &args) {
891 _tunnelRunning = false;
892 }
893
o_chest_init(uint16 var,const ArgumentsArray & args)894 void Stoneship::o_chest_init(uint16 var, const ArgumentsArray &args) {
895 _state.chestOpenState = 0;
896 }
897
o_telescope_init(uint16 var,const ArgumentsArray & args)898 void Stoneship::o_telescope_init(uint16 var, const ArgumentsArray &args) {
899 // Used in Card 2218 (Telescope view)
900 _telescopePanorama = args[0];
901 _telescopeLighthouseOff = args[1];
902 _telescopeLighthouseOn = args[2];
903 _telescopePosition = 0;
904
905 _telescopeRunning = true;
906 _telescopeLighthouseState = false;
907 _telescopeNexTime = _vm->getTotalPlayTime() + 1000;
908 }
909
telescope_run()910 void Stoneship::telescope_run() {
911 uint32 time = _vm->getTotalPlayTime();
912
913 if (time > _telescopeNexTime) {
914
915 _telescopeNexTime = time + 1000;
916 _telescopeLighthouseState = !_telescopeLighthouseState;
917
918 telescopeLighthouseDraw();
919 }
920 }
921
telescopeLighthouseDraw()922 void Stoneship::telescopeLighthouseDraw() {
923 if (_telescopePosition > 1137 && _telescopePosition < 1294) {
924 uint16 imageId = _telescopeLighthouseOff;
925
926 if (_state.generatorPowerAvailable == 1 && _telescopeLighthouseState)
927 imageId = _telescopeLighthouseOn;
928
929 Common::Rect src(1205, 0, 1205 + 131, 112);
930 src.clip(Common::Rect(_telescopePosition, 0, _telescopePosition + 112, 112));
931 src.translate(-1205, 0);
932 src.clip(131, 112);
933
934 Common::Rect dest(_telescopePosition, 0, _telescopePosition + 112, 112);
935 dest.clip(Common::Rect(1205, 0, 1205 + 131, 112));
936 dest.translate(-_telescopePosition, 0);
937 dest.clip(112, 112);
938 dest.translate(222, 112);
939
940 _vm->_gfx->copyImageSectionToScreen(imageId, src, dest);
941 }
942 }
943
o_achenarDrawers_init(uint16 var,const ArgumentsArray & args)944 void Stoneship::o_achenarDrawers_init(uint16 var, const ArgumentsArray &args) {
945 // Used for Card 2004 (Achenar's Room Drawers)
946 if (!_chestAchenarBottomDrawerClosed) {
947 uint16 count1 = args[0];
948 for (uint16 i = 0; i < count1; i++) {
949 debugC(kDebugScript, "Disable hotspot index %d", args[i + 1]);
950 _vm->getCard()->setResourceEnabled(args[i + 1], false);
951 }
952 uint16 count2 = args[count1 + 1];
953 for (uint16 i = 0; i < count2; i++) {
954 debugC(kDebugScript, "Enable hotspot index %d", args[i + count1 + 2]);
955 _vm->getCard()->setResourceEnabled(args[i + count1 + 2], true);
956 }
957 }
958 }
959
o_cloudOrb_init(uint16 var,const ArgumentsArray & args)960 void Stoneship::o_cloudOrb_init(uint16 var, const ArgumentsArray &args) {
961 _cloudOrbMovie = getInvokingResource<MystAreaVideo>();
962 _cloudOrbSound = args[0];
963 _cloudOrbStopSound = args[1];
964 }
965
966 } // End of namespace MystStacks
967 } // End of namespace Mohawk
968