added (optional) tape buttons to insert or play solution tape
[rocksndiamonds.git] / src / libgame / snapshot.c
1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // snapshot.c
10 // ============================================================================
11
12 #include "snapshot.h"
13
14
15 #ifdef DEBUG
16 #define DEBUG_SNAPSHOTS                 0
17 #endif
18
19 static ListNode *snapshot_single = NULL;
20 static ListNode *snapshot_list = NULL;
21 static ListNode *snapshot_current = NULL;
22
23 static int num_snapshots = 0;
24 static int num_snapshot_buffers = 0;
25 static int num_snapshot_bytes = 0;
26 static int next_snapshot_key = 0;
27
28
29 // -----------------------------------------------------------------------------
30 // functions for handling buffers for a single snapshot
31 // -----------------------------------------------------------------------------
32
33 void SaveSnapshotBuffer(ListNode **snapshot_buffers, void *buffer, int size)
34 {
35   struct SnapshotNodeInfo *bi =
36     checked_calloc(sizeof(struct SnapshotNodeInfo));
37
38   bi->buffer_orig = buffer;
39   bi->buffer_copy = checked_malloc(size);
40   bi->size = size;
41
42   memcpy(bi->buffer_copy, buffer, size);
43
44   addNodeToList(snapshot_buffers, NULL, bi);
45
46   num_snapshot_buffers++;
47   num_snapshot_bytes += size;
48 }
49
50 static void LoadSnapshotBuffer(struct SnapshotNodeInfo *bi)
51 {
52   memcpy(bi->buffer_orig, bi->buffer_copy, bi->size);
53 }
54
55 void LoadSnapshotBuffers(ListNode *snapshot_buffers)
56 {
57   while (snapshot_buffers != NULL)
58   {
59     LoadSnapshotBuffer((struct SnapshotNodeInfo *)snapshot_buffers->content);
60
61     snapshot_buffers = snapshot_buffers->next;
62   }
63 }
64
65 static void FreeSnapshotBuffer(void *bi_raw)
66 {
67   struct SnapshotNodeInfo *bi = (struct SnapshotNodeInfo *)bi_raw;
68
69   num_snapshot_buffers--;
70   num_snapshot_bytes -= bi->size;
71
72   checked_free(bi->buffer_copy);
73   checked_free(bi);
74 }
75
76 void FreeSnapshotBuffers(ListNode *snapshot_buffers)
77 {
78   while (snapshot_buffers != NULL)
79     deleteNodeFromList(&snapshot_buffers, NULL, FreeSnapshotBuffer);
80 }
81
82 // -----------------------------------------------------------------------------
83 // functions for handling single shapshot or list of snapshots
84 // -----------------------------------------------------------------------------
85
86 static void FreeSnapshot(void *snapshot_buffers_ptr)
87 {
88   FreeSnapshotBuffers(snapshot_buffers_ptr);
89 }
90
91 void FreeSnapshotSingle()
92 {
93   FreeSnapshotBuffers(snapshot_single);
94
95   snapshot_single = NULL;
96 }
97
98 static void FreeSnapshotList_UpToNode(ListNode *node)
99 {
100   while (snapshot_list != node)
101   {
102 #if DEBUG_SNAPSHOTS
103     printf("::: FreeSnapshotList_*() [%s, %d, %d]\n",
104            snapshot_list->key, num_snapshot_buffers, num_snapshot_bytes);
105 #endif
106
107     deleteNodeFromList(&snapshot_list, snapshot_list->key, FreeSnapshot);
108
109     num_snapshots--;
110     next_snapshot_key = (snapshot_list ? atoi(snapshot_list->key) + 1 : 0);
111   }
112 }
113
114 void FreeSnapshotList()
115 {
116 #if DEBUG_SNAPSHOTS
117   printf("::: FreeSnapshotList()\n");
118 #endif
119
120   FreeSnapshotList_UpToNode(NULL);
121
122   num_snapshots = 0;
123   num_snapshot_buffers = 0;
124   num_snapshot_bytes = 0;
125   next_snapshot_key = 0;
126
127   snapshot_current = NULL;
128 }
129
130 void ReduceSnapshotList()
131 {
132 #if DEBUG_SNAPSHOTS
133   printf("::: (Reducing number of snapshots from %d ",
134          num_snapshots);
135 #endif
136
137   // maximum number of snapshots exceeded -- thin out list of snapshots
138   ListNode *node = snapshot_list;
139   int num_snapshots_to_skip = num_snapshots / 10;
140
141   // do not remove the newest snapshots from the list
142   while (node && num_snapshots_to_skip--)
143     node = node->next;
144
145   // remove every second snapshot from the remaining list
146   while (node)
147   {
148     // never delete the first list node (snapshot at game start)
149     if (node->next == NULL)
150       break;
151
152     // in alternation, delete one node from the list ...
153     deleteNodeFromList(&node, node->key, FreeSnapshot);
154     num_snapshots--;
155
156     // ... and keep one node (which always exists here)
157     node = node->next;
158   }
159
160 #if DEBUG_SNAPSHOTS
161   printf("to %d.)\n", num_snapshots);
162
163 #if 0
164   node = snapshot_list;
165   while (node)
166   {
167     printf("::: key: %s\n", node->key);
168     node = node->next;
169   }
170 #endif
171 #endif
172 }
173
174 void SaveSnapshotSingle(ListNode *snapshot_buffers)
175 {
176   if (snapshot_single)
177     FreeSnapshotSingle();
178
179   snapshot_single = snapshot_buffers;
180 }
181
182 void SaveSnapshotToList(ListNode *snapshot_buffers)
183 {
184   if (snapshot_current != snapshot_list)
185     FreeSnapshotList_UpToNode(snapshot_current);
186
187 #if DEBUG_SNAPSHOTS
188   printf("::: SaveSnapshotToList() [%d] [%d snapshots, %d buffers, %d bytes]\n",
189          next_snapshot_key, num_snapshots,
190          num_snapshot_buffers, num_snapshot_bytes);
191 #endif
192
193   addNodeToList(&snapshot_list, i_to_a(next_snapshot_key),
194                 snapshot_buffers);
195
196   snapshot_current = snapshot_list;
197
198   num_snapshots++;
199   next_snapshot_key++;
200
201   if (num_snapshot_bytes > setup.engine_snapshot_memory)
202     ReduceSnapshotList();
203 }
204
205 boolean LoadSnapshotSingle()
206 {
207   if (snapshot_single)
208   {
209     LoadSnapshotBuffers(snapshot_single);
210
211     return TRUE;
212   }
213
214   return FALSE;
215 }
216
217 boolean LoadSnapshotFromList_Older(int steps)
218 {
219   if (snapshot_current && snapshot_current->next)
220   {
221     while (snapshot_current->next && steps--)
222       snapshot_current = snapshot_current->next;
223
224     LoadSnapshotBuffers(snapshot_current->content);
225
226 #if DEBUG_SNAPSHOTS
227     printf("::: LoadSnapshotFromList_Older() [%s]\n", snapshot_current->key);
228 #endif
229
230     return TRUE;
231   }
232
233   return FALSE;
234 }
235
236 boolean LoadSnapshotFromList_Newer(int steps)
237 {
238   if (snapshot_current && snapshot_current->prev)
239   {
240     while (snapshot_current->prev && steps--)
241       snapshot_current = snapshot_current->prev;
242
243     LoadSnapshotBuffers(snapshot_current->content);
244
245 #if DEBUG_SNAPSHOTS
246     printf("::: LoadSnapshotFromList_Newer() [%s]\n", snapshot_current->key);
247 #endif
248
249     return TRUE;
250   }
251
252   return FALSE;
253 }
254
255 boolean CheckSnapshotList()
256 {
257   return (snapshot_list ? TRUE : FALSE);
258 }