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 "mads/animation.h"
24 #include "mads/compression.h"
25
26 #define FILENAME_SIZE 13
27
28 namespace MADS {
29
load(Common::SeekableReadStream * f)30 void AAHeader::load(Common::SeekableReadStream *f) {
31 _spriteSetsCount = f->readUint16LE();
32 _miscEntriesCount = f->readUint16LE();
33 _frameEntriesCount = f->readUint16LE();
34 _messagesCount = f->readUint16LE();
35 _loadFlags = f->readUint16LE();
36 _charSpacing = f->readSint16LE();
37 _bgType = (AnimBgType)f->readUint16LE();
38 _roomNumber = f->readUint16LE();
39 f->skip(2);
40 _manualFlag = f->readUint16LE() != 0;
41 _spritesIndex = f->readUint16LE();
42 _scrollPosition.x = f->readSint16LE();
43 _scrollPosition.y = f->readSint16LE();
44 _scrollTicks = f->readUint32LE() & 0xffff;
45 f->skip(6);
46
47 char buffer[FILENAME_SIZE];
48 f->read(buffer, FILENAME_SIZE);
49 buffer[FILENAME_SIZE - 1] = '\0';
50 _backgroundFile = Common::String(buffer);
51
52 for (int i = 0; i < 50; ++i) {
53 f->read(buffer, FILENAME_SIZE);
54 buffer[FILENAME_SIZE - 1] = '\0';
55 if (i < _spriteSetsCount)
56 _spriteSetNames.push_back(Common::String(buffer));
57 }
58
59 f->read(buffer, FILENAME_SIZE);
60 buffer[FILENAME_SIZE - 1] = '\0';
61 _soundName = Common::String(buffer);
62
63 f->skip(13);
64 f->read(buffer, FILENAME_SIZE);
65 buffer[FILENAME_SIZE - 1] = '\0';
66 _dsrName = Common::String(buffer);
67
68 f->read(buffer, FILENAME_SIZE);
69 buffer[FILENAME_SIZE - 1] = '\0';
70 _fontResource = Common::String(buffer);
71 }
72
73 /*------------------------------------------------------------------------*/
74
load(Common::SeekableReadStream * f)75 void AnimMessage::load(Common::SeekableReadStream *f) {
76 _soundId = f->readSint16LE();
77
78 char buffer[64];
79 f->read(&buffer[0], 64);
80 _msg = Common::String(buffer);
81 f->skip(4);
82 _pos.x = f->readSint16LE();
83 _pos.y = f->readSint16LE();
84 _flags = f->readUint16LE();
85 _rgb1[0] = f->readByte() << 2;
86 _rgb1[1] = f->readByte() << 2;
87 _rgb1[2] = f->readByte() << 2;
88 _rgb2[0] = f->readByte() << 2;
89 _rgb2[1] = f->readByte() << 2;
90 _rgb2[2] = f->readByte() << 2;
91 f->skip(2); // Space for kernelMsgIndex
92 _kernelMsgIndex = -1;
93 f->skip(6);
94 _startFrame = f->readUint16LE();
95 _endFrame = f->readUint16LE();
96 f->skip(2);
97 }
98
load(Common::SeekableReadStream * f,bool uiFlag)99 void AnimFrameEntry::load(Common::SeekableReadStream *f, bool uiFlag) {
100 if (uiFlag) {
101 f->skip(2);
102 _frameNumber = -1; // Unused
103 _seqIndex = f->readByte();
104 _spriteSlot._spritesIndex = f->readByte();
105 _spriteSlot._frameNumber = (int8)f->readByte();
106 f->skip(1);
107 _spriteSlot._position.x = f->readSint16LE();
108 _spriteSlot._position.y = f->readSint16LE();
109 } else {
110 _frameNumber = f->readUint16LE();
111 if (_frameNumber & 0x8000)
112 _frameNumber = -(_frameNumber & 0x7fff);
113
114 _seqIndex = f->readByte();
115 _spriteSlot._spritesIndex = f->readByte();
116 _spriteSlot._frameNumber = f->readUint16LE();
117 if (_spriteSlot._frameNumber & 0x8000)
118 _spriteSlot._frameNumber = -(_spriteSlot._frameNumber & 0x7fff);
119
120 _spriteSlot._position.x = f->readSint16LE();
121 _spriteSlot._position.y = f->readSint16LE();
122 _spriteSlot._depth = f->readSByte();
123 _spriteSlot._scale = (int8)f->readByte();
124 }
125 }
126
127 /*------------------------------------------------------------------------*/
128
load(Common::SeekableReadStream * f)129 void AnimMiscEntry::load(Common::SeekableReadStream *f) {
130 _soundId = f->readByte();
131 _msgIndex = f->readSByte();
132 _numTicks = f->readUint16LE();
133 _posAdjust.x = f->readSint16LE();
134 _posAdjust.y = f->readSint16LE();
135 _scroll.x = f->readSByte();
136 _scroll.y = f->readSByte();
137 }
138
139 /*------------------------------------------------------------------------*/
140
load(Common::SeekableReadStream * f)141 void AnimUIEntry::load(Common::SeekableReadStream *f) {
142 _probability = f->readUint16LE();
143 _imageCount = f->readUint16LE();
144 _firstImage = f->readUint16LE();
145 _lastImage = f->readUint16LE();
146 _counter = f->readSint16LE();
147 for (int i = 0; i < ANIM_SPAWN_COUNT; ++i)
148 _spawn[i] = f->readByte();
149 for (int i = 0; i < ANIM_SPAWN_COUNT; ++i)
150 _spawnFrame[i] = f->readUint16LE();
151 _sound = f->readUint16LE() & 0xFF;
152 _soundFrame = f->readUint16LE();
153 }
154
155 /*------------------------------------------------------------------------*/
156
init(MADSEngine * vm,Scene * scene)157 Animation *Animation::init(MADSEngine *vm, Scene *scene) {
158 return new Animation(vm, scene);
159 }
160
Animation(MADSEngine * vm,Scene * scene)161 Animation::Animation(MADSEngine *vm, Scene *scene) : _vm(vm), _scene(scene) {
162 _flags = 0;
163 _font = nullptr;
164 _resetFlag = false;
165 _canChangeView = false;
166 _messageCtr = 0;
167 _skipLoad = false;
168 _freeFlag = false;
169 _unkIndex = -1;
170 _nextFrameTimer = 0;
171 _nextScrollTimer = 0;
172 _trigger = 0;
173 _triggerMode = SEQUENCE_TRIGGER_PREPARE;
174 _actionDetails._verbId = VERB_NONE;
175 _actionDetails._objectNameId = -1;
176 _actionDetails._indirectObjectId = -1;
177 _currentFrame = 0;
178 _oldFrameEntry = 0;
179 _rgbResult = -1;
180 _palIndex1 = _palIndex2 = -1;
181 _dynamicHotspotIndex = -1;
182 }
183
~Animation()184 Animation::~Animation() {
185 Scene &scene = _vm->_game->_scene;
186
187 if (_header._manualFlag)
188 scene._sprites.remove(_spriteListIndexes[_header._spritesIndex]);
189
190 for (int idx = 0; idx < _header._spriteSetsCount; ++idx) {
191 if (!_header._manualFlag || _header._spritesIndex != idx)
192 scene._sprites.remove(_spriteListIndexes[idx]);
193 }
194 }
195
load(MSurface & backSurface,DepthSurface & depthSurface,const Common::String & resName,int flags,Common::Array<PaletteCycle> * palCycles,SceneInfo * sceneInfo)196 void Animation::load(MSurface &backSurface, DepthSurface &depthSurface,
197 const Common::String &resName, int flags, Common::Array<PaletteCycle> *palCycles,
198 SceneInfo *sceneInfo) {
199 Common::String resourceName = resName;
200 if (!resourceName.contains("."))
201 resourceName += ".AA";
202
203 File f(resourceName);
204 MadsPack madsPack(&f);
205
206 Common::SeekableReadStream *stream = madsPack.getItemStream(0);
207 _header.load(stream);
208 delete stream;
209
210 if (_header._bgType == ANIMBG_INTERFACE)
211 flags |= PALFLAG_RESERVED;
212 _flags = flags;
213
214 if (flags & ANIMFLAG_LOAD_BACKGROUND) {
215 loadBackground(backSurface, depthSurface, _header, flags, palCycles, sceneInfo);
216 }
217 if (flags & ANIMFLAG_LOAD_BACKGROUND_ONLY) {
218 // No data
219 _header._messagesCount = 0;
220 _header._frameEntriesCount = 0;
221 _header._miscEntriesCount = 0;
222 }
223
224 // Initialize the reference list
225 _spriteListIndexes.clear();
226 for (int i = 0; i < _header._spriteSetsCount; ++i)
227 _spriteListIndexes.push_back(-1);
228
229 int streamIndex = 1;
230 _messages.clear();
231 if (_header._messagesCount > 0) {
232 // Chunk 2: Following is a list of any messages for the animation
233 Common::SeekableReadStream *msgStream = madsPack.getItemStream(streamIndex++);
234
235 for (int i = 0; i < _header._messagesCount; ++i) {
236 AnimMessage rec;
237 rec.load(msgStream);
238 _messages.push_back(rec);
239 }
240
241 delete msgStream;
242 }
243
244 _frameEntries.clear();
245 if (_header._frameEntriesCount > 0) {
246 // Chunk 3: animation frame info
247 Common::SeekableReadStream *frameStream = madsPack.getItemStream(streamIndex++);
248
249 for (int i = 0; i < _header._frameEntriesCount; i++) {
250 AnimFrameEntry rec;
251 rec.load(frameStream, _header._bgType == ANIMBG_INTERFACE);
252 _frameEntries.push_back(rec);
253 }
254
255 delete frameStream;
256 }
257
258 _miscEntries.clear();
259 _uiEntries.clear();
260 if (_header._miscEntriesCount > 0) {
261 // Chunk 4: Misc Data
262 Common::SeekableReadStream *miscStream = madsPack.getItemStream(streamIndex++);
263
264 if (_header._bgType == ANIMBG_INTERFACE) {
265 for (int i = 0; i < _header._miscEntriesCount; ++i) {
266 AnimUIEntry rec;
267 rec.load(miscStream);
268 _uiEntries.push_back(rec);
269 }
270 } else {
271 for (int i = 0; i < _header._miscEntriesCount; ++i) {
272 AnimMiscEntry rec;
273 rec.load(miscStream);
274 _miscEntries.push_back(rec);
275 }
276 }
277
278 delete miscStream;
279 }
280
281 // If the animation specifies a font, then load it for access
282 delete _font;
283 if (_header._loadFlags & ANIMFLAG_CUSTOM_FONT) {
284 Common::String fontName = "*" + _header._fontResource;
285 _font = _vm->_font->getFont(fontName.c_str());
286 } else {
287 _font = nullptr;
288 }
289
290 // Load all the sprite sets for the animation
291 for (uint i = 0; i < _spriteSets.size(); ++i)
292 delete _spriteSets[i];
293 _spriteSets.clear();
294 _spriteSets.resize(_header._spriteSetsCount);
295
296 for (int i = 0; i < _header._spriteSetsCount; ++i) {
297 if (_header._manualFlag && (i == _header._spritesIndex)) {
298 // Skip over field, since it's manually loaded
299 _spriteSets[i] = nullptr;
300 } else {
301 _spriteSets[i] = new SpriteAsset(_vm, _header._spriteSetNames[i], flags);
302 _spriteListIndexes[i] = _vm->_game->_scene._sprites.add(_spriteSets[i]);
303 }
304 }
305
306 if (_header._manualFlag) {
307 Common::String assetResName = "*" + _header._spriteSetNames[_header._spritesIndex];
308 SpriteAsset *sprites = new SpriteAsset(_vm, assetResName, flags);
309 _spriteSets[_header._spritesIndex] = sprites;
310
311 _spriteListIndexes[_header._spritesIndex] = _scene->_sprites.add(sprites);
312 }
313
314 Common::Array<int> usageList;
315 for (int idx = 0; idx < _header._spriteSetsCount; ++idx)
316 usageList.push_back(_spriteSets[idx]->_usageIndex);
317
318 if (usageList.size() > 0) {
319 int spritesUsageIndex = _spriteSets[0]->_usageIndex;
320 _vm->_palette->_paletteUsage.updateUsage(usageList, spritesUsageIndex);
321 }
322
323 // Remaps the sprite list indexes for frames to the loaded sprite list indexes
324 for (uint i = 0; i < _frameEntries.size(); ++i) {
325 int spriteListIndex = _frameEntries[i]._spriteSlot._spritesIndex;
326 _frameEntries[i]._spriteSlot._spritesIndex = _spriteListIndexes[spriteListIndex];
327 }
328
329 f.close();
330 }
331
preLoad(const Common::String & resName,int level)332 void Animation::preLoad(const Common::String &resName, int level) {
333 // No implementation in ScummVM, since access is fast enough that data
334 // doesn't need to be preloaded
335 }
336
startAnimation(int endTrigger)337 void Animation::startAnimation(int endTrigger) {
338 _messageCtr = 0;
339 _skipLoad = true;
340
341 if (_header._manualFlag) {
342 _unkIndex = -1;
343 //SpriteAsset *asset = _scene->_sprites[_spriteListIndexes[_header._spritesIndex]];
344
345 loadFrame(1);
346 }
347
348 if (_vm->_game->_kernelMode == KERNEL_ACTIVE_CODE)
349 _vm->_palette->refreshSceneColors();
350
351 _currentFrame = 0;
352 _oldFrameEntry = 0;
353 _nextFrameTimer = _vm->_game->_scene._frameStartTime;
354 _trigger = endTrigger;
355 _triggerMode = _vm->_game->_triggerSetupMode;
356 _actionDetails = _vm->_game->_scene._action._activeAction;
357
358 for (int idx = 0; idx < _header._messagesCount; ++idx) {
359 _messages[idx]._kernelMsgIndex = -1;
360 }
361 }
362
loadFrame(int frameNumber)363 void Animation::loadFrame(int frameNumber) {
364 Scene &scene = _vm->_game->_scene;
365 if (_skipLoad)
366 return;
367
368 Common::Point pt;
369 int spriteListIndex = _spriteListIndexes[_header._spritesIndex];
370 SpriteAsset &spriteSet = *scene._sprites[spriteListIndex];
371
372 if (_unkIndex < 0) {
373 MSurface *frame = spriteSet.getFrame(0);
374 pt.x = frame->getBounds().left;
375 pt.y = frame->getBounds().top;
376 } else {
377 pt.x = _unkList[_unkIndex].x;
378 pt.y = _unkList[_unkIndex].y;
379 _unkIndex = 1 - _unkIndex;
380 warning("LoadFrame - Using unknown array");
381 }
382
383 if (drawFrame(spriteSet, pt, frameNumber))
384 error("drawFrame failure");
385 }
386
drawFrame(SpriteAsset & spriteSet,const Common::Point & pt,int frameNumber)387 bool Animation::drawFrame(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber) {
388 return 0;
389 }
390
loadBackground(MSurface & backSurface,DepthSurface & depthSurface,AAHeader & header,int flags,Common::Array<PaletteCycle> * palCycles,SceneInfo * sceneInfo)391 void Animation::loadBackground(MSurface &backSurface, DepthSurface &depthSurface,
392 AAHeader &header, int flags, Common::Array<PaletteCycle> *palCycles, SceneInfo *sceneInfo) {
393 _scene->_depthStyle = 0;
394 if (header._bgType <= ANIMBG_FULL_SIZE) {
395 _vm->_palette->_paletteUsage.setEmpty();
396 sceneInfo->load(header._roomNumber, 0, header._backgroundFile, flags, depthSurface, backSurface);
397 _scene->_depthStyle = sceneInfo->_depthStyle == 2 ? 1 : 0;
398 if (palCycles) {
399 palCycles->clear();
400 for (uint i = 0; i < sceneInfo->_paletteCycles.size(); ++i)
401 palCycles->push_back(sceneInfo->_paletteCycles[i]);
402 }
403 } else if (header._bgType == ANIMBG_INTERFACE) {
404 // Load a scene interface
405 Common::String resourceName = "*" + header._backgroundFile;
406 backSurface.load(resourceName);
407
408 if (palCycles)
409 palCycles->clear();
410 } else {
411 // Original has useless code here
412 }
413 }
414
hasScroll() const415 bool Animation::hasScroll() const {
416 return (_header._scrollPosition.x != 0) || (_header._scrollPosition.y != 0);
417 }
418
update()419 void Animation::update() {
420 Scene &scene = _vm->_game->_scene;
421 Palette &palette = *_vm->_palette;
422
423 if (_header._manualFlag) {
424 int spriteListIndex = _spriteListIndexes[_header._spritesIndex];
425 int newIndex = -1;
426
427 for (uint idx = _oldFrameEntry; idx < _frameEntries.size(); ++idx) {
428 if (_frameEntries[idx]._frameNumber > _currentFrame)
429 break;
430 if (_frameEntries[idx]._spriteSlot._spritesIndex == spriteListIndex)
431 newIndex = _frameEntries[idx]._spriteSlot._frameNumber;
432 }
433
434 if (newIndex >= 0)
435 loadFrame(newIndex);
436 }
437
438 // If it's not time for the next frame, then exit
439 if (_vm->_game->_scene._frameStartTime < _nextFrameTimer)
440 return;
441
442 // Erase any active sprites
443 eraseSprites();
444
445 // Validate the current frame
446 if (_currentFrame >= (int)_miscEntries.size()) {
447 // Is the animation allowed to be repeated?
448 if (_resetFlag) {
449 _currentFrame = 0;
450 _oldFrameEntry = 0;
451 } else {
452 _freeFlag = true;
453 return;
454 }
455 }
456
457 // Handle executing any sound command for this frame
458 AnimMiscEntry &misc = _miscEntries[_currentFrame];
459 if (misc._soundId)
460 _vm->_sound->command(misc._soundId);
461
462 // Handle any screen scrolling
463 if (hasScroll()) {
464 scene._backgroundSurface.scrollX(_header._scrollPosition.x);
465 scene._backgroundSurface.scrollY(_header._scrollPosition.y);
466 scene._spriteSlots.fullRefresh();
467 }
468
469 bool isV2 = (_vm->getGameID() != GType_RexNebular);
470 if (isV2 && _canChangeView) {
471 // Handle any offset adjustment for sprites as of this frame
472 bool paChanged = false;
473 if (getFramePosAdjust(_currentFrame).x != scene._posAdjust.x) {
474 scene._posAdjust.x = getFramePosAdjust(_currentFrame).x;
475 paChanged = true;
476 }
477
478 if (getFramePosAdjust(_currentFrame).y != scene._posAdjust.y) {
479 scene._posAdjust.y = getFramePosAdjust(_currentFrame).y;
480 paChanged = true;
481 }
482
483 if (paChanged) {
484 int newIndex = scene._spriteSlots.add();
485 scene._spriteSlots[newIndex]._seqIndex = -1;
486 scene._spriteSlots[newIndex]._flags = IMG_REFRESH;
487 }
488 }
489
490 // Main frame animation loop - frames get animated by being placed, as necessary, into the
491 // main sprite slot array
492 while ((uint)_oldFrameEntry < _frameEntries.size()) {
493 if (_frameEntries[_oldFrameEntry]._frameNumber > _currentFrame)
494 break;
495 else if (_frameEntries[_oldFrameEntry]._frameNumber == _currentFrame) {
496 // Found the correct frame
497 int spriteSlotIndex = 0;
498 int index = 0;
499
500 for (;;) {
501 if ((spriteSlotIndex == 0) && (index < (int)scene._spriteSlots.size())) {
502 int seqIndex = _frameEntries[_oldFrameEntry]._seqIndex - scene._spriteSlots[index]._seqIndex;
503 if (seqIndex == 0x80) {
504 if (scene._spriteSlots[index] == _frameEntries[_oldFrameEntry]._spriteSlot) {
505 scene._spriteSlots[index]._flags = IMG_STATIC;
506 spriteSlotIndex = -1;
507 }
508 }
509 ++index;
510 continue;
511 }
512
513 if (spriteSlotIndex == 0) {
514 int slotIndex = scene._spriteSlots.add();
515 SpriteSlot &slot = scene._spriteSlots[slotIndex];
516 slot.copy(_frameEntries[_oldFrameEntry]._spriteSlot);
517 slot._seqIndex = _frameEntries[_oldFrameEntry]._seqIndex + 0x80;
518
519 SpriteAsset &spriteSet = *scene._sprites[
520 scene._spriteSlots[slotIndex]._spritesIndex];
521 slot._flags = spriteSet.isBackground() ? IMG_DELTA : IMG_UPDATE;
522 }
523 break;
524 }
525 }
526
527 ++_oldFrameEntry;
528 }
529
530 // Handle the display of any messages
531 for (uint idx = 0; idx < _messages.size(); ++idx) {
532 if (_messages[idx]._kernelMsgIndex >= 0) {
533 // Handle currently active message
534 if ((_currentFrame < _messages[idx]._startFrame) || (_currentFrame > _messages[idx]._endFrame)) {
535 scene._kernelMessages.remove(_messages[idx]._kernelMsgIndex);
536 _messages[idx]._kernelMsgIndex = -1;
537 --_messageCtr;
538 }
539 } else if ((_currentFrame >= _messages[idx]._startFrame) && (_currentFrame <= _messages[idx]._endFrame)) {
540 // Start displaying the message
541 AnimMessage &me = _messages[idx];
542
543 if (_flags & ANIMFLAG_ANIMVIEW) {
544 _rgbResult = palette._paletteUsage.checkRGB(me._rgb1, -1, true, &_palIndex1);
545 _rgbResult = palette._paletteUsage.checkRGB(me._rgb2, _rgbResult, true, &_palIndex2);
546
547 // Update the palette with the two needed colors
548 int palStart = MIN(_palIndex1, _palIndex2);
549 int palCount = ABS(_palIndex2 - _palIndex1) + 1;
550 palette.setPalette(&palette._mainPalette[palStart * 3], palStart, palCount);
551 } else {
552 // The color index to use is dependant on how many messages are currently on-screen
553 switch (_messageCtr) {
554 case 1:
555 _palIndex1 = 252;
556 break;
557 case 2:
558 _palIndex1 = 16;
559 break;
560 default:
561 _palIndex1 = 250;
562 break;
563 }
564 _palIndex2 = _palIndex1 + 1;
565
566 _vm->_palette->setEntry(_palIndex1, me._rgb1[0], me._rgb1[1], me._rgb1[2]);
567 _vm->_palette->setEntry(_palIndex2, me._rgb2[0], me._rgb2[1], me._rgb2[2]);
568 }
569
570 // Add a kernel message to display the given text
571 me._kernelMsgIndex = scene._kernelMessages.add(me._pos,
572 _palIndex1 | (_palIndex2 << 8),
573 0, 0, INDEFINITE_TIMEOUT, me._msg);
574 assert(me._kernelMsgIndex >= 0);
575 ++_messageCtr;
576
577 // If there's an accompanying sound, also play it
578 if (me._soundId > 0)
579 _vm->_audio->playSound(me._soundId - 1);
580 }
581 }
582
583 // Move to the next frame
584 _currentFrame++;
585 if (_currentFrame >= (int)_miscEntries.size()) {
586 // Animation is complete
587 if (_trigger != 0) {
588 _vm->_game->_trigger = _trigger;
589 _vm->_game->_triggerMode = _triggerMode;
590
591 if (_triggerMode != SEQUENCE_TRIGGER_DAEMON) {
592 // Copy the noun list
593 scene._action._activeAction = _actionDetails;
594 }
595 }
596 }
597
598 int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1);
599 _nextFrameTimer = _vm->_game->_scene._frameStartTime + _miscEntries[frameNum]._numTicks;
600 }
601
setCurrentFrame(int frameNumber)602 void Animation::setCurrentFrame(int frameNumber) {
603 _currentFrame = frameNumber;
604 _oldFrameEntry = 0;
605 _freeFlag = false;
606 }
607
setNextFrameTimer(uint32 newTimer)608 void Animation::setNextFrameTimer(uint32 newTimer) {
609 _nextFrameTimer = newTimer;
610 }
611
eraseSprites()612 void Animation::eraseSprites() {
613 Scene &scene = _vm->_game->_scene;
614
615 for (uint idx = 0; idx < scene._spriteSlots.size(); ++idx) {
616 if (scene._spriteSlots[idx]._seqIndex >= 0x80)
617 scene._spriteSlots[idx]._flags = IMG_ERASE;
618 }
619 }
620
getFramePosAdjust(int idx)621 Common::Point Animation::getFramePosAdjust(int idx) {
622 warning("TODO: Implement getFramePosAdjust");
623
624 return Common::Point(0, 0);
625 }
626 } // End of namespace MADS
627