1 /*
2     Copyright (C) 2005-2007 Tom Beaumont
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 
20 struct HexPuzzle;
21 
22 class LevelSave
23 {
24 	friend struct HexPuzzle;
25 
26 	// CHECKME: If char is larger than 8 bits (== 1 byte???)
27 	// the code is no longer big endian save? SWAP16/32 is necessary?
28 	// Or is a byte always of the same size as char, e.g. 16 bits, so
29 	// that int16_t is equally saved on big and little endian systems?
30 	char * bestSolution;
31 	int32_t bestSolutionLength;
32 	int32_t bestScore;
33 	#define NUM_LAST_SCORES 19
34 	int32_t lastScores[NUM_LAST_SCORES];
35 	int32_t unlocked;
36 public:
LevelSave()37 	LevelSave()
38 	{
39 		Clear();
40 	}
Clear()41 	void Clear()
42 	{
43 		unlocked = 0;
44 		bestSolution = 0;
45 		bestScore = 0;
46 		bestSolutionLength = 0;
47 		memset(lastScores, 0, sizeof(lastScores));
48 	}
LoadSave(FILE * f,bool save)49 	void LoadSave(FILE* f, bool save)
50 	{
51 		typedef unsigned int _fn(void*, unsigned int, unsigned int, FILE*);
52 		_fn * fn = save ? (_fn*)fwrite : (_fn*)fread;
53 
54 		// we write little endian data
55 		bestSolutionLength = SWAP32(bestSolutionLength);
56 		bestScore = SWAP32(bestScore);
57 		for (int i=0; i<NUM_LAST_SCORES; ++i)
58 			lastScores[i] = SWAP32(lastScores[i]);
59 		unlocked = SWAP32(unlocked);
60 
61 		fn(&bestSolutionLength, sizeof(bestSolutionLength), 1, f);
62 		fn(&bestScore, sizeof(bestScore), 1, f);
63 		fn(&lastScores, sizeof(lastScores), 1, f);
64 		fn(&unlocked, sizeof(unlocked), 1, f);
65 
66 		bestSolutionLength = SWAP32(bestSolutionLength);
67 		bestScore = SWAP32(bestScore);
68 		for (int i=0; i<NUM_LAST_SCORES; ++i)
69 			lastScores[i] = SWAP32(lastScores[i]);
70 		unlocked = SWAP32(unlocked);
71 
72 		if (bestSolutionLength)
73 		{
74 			if (!save) SetSolution(bestSolutionLength);
75 			fn(bestSolution, sizeof(bestSolution[0]), bestSolutionLength, f);
76 		}
77 	}
78 
Dump()79 	void Dump()
80 	{
81 		for (int j=1; j<NUM_LAST_SCORES; j++)
82 			if (lastScores[j]==lastScores[0])
83 				lastScores[j] = 0;
84 
85 /*		for (int i=0; i<NUM_LAST_SCORES && lastScores[i]; i++)
86 			if (lastScores[i] != bestScore)
87 				printf("\t% 8d\n", lastScores[i]);*/
88 	}
Completed()89 	bool Completed()
90 	{
91 		return bestScore != 0;
92 	}
IsNewCompletionBetter(int score)93 	bool IsNewCompletionBetter(int score)
94 	{
95 		for (int i=0; i<NUM_LAST_SCORES; i++)
96 		{
97 			if (lastScores[i]==0)
98 				lastScores[i] = score;
99 			if (lastScores[i]==score)
100 				break;
101 		}
102 
103 		if (!Completed())
104 			return true;
105 
106 		return score <= bestScore;
107 	}
BeatsPar(int par)108 	bool BeatsPar(int par)
109 	{
110 		if (!Completed())
111 			return false;
112 		return bestScore < par;
113 	}
PassesPar(int par)114 	bool PassesPar(int par)
115 	{
116 		if (!Completed())
117 			return false;
118 		return bestScore <= par;
119 	}
GetScore()120 	int GetScore()
121 	{
122 		return bestScore;
123 	}
SetScore(int s)124 	void SetScore(int s)
125 	{
126 		bestScore = s;
127 	}
SetSolution(int l)128 	void SetSolution(int l) {
129 		delete [] bestSolution;
130 		bestSolutionLength = l;
131 		bestSolution = new char [ l ];
132 	}
SetSolutionStep(int pos,int val)133 	void SetSolutionStep(int pos, int val)
134 	{
135 		bestSolution[pos] = val;
136 	}
137 };
138 
139 class SaveState
140 {
141 	struct X : public LevelSave
142 	{
143 		X* next;
144 		char* name;
145 
nextX146 		X(const char* n, X* nx=0) : next(nx)
147 		{
148 			name = new char[strlen(n)+1];
149 			strcpy(name, n);
150 		}
~XX151 		~X()
152 		{
153 			delete [] name;
154 		}
155 	};
156 
157 	struct General {
158     /// Change big endian data into little endian data, do nothing on little endian systems
SwapBytesGeneral159 		void SwapBytes()
160 		{
161 			scoringOn = SWAP32(scoringOn);
162 			hintFlags = SWAP32(hintFlags);
163 			completionPercentage = SWAP32(completionPercentage);
164 			endSequence = SWAP32(endSequence);
165 			masteredPercentage = SWAP32(masteredPercentage);
166 			for (unsigned int i=0; i<sizeof(pad)/sizeof(int32_t); ++i)
167 				pad[i] = SWAP32(pad[i]);
168 		}
169 		int32_t scoringOn;
170 		int32_t hintFlags;
171 		int32_t completionPercentage;
172 		int32_t endSequence;
173 		int32_t masteredPercentage;
174 		int32_t pad[6];
175 	};
176 
177 	X* first;
178 
ClearRaw()179 	void ClearRaw()
180 	{
181 		memset(&general, 0, sizeof(general));
182 		general.hintFlags = 1<<31 | 1<<30;
183 
184 		X* x=first;
185 		while (x)
186 		{
187 			X* nx = x->next;
188 			delete x;
189 			x = nx;
190 		}
191 		first = 0;
192 
193 	}
194 
195 public:
196 
197 	General general;
198 
199 
SaveState()200 	SaveState() : first(0)
201 	{
202 		Clear();
203 	}
204 
~SaveState()205 	~SaveState()
206 	{
207 		ClearRaw();
208 	}
209 
Clear()210 	void Clear()
211 	{
212 		ClearRaw();
213 		ApplyStuff();
214 	}
215 
216 	void GetStuff();
217 	void ApplyStuff();
218 
LoadSave(FILE * f,bool save)219 	void LoadSave(FILE* f, bool save)
220 	{
221 		if (save)
222 		{
223 			GetStuff();
224 
225 			//printf("----\n");
226 
227 			fputc('2', f);
228 			general.SwapBytes(); // big==>little endian
229 			fwrite(&general, sizeof(general), 1, f);
230 			general.SwapBytes(); // revert changes
231 			for(X* x=first; x; x=x->next)
232 			{
233 				int16_t len = strlen(x->name);
234 				len = SWAP16(len);
235 				fwrite(&len, sizeof(len), 1, f);
236 				len = SWAP16(len);
237 				fwrite(x->name, 1, len, f);
238 
239 				x->LoadSave(f,save);
240 
241 				if (x->Completed())
242 				{
243 					//printf("% 8d %s\n", x->GetScore(), x->name);
244 					x->Dump();
245 				}
246 			}
247 		}
248 		else
249 		{
250 			ClearRaw();
251 			int v = fgetc(f);
252 			if (v=='2')
253 			{
254 				fread(&general, sizeof(general), 1, f);
255 				general.SwapBytes();
256 				v = '1';
257 			}
258 			if (v=='1')
259 			{
260 				while(!feof(f))
261 				{
262 					char temp[1000];
263 					int16_t len;
264 					fread(&len, sizeof(len), 1, f);
265 					len = SWAP16(len);
266 					if (feof(f)) break;
267 					fread(temp, len, 1, f);
268 					temp[len] = 0;
269 					first = new X(temp, first);
270 
271 					first->LoadSave(f,save);
272 				}
273 			}
274 
275 			ApplyStuff();
276 		}
277 	}
278 
GetLevel(const char * name,bool create)279 	LevelSave* GetLevel(const char * name, bool create)
280 	{
281 		const char * l = strstr(name, "Levels");
282 		if (l)
283 			name = l;
284 
285 		X* x = first;
286 		if (x && strcmp(name, x->name)==0) return x;
287 		while (x && x->next)
288 		{
289 			if (strcmp(name, x->next->name)==0) return x->next;
290 			x = x->next;
291 		}
292 		if (create)
293 		{
294 			X* n = new X(name);
295 			if (x)
296 				x->next = n;
297 			else
298 				first = n;
299 			return n;
300 		}
301 		else
302 		{
303 			return 0;
304 		}
305 	}
306 };
307