|
1 /* $Id$ */ |
|
2 |
|
3 /** @file animated_tile.cpp Everything related to animated tiles. */ |
|
4 |
|
5 #include "stdafx.h" |
|
6 #include "openttd.h" |
|
7 #include "saveload.h" |
|
8 #include "landscape.h" |
|
9 #include "core/alloc_func.hpp" |
|
10 #include "functions.h" |
|
11 |
|
12 /** The table/list with animated tiles. */ |
|
13 TileIndex *_animated_tile_list = NULL; |
|
14 /** The number of animated tiles in the current state. */ |
|
15 uint _animated_tile_count = 0; |
|
16 /** The number of slots for animated tiles allocated currently. */ |
|
17 static uint _animated_tile_allocated = 0; |
|
18 |
|
19 /** |
|
20 * Removes the given tile from the animated tile table. |
|
21 * @param tile the tile to remove |
|
22 */ |
|
23 void DeleteAnimatedTile(TileIndex tile) |
|
24 { |
|
25 for (TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { |
|
26 if (tile == *ti) { |
|
27 /* Remove the hole |
|
28 * The order of the remaining elements must stay the same, otherwise the animation loop |
|
29 * may miss a tile; that's why we must use memmove instead of just moving the last element. |
|
30 */ |
|
31 memmove(ti, ti + 1, (_animated_tile_list + _animated_tile_count - (ti + 1)) * sizeof(*ti)); |
|
32 _animated_tile_count--; |
|
33 MarkTileDirtyByTile(tile); |
|
34 return; |
|
35 } |
|
36 } |
|
37 } |
|
38 |
|
39 /** |
|
40 * Add the given tile to the animated tile table (if it does not exist |
|
41 * on that table yet). Also increases the size of the table if necessary. |
|
42 * @param tile the tile to make animated |
|
43 */ |
|
44 void AddAnimatedTile(TileIndex tile) |
|
45 { |
|
46 MarkTileDirtyByTile(tile); |
|
47 |
|
48 for (const TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { |
|
49 if (tile == *ti) return; |
|
50 } |
|
51 |
|
52 /* Table not large enough, so make it larger */ |
|
53 if (_animated_tile_count == _animated_tile_allocated) { |
|
54 _animated_tile_allocated *= 2; |
|
55 _animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated); |
|
56 } |
|
57 |
|
58 _animated_tile_list[_animated_tile_count] = tile; |
|
59 _animated_tile_count++; |
|
60 } |
|
61 |
|
62 /** |
|
63 * Animate all tiles in the animated tile list, i.e.\ call AnimateTile on them. |
|
64 */ |
|
65 void AnimateAnimatedTiles() |
|
66 { |
|
67 const TileIndex *ti = _animated_tile_list; |
|
68 while (ti < _animated_tile_list + _animated_tile_count) { |
|
69 const TileIndex curr = *ti; |
|
70 AnimateTile(curr); |
|
71 /* During the AnimateTile call, DeleteAnimatedTile could have been called, |
|
72 * deleting an element we've already processed and pushing the rest one |
|
73 * slot to the left. We can detect this by checking whether the index |
|
74 * in the current slot has changed - if it has, an element has been deleted, |
|
75 * and we should process the current slot again instead of going forward. |
|
76 * NOTE: this will still break if more than one animated tile is being |
|
77 * deleted during the same AnimateTile call, but no code seems to |
|
78 * be doing this anyway. |
|
79 */ |
|
80 if (*ti == curr) ++ti; |
|
81 } |
|
82 } |
|
83 |
|
84 /** |
|
85 * Initialize all animated tile variables to some known begin point |
|
86 */ |
|
87 void InitializeAnimatedTiles() |
|
88 { |
|
89 _animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, 256); |
|
90 _animated_tile_count = 0; |
|
91 _animated_tile_allocated = 256; |
|
92 } |
|
93 |
|
94 /** |
|
95 * Save the ANIT chunk. |
|
96 */ |
|
97 static void Save_ANIT() |
|
98 { |
|
99 SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list)); |
|
100 SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); |
|
101 } |
|
102 |
|
103 /** |
|
104 * Load the ANIT chunk; the chunk containing the animated tiles. |
|
105 */ |
|
106 static void Load_ANIT() |
|
107 { |
|
108 /* Before version 80 we did NOT have a variable length animated tile table */ |
|
109 if (CheckSavegameVersion(80)) { |
|
110 /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ |
|
111 SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32); |
|
112 |
|
113 for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) { |
|
114 if (_animated_tile_list[_animated_tile_count] == 0) break; |
|
115 } |
|
116 return; |
|
117 } |
|
118 |
|
119 _animated_tile_count = SlGetFieldLength() / sizeof(*_animated_tile_list); |
|
120 |
|
121 /* Determine a nice rounded size for the amount of allocated tiles */ |
|
122 _animated_tile_allocated = 256; |
|
123 while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2; |
|
124 |
|
125 _animated_tile_list = ReallocT<TileIndex>(_animated_tile_list, _animated_tile_allocated); |
|
126 SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); |
|
127 } |
|
128 |
|
129 /** |
|
130 * "Definition" imported by the saveload code to be able to load and save |
|
131 * the animated tile table. |
|
132 */ |
|
133 extern const ChunkHandler _animated_tile_chunk_handlers[] = { |
|
134 { 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST}, |
|
135 }; |