ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/hiscore.C
Revision: 1.31
Committed: Sun Jan 31 03:46:20 2010 UTC (14 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.30: +0 -0 lines
State: FILE REMOVED
Log Message:
*** empty log message ***

File Contents

# Content
1 /*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 *
4 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 *
8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the Affero GNU General Public License
19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
21 *
22 * The authors can be reached via e-mail to <support@deliantra.net>
23 */
24
25 #include <global.h>
26 #include <sproto.h>
27
28 /*
29 * The score structure is used when treating new high-scores
30 */
31 typedef struct scr
32 {
33 char name[64]; // name */
34 char title[64]; // Title */
35 char killer[64]; // name (+ title) or "quit" */
36 sint64 exp; // Experience */
37 char maplevel[128]; // Killed on what level */
38 int maxhp, maxsp, maxgrace; // Max hp, sp, grace when killed */
39 int position; // Position in the highscore list */
40 } score;
41
42 /*
43 * spool works mostly like strtok(char *, ":"), but it can also
44 * log a specified error message if something goes wrong.
45 */
46 static char *
47 spool (char *bp, const char *error)
48 {
49 static char *prev_pos = NULL;
50 char *next_pos;
51
52 if (bp == NULL)
53 {
54 if (prev_pos == NULL)
55 {
56 LOG (llevError, "Called spool (%s) with NULL without previous call.\n", error);
57 return NULL;
58 }
59 bp = prev_pos;
60 }
61 if (*bp == '\0')
62 {
63 LOG (llevError, "spool: End of line at %s\n", error);
64 return NULL;
65 }
66 if ((next_pos = strchr (bp, ':')) != NULL)
67 {
68 *next_pos = '\0';
69 prev_pos = next_pos + 1;
70 }
71 else
72 prev_pos = NULL;
73 return bp;
74 }
75
76 /*
77 * Does what it says, copies the contents of the first score structure
78 * to the second one.
79 */
80 static void
81 copy_score (score *sc1, score *sc2)
82 {
83 assign (sc2->name , sc1->name);
84 assign (sc2->title , sc1->title);
85 assign (sc2->killer , sc1->killer);
86 assign (sc2->maplevel, sc1->maplevel);
87 sc2->exp = sc1->exp;
88 sc2->maxhp = sc1->maxhp;
89 sc2->maxsp = sc1->maxsp;
90 sc2->maxgrace = sc1->maxgrace;
91 }
92
93 /*
94 * Writes the given score structure to a static buffer, and returns
95 * a pointer to it.
96 */
97 static char *
98 put_score (score *sc)
99 {
100 static char buf[MAX_BUF];
101
102 sprintf (buf, "%s:%s:%" PRId64 ":%s:%s:%d:%d:%d",
103 sc->name, sc->title, (sint64)sc->exp, sc->killer,
104 sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace);
105 return buf;
106 }
107
108 /*
109 * The oposite of put_score, get_score reads from the given buffer into
110 * a static score structure, and returns a pointer to it.
111 */
112
113 static score *
114 get_score (char *bp)
115 {
116 static score sc;
117 char *cp;
118
119 if ((cp = strchr (bp, '\n')) != NULL)
120 *cp = '\0';
121
122 if ((cp = spool (bp, "name")) == NULL)
123 return 0;
124
125 assign (sc.name, cp);
126
127 if ((cp = spool (0, "title")) == NULL)
128 return 0;
129
130 assign (sc.title, cp);
131
132 if ((cp = spool (0, "score")) == NULL)
133 return 0;
134
135 sscanf (cp, "%" SCNd64, &sc.exp);
136
137 if ((cp = spool (0, "killer")) == NULL)
138 return 0;
139
140 assign (sc.killer, cp);
141
142 if ((cp = spool (0, "map")) == NULL)
143 return 0;
144
145 assign (sc.maplevel, cp);
146
147 if ((cp = spool (0, "maxhp")) == NULL)
148 return 0;
149
150 sscanf (cp, "%d", &sc.maxhp);
151
152 if ((cp = spool (0, "maxsp")) == NULL)
153 return 0;
154
155 sscanf (cp, "%d", &sc.maxsp);
156
157 if ((cp = spool (0, "maxgrace")) == NULL)
158 return 0;
159
160 sscanf (cp, "%d", &sc.maxgrace);
161 return &sc;
162 }
163
164 static char *
165 draw_one_high_score (score *sc)
166 {
167 static char retbuf[MAX_BUF];
168
169 if (!strncmp (sc->killer, "quit", MAX_NAME))
170 sprintf (retbuf, "%3d %10lld %s the %s quit the game on map %s [%d][%d][%d].",
171 sc->position, (long long) sc->exp, sc->name, sc->title, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace);
172 else if (!strncmp (sc->killer, "leaving", MAX_NAME))
173 sprintf (retbuf, "%3d %10lld %s the %s left the game on map %s [%d][%d][%d].",
174 sc->position, (long long) sc->exp, sc->name, sc->title, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace);
175 else
176 sprintf (retbuf, "%3d %10lld %s the %s was killed by %s on map %s [%d][%d][%d].",
177 sc->position, (long long) sc->exp, sc->name, sc->title, sc->killer, sc->maplevel, sc->maxhp, sc->maxsp, sc->maxgrace);
178
179 return retbuf;
180 }
181
182 /*
183 * add_score() adds the given score-structure to the high-score list, but
184 * only if it was good enough to deserve a place.
185 */
186
187 static score *
188 add_score (score *new_score)
189 {
190 FILE *fp;
191 static score old_score;
192 score *tmp_score, pscore[HIGHSCORE_LENGTH];
193 char buf[MAX_BUF], filename[MAX_BUF], *bp;
194 int nrofscores = 0, flag = 0, i, comp;
195
196 new_score->position = HIGHSCORE_LENGTH + 1;
197 old_score.position = -1;
198 sprintf (filename, "%s/%s", settings.localdir, HIGHSCORE);
199 if ((fp = open_and_uncompress (filename, 1, &comp)) != NULL)
200 {
201 while (fgets (buf, MAX_BUF, fp) != NULL && nrofscores < HIGHSCORE_LENGTH)
202 {
203 if ((tmp_score = get_score (buf)) == NULL)
204 break;
205 if (!flag && new_score->exp >= tmp_score->exp)
206 {
207 copy_score (new_score, &pscore[nrofscores]);
208 new_score->position = nrofscores;
209 flag = 1;
210 if (++nrofscores >= HIGHSCORE_LENGTH)
211 break;
212 }
213 if (!strcmp (new_score->name, tmp_score->name))
214 { /* Another entry */
215 copy_score (tmp_score, &old_score);
216 old_score.position = nrofscores;
217 if (flag)
218 continue;
219 }
220 copy_score (tmp_score, &pscore[nrofscores++]);
221 }
222 close_and_delete (fp, comp);
223 }
224 if (old_score.position != -1 && old_score.exp >= new_score->exp)
225 return &old_score; /* Did not beat old score */
226 if (!flag && nrofscores < HIGHSCORE_LENGTH)
227 copy_score (new_score, &pscore[nrofscores++]);
228 if ((fp = fopen (filename, "w")) == NULL)
229 {
230 LOG (llevError, "Cannot write to highscore file %s: %s\n", filename, strerror (errno));
231 return NULL;
232 }
233 for (i = 0; i < nrofscores; i++)
234 {
235 bp = put_score (&pscore[i]);
236 fprintf (fp, "%s\n", bp);
237 }
238 fclose (fp);
239 if (flag)
240 {
241
242 /* Eneq(@csd.uu.se): Patch to fix error in adding a new score to the
243 hiscore-list */
244 if (old_score.position == -1)
245 return new_score;
246 return &old_score;
247 }
248 new_score->position = -1;
249 if (old_score.position != -1)
250 return &old_score;
251 if (nrofscores)
252 {
253 copy_score (&pscore[nrofscores - 1], &old_score);
254 return &old_score;
255 }
256 LOG (llevError, "Highscore error.\n");
257 return NULL;
258 }
259
260 void
261 check_score (object *op)
262 {
263 score new_score;
264 score *old_score;
265
266 if (op->stats.exp == 0)
267 return;
268
269 assign (new_score.name, op->name);
270 assign (new_score.title, op->title.length () ? &op->title : op->contr->title);
271 assign (new_score.killer, op->contr->killer_name ());
272 assign (new_score.maplevel, op->map ? op->map->name ? &op->map->name : &op->map->path : "");
273
274 new_score.exp = op->stats.exp;
275 new_score.maxhp = op->stats.maxhp;
276 new_score.maxsp = op->stats.maxsp;
277 new_score.maxgrace = op->stats.maxgrace;
278
279 if ((old_score = add_score (&new_score)) == NULL)
280 {
281 new_draw_info (NDI_UNIQUE, 0, op, "Error in the highscore list.");
282 return;
283 }
284
285 if (new_score.position == -1)
286 {
287 new_score.position = HIGHSCORE_LENGTH + 1; /* Not strictly correct... */
288 if (!strcmp (old_score->name, new_score.name))
289 new_draw_info (NDI_UNIQUE, 0, op, "You didn't beat your last highscore:");
290 else
291 new_draw_info (NDI_UNIQUE, 0, op, "You didn't enter the highscore list:");
292 new_draw_info (NDI_UNIQUE, 0, op, draw_one_high_score (old_score));
293 new_draw_info (NDI_UNIQUE, 0, op, draw_one_high_score (&new_score));
294 return;
295 }
296
297 if (old_score->exp >= new_score.exp)
298 new_draw_info (NDI_UNIQUE, 0, op, "You didn't beat your last score:");
299 else
300 new_draw_info (NDI_UNIQUE, 0, op, "You beat your last score:");
301
302 new_draw_info (NDI_UNIQUE, 0, op, draw_one_high_score (old_score));
303 new_draw_info (NDI_UNIQUE, 0, op, draw_one_high_score (&new_score));
304 }
305