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 * Cursor and cursor trails.
22 */
23
24 #include "tinsel/cursor.h"
25
26 #include "tinsel/anim.h"
27 #include "tinsel/background.h"
28 #include "tinsel/cursor.h"
29 #include "tinsel/dw.h"
30 #include "tinsel/events.h" // For EventsManager class
31 #include "tinsel/film.h"
32 #include "tinsel/graphics.h"
33 #include "tinsel/handle.h"
34 #include "tinsel/dialogs.h"
35 #include "tinsel/multiobj.h" // multi-part object defintions etc.
36 #include "tinsel/object.h"
37 #include "tinsel/pid.h"
38 #include "tinsel/play.h"
39 #include "tinsel/sched.h"
40 #include "tinsel/sysvar.h"
41 #include "tinsel/text.h"
42 #include "tinsel/timers.h" // For ONE_SECOND constant
43 #include "tinsel/tinlib.h" // resetidletime()
44 #include "tinsel/tinsel.h" // For engine access
45
46
47 namespace Tinsel {
48
49 //----------------- LOCAL DEFINES --------------------
50
51 #define ITERATION_BASE FRAC_ONE
52 #define ITER_ACCELERATION (10L << (FRAC_BITS - 4))
53
Cursor()54 Cursor::Cursor() {
55 _mainCursor = nullptr;
56 _auxCursor = nullptr;
57
58 _mainCursorAnim = {0, 0, 0, 0, 0};
59 _auxCursorAnim = {0, 0, 0, 0, 0};
60
61 _hiddenCursor = false;
62 _hiddenTrails = false;
63 _tempHiddenCursor = false;
64 _frozenCursor = false;
65
66 _iterationSize = 0;
67
68 _cursorFilm = 0;
69
70 _numTrails = 0;
71 _nextTrail = 0;
72
73 _cursorProcessesStopped = false;
74 _cursorProcessesRestarted = false;
75
76 _auxCursorOffsetX = 0;
77 _auxCursorOffsetY = 0;
78
79 _lastCursorX = 0;
80 _lastCursorY = 0;
81 }
82
83 /**
84 * Initialize and insert a cursor trail object, set its Z-pos, and hide
85 * it. Also initialize its animation script.
86 */
InitCurTrailObj(int i,int x,int y)87 void Cursor::InitCurTrailObj(int i, int x, int y) {
88 const FREEL *pfr; // pointer to reel
89 IMAGE *pim; // pointer to image
90 const MULTI_INIT *pmi; // MULTI_INIT structure
91
92 const FILM *pfilm;
93
94 if (!_numTrails)
95 return;
96
97 // Get rid of old object
98 if (_trailData[i].trailObj != NULL)
99 MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _trailData[i].trailObj);
100
101 pim = GetImageFromFilm(_cursorFilm, i+1, &pfr, &pmi, &pfilm);// Get pointer to image
102 assert(_vm->_bg->BgPal()); // No background palette
103 pim->hImgPal = TO_32(_vm->_bg->BgPal());
104
105 // Initialize and insert the object, set its Z-pos, and hide it
106 _trailData[i].trailObj = MultiInitObject(pmi);
107 MultiInsertObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _trailData[i].trailObj);
108 MultiSetZPosition(_trailData[i].trailObj, Z_CURSORTRAIL);
109 MultiSetAniXY(_trailData[i].trailObj, x, y);
110
111 // Initialize the animation script
112 InitStepAnimScript(&_trailData[i].trailAnim, _trailData[i].trailObj, FROM_32(pfr->script), ONE_SECOND / FROM_32(pfilm->frate));
113 StepAnimScript(&_trailData[i].trailAnim);
114 }
115
116 /**
117 * Get the cursor position from the mouse driver.
118 */
GetDriverPosition(int * x,int * y)119 bool Cursor::GetDriverPosition(int *x, int *y) {
120 Common::Point ptMouse = _vm->getMousePosition();
121 *x = ptMouse.x;
122 *y = ptMouse.y;
123
124 return(*x >= 0 && *x <= SCREEN_WIDTH - 1 &&
125 *y >= 0 && *y <= SCREEN_HEIGHT - 1);
126 }
127
128 /**
129 * Move the cursor relative to current position.
130 */
AdjustCursorXY(int deltaX,int deltaY)131 void Cursor::AdjustCursorXY(int deltaX, int deltaY) {
132 int x, y;
133
134 if (deltaX || deltaY) {
135 if (GetDriverPosition(&x, &y))
136 _vm->setMousePosition(Common::Point(x + deltaX, y + deltaY));
137 }
138 DoCursorMove();
139 }
140
141 /**
142 * Move the cursor to an absolute position.
143 */
SetCursorXY(int newx,int newy)144 void Cursor::SetCursorXY(int newx, int newy) {
145 int x, y;
146 int Loffset, Toffset; // Screen offset
147
148 _vm->_bg->PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
149 newx -= Loffset;
150 newy -= Toffset;
151
152 if (GetDriverPosition(&x, &y))
153 _vm->setMousePosition(Common::Point(newx, newy));
154 DoCursorMove();
155 }
156
157 /**
158 * Move the cursor to a screen position.
159 */
SetCursorScreenXY(int newx,int newy)160 void Cursor::SetCursorScreenXY(int newx, int newy) {
161 int x, y;
162
163 if (GetDriverPosition(&x, &y))
164 _vm->setMousePosition(Common::Point(newx, newy));
165 DoCursorMove();
166 }
167
168 /**
169 * Called by the world and his brother.
170 * Returns the cursor's animation position in (x,y).
171 * Returns false if there is no cursor object.
172 */
GetCursorXYNoWait(int * x,int * y,bool absolute)173 bool Cursor::GetCursorXYNoWait(int *x, int *y, bool absolute) {
174 if (_mainCursor == NULL) {
175 *x = *y = 0;
176 return false;
177 }
178
179 GetAniPosition(_mainCursor, x, y);
180
181 if (absolute) {
182 int Loffset, Toffset; // Screen offset
183 _vm->_bg->PlayfieldGetPos(FIELD_WORLD, &Loffset, &Toffset);
184 *x += Loffset;
185 *y += Toffset;
186 }
187
188 return true;
189 }
190
191 /**
192 * Called by the world and his brother.
193 * Returns the cursor's animation position.
194 * If called while there is no cursor object, the calling process ends
195 * up waiting until there is.
196 */
GetCursorXY(int * x,int * y,bool absolute)197 void Cursor::GetCursorXY(int *x, int *y, bool absolute) {
198 //while (McurObj == NULL)
199 // ProcessSleepSelf();
200 assert(_mainCursor);
201 GetCursorXYNoWait(x, y, absolute);
202 }
203
204 /**
205 * Re-initialize the main cursor to use the main cursor reel.
206 * Called from TINLIB.C to restore cursor after hiding it.
207 * Called from INVENTRY.C to restore cursor after customising it.
208 */
RestoreMainCursor()209 void Cursor::RestoreMainCursor() {
210 const FILM *pfilm;
211
212 if (_mainCursor != NULL) {
213 pfilm = (const FILM *)_vm->_handle->LockMem(_cursorFilm);
214
215 InitStepAnimScript(&_mainCursorAnim, _mainCursor, FROM_32(pfilm->reels->script), ONE_SECOND / FROM_32(pfilm->frate));
216 StepAnimScript(&_mainCursorAnim);
217 }
218 _hiddenCursor = false;
219 _frozenCursor = false;
220 }
221
222 /**
223 * Called from INVENTRY.C to customise the main cursor.
224 */
SetTempCursor(SCNHANDLE pScript)225 void Cursor::SetTempCursor(SCNHANDLE pScript) {
226 if (_mainCursor != NULL)
227 InitStepAnimScript(&_mainCursorAnim, _mainCursor, pScript, 2);
228 }
229
230 /**
231 * Hide the cursor.
232 */
DwHideCursor()233 void Cursor::DwHideCursor() {
234 _hiddenCursor = true;
235
236 if (_mainCursor)
237 MultiHideObject(_mainCursor);
238 if (_auxCursor)
239 MultiHideObject(_auxCursor);
240
241 for (int i = 0; i < _numTrails; i++) {
242 if (_trailData[i].trailObj != NULL) {
243 MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _trailData[i].trailObj);
244 _trailData[i].trailObj = nullptr;
245 }
246 }
247 }
248
HideCursorProcess()249 void Cursor::HideCursorProcess() {
250 if (_mainCursor)
251 MultiHideObject(_mainCursor);
252 if (_auxCursor)
253 MultiHideObject(_auxCursor);
254
255 for (int i = 0; i < _numTrails; i++) {
256 if (_trailData[i].trailObj != NULL)
257 MultiHideObject(_trailData[i].trailObj);
258 }
259 }
260
261 /**
262 * Unhide the cursor.
263 */
UnHideCursor()264 void Cursor::UnHideCursor() {
265 _hiddenCursor = false;
266 }
267
268 /**
269 * Freeze the cursor.
270 */
FreezeCursor()271 void Cursor::FreezeCursor() {
272 _frozenCursor = true;
273 }
274
275 /**
276 * Freeze the cursor, or not.
277 */
DoFreezeCursor(bool bFreeze)278 void Cursor::DoFreezeCursor(bool bFreeze) {
279 _frozenCursor = bFreeze;
280 }
281
282 /**
283 * HideCursorTrails
284 */
HideCursorTrails()285 void Cursor::HideCursorTrails() {
286 int i;
287
288 _hiddenTrails = true;
289
290 for (i = 0; i < _numTrails; i++) {
291 if (_trailData[i].trailObj != NULL) {
292 MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _trailData[i].trailObj);
293 _trailData[i].trailObj = nullptr;
294 }
295 }
296 }
297
298 /**
299 * UnHideCursorTrails
300 */
UnHideCursorTrails()301 void Cursor::UnHideCursorTrails() {
302 _hiddenTrails = false;
303 }
304
305 /**
306 * Get pointer to image from a film reel. And the rest.
307 */
GetImageFromReel(const FREEL * pfr,const MULTI_INIT ** ppmi)308 IMAGE *Cursor::GetImageFromReel(const FREEL *pfr, const MULTI_INIT **ppmi) {
309 const MULTI_INIT *pmi;
310 const FRAME *pFrame;
311
312 pmi = (const MULTI_INIT *)_vm->_handle->LockMem(FROM_32(pfr->mobj));
313 if (ppmi)
314 *ppmi = pmi;
315
316 pFrame = (const FRAME *)_vm->_handle->LockMem(FROM_32(pmi->hMulFrame));
317
318 // get pointer to image
319 return (IMAGE *)_vm->_handle->LockMem(READ_32(pFrame));
320 }
321
322 /**
323 * Get pointer to image from a film. And the rest.
324 */
GetImageFromFilm(SCNHANDLE hFilm,int reel,const FREEL ** ppfr,const MULTI_INIT ** ppmi,const FILM ** ppfilm)325 IMAGE *Cursor::GetImageFromFilm(SCNHANDLE hFilm, int reel, const FREEL **ppfr, const MULTI_INIT **ppmi, const FILM **ppfilm) {
326 const FILM *pfilm;
327 const FREEL *pfr;
328
329 pfilm = (const FILM *)_vm->_handle->LockMem(hFilm);
330 if (ppfilm)
331 *ppfilm = pfilm;
332
333 pfr = &pfilm->reels[reel];
334 if (ppfr)
335 *ppfr = pfr;
336
337 return GetImageFromReel(pfr, ppmi);
338 }
339
340 /**
341 * Delete auxillary cursor. Restore animation offsets in the image.
342 */
DelAuxCursor()343 void Cursor::DelAuxCursor() {
344 if (_auxCursor != NULL) {
345 MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _auxCursor);
346 _auxCursor = nullptr;
347 }
348 }
349
350 /**
351 * Set auxillary cursor.
352 * Save animation offsets from the image if required.
353 */
SetAuxCursor(SCNHANDLE hFilm)354 void Cursor::SetAuxCursor(SCNHANDLE hFilm) {
355 IMAGE *pim; // Pointer to auxillary cursor's image
356 const FREEL *pfr;
357 const MULTI_INIT *pmi;
358 const FILM *pfilm;
359 int x, y; // Cursor position
360
361 DelAuxCursor(); // Get rid of previous
362
363 // WORKAROUND: There's no palette when loading a DW1 savegame with a held item, so exit if so
364 if (!_vm->_bg->BgPal())
365 return;
366
367 GetCursorXY(&x, &y, false); // Note: also waits for cursor to appear
368
369 pim = GetImageFromFilm(hFilm, 0, &pfr, &pmi, &pfilm);// Get pointer to image
370 assert(_vm->_bg->BgPal()); // no background palette
371 pim->hImgPal = TO_32(_vm->_bg->BgPal()); // Poke in the background palette
372
373 _auxCursorOffsetX = (short)(FROM_16(pim->imgWidth)/2 - ((int16) FROM_16(pim->anioffX)));
374 _auxCursorOffsetY = (short)((FROM_16(pim->imgHeight) & ~C16_FLAG_MASK)/2 -
375 ((int16) FROM_16(pim->anioffY)));
376
377 // Initialize and insert the auxillary cursor object
378 _auxCursor = MultiInitObject(pmi);
379 MultiInsertObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _auxCursor);
380
381 // Initialize the animation and set its position
382 InitStepAnimScript(&_auxCursorAnim, _auxCursor, FROM_32(pfr->script), ONE_SECOND / FROM_32(pfilm->frate));
383 MultiSetAniXY(_auxCursor, x - _auxCursorOffsetX, y - _auxCursorOffsetY);
384 MultiSetZPosition(_auxCursor, Z_ACURSOR);
385
386 if (_hiddenCursor)
387 MultiHideObject(_auxCursor);
388 }
389
390 /**
391 * MoveCursor
392 */
DoCursorMove()393 void Cursor::DoCursorMove() {
394 int startX, startY;
395 Common::Point ptMouse;
396 frac_t newX, newY;
397 unsigned dir;
398
399 // get cursors start animation position
400 GetCursorXYNoWait(&startX, &startY, false);
401
402 // get mouse drivers current position
403 ptMouse = _vm->getMousePosition();
404
405 // convert to fixed point
406 newX = intToFrac(ptMouse.x);
407 newY = intToFrac(ptMouse.y);
408
409 // modify mouse driver position depending on cursor keys
410 dir = _vm->getKeyDirection();
411 if (dir != 0) {
412 if (dir & MSK_LEFT)
413 newX -= _iterationSize;
414
415 if (dir & MSK_RIGHT)
416 newX += _iterationSize;
417
418 if (dir & MSK_UP)
419 newY -= _iterationSize;
420
421 if (dir & MSK_DOWN)
422 newY += _iterationSize;
423
424 _iterationSize += ITER_ACCELERATION;
425
426 // set new mouse driver position
427 _vm->setMousePosition(Common::Point(fracToInt(newX), fracToInt(newY)));
428 } else
429
430 _iterationSize = ITERATION_BASE;
431
432 // get new mouse driver position - could have been modified
433 ptMouse = _vm->getMousePosition();
434
435 if (_lastCursorX != ptMouse.x || _lastCursorY != ptMouse.y) {
436 resetUserEventTime();
437
438 if (!_hiddenTrails && !_hiddenCursor) {
439 InitCurTrailObj(_nextTrail++, _lastCursorX, _lastCursorY);
440 if (_nextTrail == _numTrails)
441 _nextTrail = 0;
442 }
443 }
444
445 // adjust cursor to new mouse position
446 if (_mainCursor)
447 MultiSetAniXY(_mainCursor, ptMouse.x, ptMouse.y);
448 if (_auxCursor != NULL)
449 MultiSetAniXY(_auxCursor, ptMouse.x - _auxCursorOffsetX, ptMouse.y - _auxCursorOffsetY);
450
451 if (_vm->_dialogs->InventoryActive() && _mainCursor) {
452 // Notify the inventory
453 _vm->_dialogs->Xmovement(ptMouse.x - startX);
454 _vm->_dialogs->Ymovement(ptMouse.y - startY);
455 }
456
457 _lastCursorX = ptMouse.x;
458 _lastCursorY = ptMouse.y;
459 }
460
461 /**
462 * Initialize cursor object.
463 */
InitCurObj()464 void Cursor::InitCurObj() {
465 const FILM *pFilm;
466 const FREEL *pfr;
467 const MULTI_INIT *pmi;
468 IMAGE *pim;
469
470 if (TinselV2 || TinselV3) {
471 pFilm = (const FILM *)_vm->_handle->LockMem(_cursorFilm);
472 pfr = (const FREEL *)&pFilm->reels[0];
473 pmi = (MULTI_INIT *)_vm->_handle->LockMem(FROM_32(pfr->mobj));
474
475 if (!TinselV3) {
476 PokeInPalette(pmi);
477 }
478 } else {
479 assert(_vm->_bg->BgPal()); // no background palette
480
481 pim = GetImageFromFilm(_cursorFilm, 0, &pfr, &pmi, &pFilm);// Get pointer to image
482 pim->hImgPal = TO_32(_vm->_bg->BgPal());
483
484 _auxCursor = nullptr; // No auxillary cursor
485 }
486
487 _mainCursor = MultiInitObject(pmi);
488 MultiInsertObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _mainCursor);
489
490 InitStepAnimScript(&_mainCursorAnim, _mainCursor, FROM_32(pfr->script), ONE_SECOND / FROM_32(pFilm->frate));
491 }
492
493 /**
494 * Initialize the cursor position.
495 */
InitCurPos()496 void Cursor::InitCurPos() {
497 Common::Point ptMouse = _vm->getMousePosition();
498 _lastCursorX = ptMouse.x;
499 _lastCursorY = ptMouse.y;
500
501 MultiSetZPosition(_mainCursor, Z_CURSOR);
502 DoCursorMove();
503 MultiHideObject(_mainCursor);
504
505 _iterationSize = ITERATION_BASE;
506 }
507
508 /**
509 * Called from dec_cursor() Glitter function.
510 * Register the handle to cursor reel data.
511 */
DwInitCursor(SCNHANDLE bfilm)512 void Cursor::DwInitCursor(SCNHANDLE bfilm) {
513 const FILM *pfilm;
514
515 _cursorFilm = bfilm;
516
517 pfilm = (const FILM *)_vm->_handle->LockMem(_cursorFilm);
518 _numTrails = FROM_32(pfilm->numreels) - 1;
519
520 assert(_numTrails <= MAX_TRAILERS);
521 }
522
523 /**
524 * DropCursor is called when a scene is closing down.
525 */
DropCursor()526 void Cursor::DropCursor() {
527 if (TinselV2) {
528 if (_auxCursor)
529 MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _auxCursor);
530 if (_mainCursor)
531 MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _mainCursor);
532
533 _cursorProcessesRestarted = false;
534 }
535
536 _auxCursor = nullptr; // No auxillary cursor
537 _mainCursor = nullptr; // No cursor object (imminently deleted elsewhere)
538 _hiddenCursor = false; // Not hidden in next scene
539 _hiddenTrails = false; // Trailers not hidden in next scene
540 _cursorProcessesStopped = true; // Suspend cursor processes
541
542 for (int i = 0; i < _numTrails; i++) {
543 if (_trailData[i].trailObj != NULL) {
544 MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _trailData[i].trailObj);
545 _trailData[i].trailObj = nullptr;
546 }
547 }
548 }
549
550 /**
551 * RestartCursor is called when a new scene is starting up.
552 */
RestartCursor()553 void Cursor::RestartCursor() {
554 _cursorProcessesRestarted = true; // Get the main cursor to re-initialize
555 }
556
557 /**
558 * Called when restarting the game, ensures correct re-start with NULL
559 * pointers etc.
560 */
RebootCursor()561 void Cursor::RebootCursor() {
562 _mainCursor = _auxCursor = nullptr;
563 for (int i = 0; i < MAX_TRAILERS; i++)
564 _trailData[i].trailObj = nullptr;
565
566 _hiddenCursor = _hiddenTrails = _frozenCursor = false;
567
568 _cursorFilm = 0;
569
570 _cursorProcessesStopped = false;
571 _cursorProcessesRestarted = false;
572 }
573
StartCursorFollowed()574 void Cursor::StartCursorFollowed() {
575 DelAuxCursor();
576
577 if (!SysVar(SV_ENABLEPRINTCURSOR))
578 _tempHiddenCursor = true;
579 }
580
EndCursorFollowed()581 void Cursor::EndCursorFollowed() {
582 _vm->_dialogs->InventoryIconCursor(false); // May be holding something
583 _tempHiddenCursor = false;
584 }
585
isCursorShown()586 bool Cursor::isCursorShown() {
587 return !(_tempHiddenCursor || _hiddenCursor);
588 }
589
AnimateProcess()590 void Cursor::AnimateProcess() {
591 // Step the animation script(s)
592 StepAnimScript(&_mainCursorAnim);
593 if (_auxCursor != NULL)
594 StepAnimScript(&_auxCursorAnim);
595 for (int i = 0; i < _vm->_cursor->NumTrails(); i++) {
596 if (_trailData[i].trailObj != NULL) {
597 if (StepAnimScript(&_trailData[i].trailAnim) == ScriptFinished) {
598 MultiDeleteObject(_vm->_bg->GetPlayfieldList(FIELD_STATUS), _trailData[i].trailObj);
599 _trailData[i].trailObj = nullptr;
600 }
601 }
602 }
603
604 // Move the cursor as appropriate
605 if (!_vm->_cursor->CursorIsFrozen())
606 _vm->_cursor->DoCursorMove();
607 }
608
609 /**
610 * CursorStoppedCheck
611 */
CursorStoppedCheck(CORO_PARAM)612 void CursorStoppedCheck(CORO_PARAM) {
613 // COROUTINE
614 CORO_BEGIN_CONTEXT;
615 CORO_END_CONTEXT(_ctx);
616
617 CORO_BEGIN_CODE(_ctx);
618
619 // If scene is closing down
620 if (_vm->_cursor->_cursorProcessesStopped) {
621 // ...wait for next scene start-up
622 while (!_vm->_cursor->_cursorProcessesRestarted)
623 CORO_SLEEP(1);
624
625 // Re-initialize
626 _vm->_cursor->InitCurObj();
627 _vm->_cursor->InitCurPos();
628 _vm->_dialogs->InventoryIconCursor(false); // May be holding something
629
630 // Re-start the cursor trails
631 _vm->_cursor->_cursorProcessesRestarted = true;
632 _vm->_cursor->_cursorProcessesStopped = false;
633 }
634 CORO_END_CODE;
635 }
636
CanInitializeCursor()637 bool CanInitializeCursor() {
638 if (!_vm->_cursor->HasReelData()) {
639 return false;
640 } else if (TinselVersion != TINSEL_V3) {
641 return (_vm->_bg->BgPal() != 0);
642 }
643 return true;
644 }
645
646 /**
647 * The main cursor process.
648 */
CursorProcess(CORO_PARAM,const void *)649 void CursorProcess(CORO_PARAM, const void *) {
650 // COROUTINE
651 CORO_BEGIN_CONTEXT;
652 CORO_END_CONTEXT(_ctx);
653
654 CORO_BEGIN_CODE(_ctx);
655
656 while (!CanInitializeCursor())
657 CORO_SLEEP(1);
658
659 _vm->_cursor->InitCurObj();
660 _vm->_cursor->InitCurPos();
661 _vm->_dialogs->InventoryIconCursor(false); // May be holding something
662
663 _vm->_cursor->_cursorProcessesStopped = false;
664 _vm->_cursor->_cursorProcessesRestarted = false;
665
666 while (1) {
667 // allow rescheduling
668 CORO_SLEEP(1);
669
670 // Stop/start between scenes
671 CORO_INVOKE_0(CursorStoppedCheck);
672
673 _vm->_cursor->AnimateProcess();
674
675 // If the cursor should be hidden...
676 if (_vm->_cursor->ShouldBeHidden()) {
677 _vm->_cursor->HideCursorProcess();
678
679 // Wait 'til cursor is again required.
680 while (_vm->_cursor->IsHidden()) {
681 CORO_SLEEP(1);
682
683 // Stop/start between scenes
684 CORO_INVOKE_0(CursorStoppedCheck);
685 }
686 }
687 }
688 CORO_END_CODE;
689 }
690
691 } // End of namespace Tinsel
692