1 /***************************************************************************
2                           score.c  -  description
3                              -------------------
4     begin                : Sat Jan 1 2000
5     copyright            : (C) 2000 by Perdig
6     email                : perdig@linuxbr.com.br
7 
8     $Id: score.c,v 1.6 2001/01/01 18:49:16 perdig Exp $
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   (at your option) any later version.                                   *
17  *                                                                         *
18  ***************************************************************************/
19 
20 #include <string.h>
21 #include "config.h"
22 #include "score.h"
23 #include "time.h"
24 
25 #define MAXHISCORE 20
26 
27 hiScoreStruct hiscore;
28 
29 #define addMember(member, string) do { \
30 	hiscoreTemp = member; \
31 	member = (hiMemberStruct *)malloc(sizeof(hiMemberStruct)); \
32 	member->name = string; \
33 	member->child = NULL; \
34 	member->next = hiscoreTemp; } while (0)
35 
36 bool useGAMEDIR = true;
37 time_t startime;
38 
39 extern int lives;
40 extern char livesString[10];
41 
lookup(hiMemberStruct * member,char * name)42 hiMemberStruct *lookup(hiMemberStruct *member, char *name) {
43 	while (member != NULL && strcmp(member->name, name) != 0) {
44 		member = member->next;
45 	}
46 	return member;
47 }
48 
numElements(hiMemberStruct * member)49 int numElements(hiMemberStruct *member) {
50 	int a = 0;
51 	while (member != NULL) {
52 		a++;
53 		member = member->next;
54 	}
55 	return a;
56 }
57 
loadRecords(char * filename)58 void loadRecords(char *filename) {
59 	FILE *fd;
60 	char buf[256] = "";
61 	char *temp = NULL;
62 	hiMemberStruct *hiscoreTemp;
63 	// Look first for a global hiscore
64 	temp = (char *)malloc(256);
65 	getcwd(temp, 256);
66 	chdir(GAMEDIR);
67 	fd = fopen(filename, "r");
68 	if (fd == NULL) {
69 		useGAMEDIR = false;
70 		chdir(temp);
71 		dbg("%s...", temp);
72 		fd = fopen(filename, "r");
73 		if (fd == NULL) {
74 			dbg("can't find a hiscore file. Creating a new one at %s...", temp);
75 			return;
76 		}
77 	} else {
78 		dbg("%s...", GAMEDIR);
79 	}
80 	chdir(temp);
81 	free(temp);
82 	temp = NULL;
83 
84 	while(fgets(buf, 256, fd)) {
85 		temp = (char *)malloc(strlen(buf-2));
86 		strcpy(temp, buf+2);
87 		temp[ strlen(temp)-1 ] = 0;
88 		switch (*buf) {
89 			case '*':
90 				addMember(hiscore.level, temp);
91 				break;
92 			case '+':
93 				addMember(hiscore.level->child, temp);
94 				break;
95 			case '-':
96 				addMember(hiscore.level->child->child, temp);
97 				break;
98 		}
99 	}
100 }
101 
newRecord(levelStruct * level,scoreStruct * score)102 bool newRecord(levelStruct *level, scoreStruct *score) {
103 	int record;
104 	hiMemberStruct *it;
105 	// If 0 points, don't even care
106 	if (score->value <= 0)
107 		return false;
108 
109 	// Lookup level
110 	it = lookup(hiscore.level, level->name);
111 
112 	// Lookup variation
113 	if (it == NULL) {
114 		// No level!
115 		return true;
116 	}
117 	it = lookup(it->child, level->sum);
118 	if (it == NULL) {
119 		// No var!
120 		return true;
121 	}
122 	it = it->child;
123 	if (numElements(it) < MAXHISCORE)
124 		return true;
125 	else {
126 		while (it->next != NULL)
127 			it = it->next;
128 		sscanf(it->name, "%d", &record);
129 		return score->value > record;
130 	}
131 }
132 
addRecord(levelStruct * level,scoreStruct * score,char * name)133 int addRecord(levelStruct *level, scoreStruct *score, char *name) {
134 	int record = score->value+1;
135 	hiMemberStruct *itL, *itV, *itR;
136 	hiMemberStruct *hiscoreTemp;
137 	char *temp;
138 	char livStr[16];
139 	char date[256];
140 	int pos = 1;
141 	bool first = false;
142 	time_t curtime;
143 	ldbg("Adding record of %d by %s", score->value, name);
144 	// Create string
145 	curtime = time(0);
146 	strftime(date, 256, "%m/%d/%Y", localtime(&curtime));
147 	temp = (char *)malloc(256);
148 	if (lives >= 0)
149 		sprintf(livStr, "%d lives", lives);
150 	else
151 		sprintf(livStr, "Died");
152 	sprintf(temp, "%d %s (%s - %ld min:%ld sec) %s", score->value, name, livStr, (curtime-startime)/60, (curtime-startime)%60, date);
153 	// Find level
154 	itL = lookup(hiscore.level, level->name);
155 	if (itL == NULL) {
156 		// No level by that name! Create new
157 		addMember(hiscore.level, level->name);
158 		itL = hiscore.level;
159 	}
160 	// Find sum
161 	itV = lookup(itL->child, level->sum);
162 	if (itV == NULL) {
163 		// No of that sum! Create new
164 		addMember(itL->child, level->sum);
165 		itV = itL->child;
166 	}
167 	itR = itV->child;
168 	if (itR == NULL) {
169 		// No record yet! Create new
170 		addMember(itV->child, temp);
171 		return 0;
172 	}
173 	sscanf(itR->name, "%d", &record);
174 	if (record < score->value)
175 		first = true;
176 	while (itR->next) {
177 		sscanf(itR->next->name, "%d", &record);
178 		if (record < score->value)
179 			break;
180 		pos++;
181 		itR = itR->next;
182 	}
183 	// 'itR' now holds a pointer to the right place.
184 	hiscoreTemp = (hiMemberStruct *)malloc(sizeof(hiMemberStruct));
185 	hiscoreTemp->next = first ? itR : itR->next;
186 	hiscoreTemp->child = NULL;
187 	hiscoreTemp->name = temp;
188 	if (!first)
189 		itR->next = hiscoreTemp;
190 	else
191 		itV->child = hiscoreTemp;
192 	// Erases those who are extra
193 	itR = itV->child;
194 	while (numElements(itR) > MAXHISCORE) {
195 		itR = itV->child;
196 		if (!itR->next)
197 			break;
198 		while (itR->next->next != NULL)
199 			itR = itR->next;
200 		itR->next = NULL;
201 	}
202 
203 	return first ? 0 : pos;
204 }
205 
getRecord(levelStruct * level)206 char *getRecord(levelStruct *level) {
207   hiMemberStruct *itLev;
208   hiMemberStruct *itVar;
209   unsigned int val;
210   char *name = NULL;
211   char *retval = NULL;
212   for (itLev = hiscore.level; itLev; itLev = itLev->next) {
213     if (strcmp(level->name, itLev->name)==0) {
214       for (itVar = itLev->child; itVar; itVar = itVar->next) {
215         if (strcmp(level->sum, itVar->name)==0) {
216           name = itVar->child->name;
217           break;
218         }
219       }
220     }
221   }
222   if (name) {
223     retval = (char *)malloc(SCORE_DIGITS*sizeof(char));
224     sscanf(name, "%u", &val);
225     sprintf(retval, "%.*u", SCORE_DIGITS-1, val);
226   }
227 
228   return retval;
229 
230 }
231 
listRecords(levelStruct * level)232 char **listRecords(levelStruct *level) {
233 	hiMemberStruct *itLev;
234 	hiMemberStruct *itVar;
235 	hiMemberStruct *itVal;
236 	char **values = NULL;
237 	int a;
238 
239 	ldbg("Starting to display high scores now!");
240 	for (itLev = hiscore.level; itLev; itLev = itLev->next) {
241 		if (strcmp(level->name, itLev->name)==0) {
242 			for (itVar = itLev->child; itVar; itVar = itVar->next) {
243 				if (strcmp(level->sum, itVar->name)==0) {
244 					values = (char **)calloc(numElements(itVar->child)+1, sizeof(char *));
245 					values[0] = (char *)malloc(sizeof(char));
246 					*values[0] = (char )numElements(itVar->child);
247 					for (itVal = itVar->child, a = 1; itVal; itVal = itVal->next, a++) {
248 						values[a] = itVal->name;
249 					}
250 				}
251 			}
252 		}
253 	}
254 	return values;
255 }
256 
saveRecords(char * filename)257 void saveRecords(char *filename) {
258 	FILE *fd;
259 	char *temp = NULL;
260 	hiMemberStruct *itL, *itV, *itR;
261 	if (useGAMEDIR) {
262 		temp = (char *)malloc(256);
263 		getcwd(temp, 256);
264 		chdir(GAMEDIR);
265 	}
266 	fd = fopen(filename, "w");
267 	if (!fd) {
268 		perror("Can't create new file");
269 		return;
270 	}
271 	if (useGAMEDIR) {
272 		chdir(temp);
273 		free(temp);
274 		temp = NULL;
275 	}
276 	// Stores the values in inverse order
277 	// Also erases everything
278 	for (itL = hiscore.level; itL; itL = itL->next) {
279 		// Writes the level
280 		fprintf(fd, "* %s\n", itL->name);
281 		for (itV = itL->child; itV; itV = itV->next) {
282 			fprintf(fd, "+ %s\n", itV->name);
283 			itR = itV->child;
284 			// Ok, now saves it
285 			while (itR != NULL) {
286 				itR = itV->child;
287 				if (itR->next == NULL) {
288 					fprintf(fd, "- %s\n", itR->name);
289 					break;
290 				}
291 				// Puts itR at the end
292 				while (itR->next->next != NULL)
293 					itR = itR->next;
294 				// itR->next is the last one! Write it down
295 				fprintf(fd, "- %s\n", itR->next->name);
296 				// Now erases it
297 				free(itR->next);
298 				itR->next = NULL;
299 				// Go to next one
300 			}
301 		}
302 	}
303 	fclose(fd);
304 }
305 
add_score(scoreStruct * score,levelStruct * level,int value)306 void add_score(scoreStruct *score, levelStruct *level, int value) {
307 	while (value > 0) {
308 		score->value++;
309 		value--;
310 		if (score->value >= score->current_extra && score->current_extra > 0) {
311 			lives++;
312 			sprintf(livesString, "Lives: %d", lives);
313 			score->num_extra++;
314 			score->current_extra += score->num_extra*level->extra;
315 			score->timer+=128;
316 		}
317 	}
318 	sprintf(score->string, "%.*u", SCORE_DIGITS - 1, score->value);
319 }
320