added optional button to restart game (door, panel and touch variants)
[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 //                  https://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(void)
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     Debug("snapshot:FreeSnapshotList_UpToNode", "[%s, %d, %d]",
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(void)
115 {
116 #if DEBUG_SNAPSHOTS
117   Debug("snapshot:FreeSnapshotList", "");
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 static void ReduceSnapshotList(void)
131 {
132 #if DEBUG_SNAPSHOTS
133   int num_snapshots_last = num_snapshots;
134 #endif
135
136   // maximum number of snapshots exceeded -- thin out list of snapshots
137   ListNode *node = snapshot_list;
138   int num_snapshots_to_skip = num_snapshots / 10;
139
140   // do not remove the newest snapshots from the list
141   while (node && num_snapshots_to_skip--)
142     node = node->next;
143
144   // remove every second snapshot from the remaining list
145   while (node)
146   {
147     // never delete the first list node (snapshot at game start)
148     if (node->next == NULL)
149       break;
150
151     // in alternation, delete one node from the list ...
152     deleteNodeFromList(&node, node->key, FreeSnapshot);
153     num_snapshots--;
154
155     // ... and keep one node (which always exists here)
156     node = node->next;
157   }
158
159 #if DEBUG_SNAPSHOTS
160   Debug("snapshot:ReduceSnapshotList",
161         "(Reducing number of snapshots from %d to %d.)",
162         num_snapshots_last, num_snapshots);
163
164 #if 0
165   node = snapshot_list;
166   while (node)
167   {
168     Debug("snapshot:ReduceSnapshotList", "key: %s", node->key);
169
170     node = node->next;
171   }
172 #endif
173 #endif
174 }
175
176 void SaveSnapshotSingle(ListNode *snapshot_buffers)
177 {
178   if (snapshot_single)
179     FreeSnapshotSingle();
180
181   snapshot_single = snapshot_buffers;
182 }
183
184 void SaveSnapshotToList(ListNode *snapshot_buffers)
185 {
186   if (snapshot_current != snapshot_list)
187     FreeSnapshotList_UpToNode(snapshot_current);
188
189 #if DEBUG_SNAPSHOTS
190   Debug("snapshot:SaveSnapshotToList",
191         "[%d] [%d snapshots, %d buffers, %d bytes]",
192         next_snapshot_key, num_snapshots,
193         num_snapshot_buffers, num_snapshot_bytes);
194 #endif
195
196   addNodeToList(&snapshot_list, i_to_a(next_snapshot_key),
197                 snapshot_buffers);
198
199   snapshot_current = snapshot_list;
200
201   num_snapshots++;
202   next_snapshot_key++;
203
204   if (num_snapshot_bytes > setup.engine_snapshot_memory)
205     ReduceSnapshotList();
206 }
207
208 boolean LoadSnapshotSingle(void)
209 {
210   if (snapshot_single)
211   {
212     LoadSnapshotBuffers(snapshot_single);
213
214     return TRUE;
215   }
216
217   return FALSE;
218 }
219
220 boolean LoadSnapshotFromList_Older(int steps)
221 {
222   if (snapshot_current && snapshot_current->next)
223   {
224     while (snapshot_current->next && steps--)
225       snapshot_current = snapshot_current->next;
226
227     LoadSnapshotBuffers(snapshot_current->content);
228
229 #if DEBUG_SNAPSHOTS
230     Debug("snapshot:LoadSnapshotFromList_Older", "[%s]", snapshot_current->key);
231 #endif
232
233     return TRUE;
234   }
235
236   return FALSE;
237 }
238
239 boolean LoadSnapshotFromList_Newer(int steps)
240 {
241   if (snapshot_current && snapshot_current->prev)
242   {
243     while (snapshot_current->prev && steps--)
244       snapshot_current = snapshot_current->prev;
245
246     LoadSnapshotBuffers(snapshot_current->content);
247
248 #if DEBUG_SNAPSHOTS
249     Debug("snapshot:LoadSnapshotFromList_Newer", "[%s]", snapshot_current->key);
250 #endif
251
252     return TRUE;
253   }
254
255   return FALSE;
256 }
257
258 boolean CheckSnapshotList(void)
259 {
260   return (snapshot_list ? TRUE : FALSE);
261 }