421 break; |
419 break; |
422 |
420 |
423 default: NOT_REACHED(); |
421 default: NOT_REACHED(); |
424 } |
422 } |
425 } |
423 } |
426 |
|
427 /** The table/list with animated tiles. */ |
|
428 TileIndex *_animated_tile_list = NULL; |
|
429 /** The number of animated tiles in the current state. */ |
|
430 uint _animated_tile_count = 0; |
|
431 /** The number of slots for animated tiles allocated currently. */ |
|
432 static uint _animated_tile_allocated = 0; |
|
433 |
|
434 /** |
|
435 * Removes the given tile from the animated tile table. |
|
436 * @param tile the tile to remove |
|
437 */ |
|
438 void DeleteAnimatedTile(TileIndex tile) |
|
439 { |
|
440 for (TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { |
|
441 if (tile == *ti) { |
|
442 /* Remove the hole |
|
443 * The order of the remaining elements must stay the same, otherwise the animation loop |
|
444 * may miss a tile; that's why we must use memmove instead of just moving the last element. |
|
445 */ |
|
446 memmove(ti, ti + 1, (_animated_tile_list + _animated_tile_count - (ti + 1)) * sizeof(*ti)); |
|
447 _animated_tile_count--; |
|
448 MarkTileDirtyByTile(tile); |
|
449 return; |
|
450 } |
|
451 } |
|
452 } |
|
453 |
|
454 /** |
|
455 * Add the given tile to the animated tile table (if it does not exist |
|
456 * on that table yet). Also increases the size of the table if necessary. |
|
457 * @param tile the tile to make animated |
|
458 */ |
|
459 void AddAnimatedTile(TileIndex tile) |
|
460 { |
|
461 MarkTileDirtyByTile(tile); |
|
462 |
|
463 for (const TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { |
|
464 if (tile == *ti) return; |
|
465 } |
|
466 |
|
467 /* Table not large enough, so make it larger */ |
|
468 if (_animated_tile_count == _animated_tile_allocated) { |
|
469 _animated_tile_allocated *= 2; |
|
470 _animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated); |
|
471 } |
|
472 |
|
473 _animated_tile_list[_animated_tile_count] = tile; |
|
474 _animated_tile_count++; |
|
475 } |
|
476 |
|
477 /** |
|
478 * Animate all tiles in the animated tile list, i.e.\ call AnimateTile on them. |
|
479 */ |
|
480 void AnimateAnimatedTiles() |
|
481 { |
|
482 const TileIndex *ti = _animated_tile_list; |
|
483 while (ti < _animated_tile_list + _animated_tile_count) { |
|
484 const TileIndex curr = *ti; |
|
485 AnimateTile(curr); |
|
486 /* During the AnimateTile call, DeleteAnimatedTile could have been called, |
|
487 * deleting an element we've already processed and pushing the rest one |
|
488 * slot to the left. We can detect this by checking whether the index |
|
489 * in the current slot has changed - if it has, an element has been deleted, |
|
490 * and we should process the current slot again instead of going forward. |
|
491 * NOTE: this will still break if more than one animated tile is being |
|
492 * deleted during the same AnimateTile call, but no code seems to |
|
493 * be doing this anyway. |
|
494 */ |
|
495 if (*ti == curr) ++ti; |
|
496 } |
|
497 } |
|
498 |
|
499 /** |
|
500 * Initialize all animated tile variables to some known begin point |
|
501 */ |
|
502 void InitializeAnimatedTiles() |
|
503 { |
|
504 _animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, 256); |
|
505 _animated_tile_count = 0; |
|
506 _animated_tile_allocated = 256; |
|
507 } |
|
508 |
|
509 /** |
|
510 * Save the ANIT chunk. |
|
511 */ |
|
512 static void Save_ANIT() |
|
513 { |
|
514 SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list)); |
|
515 SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); |
|
516 } |
|
517 |
|
518 /** |
|
519 * Load the ANIT chunk; the chunk containing the animated tiles. |
|
520 */ |
|
521 static void Load_ANIT() |
|
522 { |
|
523 /* Before version 80 we did NOT have a variable length animated tile table */ |
|
524 if (CheckSavegameVersion(80)) { |
|
525 /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ |
|
526 SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32); |
|
527 |
|
528 for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) { |
|
529 if (_animated_tile_list[_animated_tile_count] == 0) break; |
|
530 } |
|
531 return; |
|
532 } |
|
533 |
|
534 _animated_tile_count = SlGetFieldLength() / sizeof(*_animated_tile_list); |
|
535 |
|
536 /* Determine a nice rounded size for the amount of allocated tiles */ |
|
537 _animated_tile_allocated = 256; |
|
538 while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2; |
|
539 |
|
540 _animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated); |
|
541 SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); |
|
542 } |
|
543 |
|
544 /** |
|
545 * "Definition" imported by the saveload code to be able to load and save |
|
546 * the animated tile table. |
|
547 */ |
|
548 extern const ChunkHandler _animated_tile_chunk_handlers[] = { |
|
549 { 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST}, |
|
550 }; |
|