Mercurial > ~darius > hgwebdir.cgi > paradise_server
comparison src/tool-hs.c @ 8:0836fb919dfa
First entry of Paradise Server 2.9 patch 10 Beta
author | darius |
---|---|
date | Sat, 06 Dec 1997 04:37:05 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
7:814de70c9f67 | 8:0836fb919dfa |
---|---|
1 /*-------------------------------------------------------------------------- | |
2 NETREK II -- Paradise | |
3 | |
4 Permission to use, copy, modify, and distribute this software and its | |
5 documentation, or any derivative works thereof, for any NON-COMMERCIAL | |
6 purpose and without fee is hereby granted, provided that this copyright | |
7 notice appear in all copies. No representations are made about the | |
8 suitability of this software for any purpose. This software is provided | |
9 "as is" without express or implied warranty. | |
10 | |
11 Xtrek Copyright 1986 Chris Guthrie | |
12 Netrek (Xtrek II) Copyright 1989 Kevin P. Smith | |
13 Scott Silvey | |
14 Paradise II (Netrek II) Copyright 1993 Larry Denys | |
15 Kurt Olsen | |
16 Brandon Gillespie | |
17 --------------------------------------------------------------------------*/ | |
18 | |
19 /* | |
20 * This is probably broken in anything but the default config | |
21 */ | |
22 | |
23 #include "config.h" | |
24 | |
25 #include <stdio.h> | |
26 #include <malloc.h> | |
27 #include <sys/types.h> | |
28 #include <sys/stat.h> | |
29 #include "struct.h" | |
30 #include "data.h" | |
31 | |
32 int topn = 1; | |
33 char name[40] = ""; /* if we want stats for a particular name */ | |
34 int nplayers; | |
35 struct statentry *database; | |
36 | |
37 struct highscore | |
38 { | |
39 char name[32]; | |
40 int di, tkills, tlosses, tarmsbomb, tresbomb, tdooshes, tplanets; | |
41 int ticks; | |
42 struct highscore *next; | |
43 }; | |
44 | |
45 struct highscore *scores; | |
46 int scoresize, nscores; | |
47 | |
48 void | |
49 subbrag(name, stuff, time, title, descr, num) | |
50 char *name; | |
51 int stuff, time; | |
52 char *title; | |
53 char *descr; | |
54 int num; | |
55 { | |
56 char full[64]; | |
57 char line[80]; | |
58 int len, tlen; | |
59 int i; | |
60 double rate; | |
61 | |
62 if (title) | |
63 { | |
64 sprintf(full, "%s: %s", title, name); | |
65 | |
66 len = strlen(full); | |
67 tlen = title ? strlen(title) : 0; | |
68 | |
69 for (i = len; i - tlen < 10; i++) | |
70 full[i] = ' '; | |
71 full[i] = 0; | |
72 } | |
73 else | |
74 { | |
75 strcpy(full, name); | |
76 } | |
77 | |
78 if (topn != 1) | |
79 sprintf(line, "%15s %3d over ", full, stuff); | |
80 else | |
81 sprintf(line, "%-30s (%2d) %3d %s, over ", full, num, stuff, descr); | |
82 | |
83 if (time / 10.0 > 3600) | |
84 sprintf(line, "%s%1.2f hours ", line, time / 36000.0); | |
85 else | |
86 sprintf(line, "%s%1.2f minutes ", line, time / 600.0); | |
87 | |
88 if (topn == 1) | |
89 sprintf(line, "%s\n%40s", line, ""); | |
90 | |
91 rate = stuff / (time / 600.0); | |
92 | |
93 if (rate < 1) | |
94 { | |
95 printf(line); | |
96 printf("(%1.2f minutes per)\n", 1 / rate); | |
97 } | |
98 else if (rate > 60) | |
99 { | |
100 printf(line); | |
101 printf("(%1.2f per hour)\n", rate / 60); | |
102 } | |
103 else | |
104 { | |
105 printf(line); | |
106 printf("(%1.2f per minute)\n", rate); | |
107 } | |
108 } | |
109 | |
110 void | |
111 brag(title, descr, offset) | |
112 char *title, *descr; | |
113 { | |
114 int i; | |
115 if (name[0] != 0) | |
116 { | |
117 for (i = 0; i < nscores; i++) | |
118 { | |
119 if (0 == strcmp(scores[i].name, name)) | |
120 { | |
121 printf("#%5d: ", i + 1); | |
122 subbrag("", *(int *) (offset + (char *) &scores[i]), | |
123 scores[i].ticks, title, descr, i); | |
124 break; | |
125 } | |
126 } | |
127 } | |
128 else | |
129 { | |
130 if (topn != 1) | |
131 printf("\n%s (%s)\n", title, descr); | |
132 for (i = 0; i < topn && i < nscores; i++) | |
133 { | |
134 printf("%10s", ""); | |
135 subbrag(scores[i].name, *(int *) (offset + (char *) &scores[i]), | |
136 scores[i].ticks, topn == 1 ? title : (char *) 0, descr, i); | |
137 } | |
138 } | |
139 } | |
140 | |
141 #if __STDC__ | |
142 #define COMPUTE(STN) \ | |
143 do { \ | |
144 currscore->STN = currplayer.stats.st_ ## STN - \ | |
145 prevplayer->stats.st_ ## STN; \ | |
146 } while (0) | |
147 | |
148 | |
149 #define COMPARE(STN) \ | |
150 int cmp_raw ## STN(a,b) \ | |
151 struct highscore *a, *b; \ | |
152 { \ | |
153 int diff = a->STN - b->STN; \ | |
154 \ | |
155 if (diff<0) \ | |
156 return 1; \ | |
157 else if (diff==0) \ | |
158 return 0; \ | |
159 else \ | |
160 return -1; \ | |
161 } \ | |
162 \ | |
163 int cmp_per ## STN(a,b) \ | |
164 struct highscore *a, *b; \ | |
165 { \ | |
166 double diff = a->STN/(double)a->ticks - b->STN/(double)b->ticks; \ | |
167 \ | |
168 if (diff<0) \ | |
169 return 1; \ | |
170 else if (diff==0) \ | |
171 return 0; \ | |
172 else \ | |
173 return -1; \ | |
174 } | |
175 #else | |
176 #define COMPUTE(STN) \ | |
177 do { \ | |
178 currscore->STN = currplayer.stats.st_/**/STN - \ | |
179 prevplayer->stats.st_/**/STN; \ | |
180 } while (0) | |
181 | |
182 | |
183 #define COMPARE(STN) \ | |
184 int cmp_raw/**/STN(a,b) \ | |
185 struct highscore *a, *b; \ | |
186 { \ | |
187 int diff = a->STN - b->STN; \ | |
188 \ | |
189 if (diff<0) \ | |
190 return 1; \ | |
191 else if (diff==0) \ | |
192 return 0; \ | |
193 else \ | |
194 return -1; \ | |
195 } \ | |
196 \ | |
197 int cmp_per/**/STN(a,b) \ | |
198 struct highscore *a, *b; \ | |
199 { \ | |
200 double diff = a->STN/(double)a->ticks - b->STN/(double)b->ticks; \ | |
201 \ | |
202 if (diff<0) \ | |
203 return 1; \ | |
204 else if (diff==0) \ | |
205 return 0; \ | |
206 else \ | |
207 return -1; \ | |
208 } | |
209 #endif | |
210 | |
211 COMPARE(di) | |
212 COMPARE(tkills) | |
213 COMPARE(tlosses) | |
214 COMPARE(tarmsbomb) | |
215 COMPARE(tresbomb) | |
216 COMPARE(tdooshes) | |
217 COMPARE(tplanets) | |
218 int cmp_ticks(a, b) | |
219 struct highscore *a, *b; | |
220 { | |
221 int diff = a->ticks - b->ticks; | |
222 | |
223 if (diff < 0) | |
224 return 1; | |
225 else if (diff == 0) | |
226 return 0; | |
227 else | |
228 return -1; | |
229 } | |
230 | |
231 struct statentry zeroplayer; | |
232 | |
233 int | |
234 different(one, two) | |
235 struct highscore *one, *two; | |
236 { | |
237 return 0 != strcmp(one->name, two->name); | |
238 } | |
239 | |
240 double atof(); | |
241 | |
242 int | |
243 main(argc, argv) | |
244 int argc; | |
245 char **argv; | |
246 { | |
247 struct stat fstats; | |
248 FILE *fp; | |
249 int i; | |
250 int code = 0; | |
251 struct statentry currplayer; | |
252 char **av; | |
253 int usage = 0; | |
254 float mintime = 30.0; | |
255 | |
256 for (av = &argv[1]; *av && (*av)[0] == '-'; av++) | |
257 { | |
258 if (0 == strcmp(*av, "-n") && av[1]) | |
259 { | |
260 topn = atoi(*++av); | |
261 } | |
262 else if (0 == strcmp(*av, "-c") && av[1]) | |
263 { | |
264 code = atoi(*++av); | |
265 } | |
266 else if (0 == strcmp(*av, "-name") && av[1]) | |
267 { | |
268 strcpy(name, *++av); | |
269 } | |
270 else if (0 == strcmp(*av, "-time") && av[1]) | |
271 { | |
272 mintime = atof(*++av); | |
273 } | |
274 else | |
275 { | |
276 usage = 1; | |
277 break; | |
278 } | |
279 } | |
280 if (argc - (av - argv) != 2) | |
281 { | |
282 usage = 1; | |
283 } | |
284 | |
285 if (usage) | |
286 { | |
287 int x; | |
288 char message[][255] = { | |
289 "\nHigh Scores, created by comparing two databases.\n", | |
290 "\n\t'%s -n <num> -c <num> [-name <name>] <old db> <new db>'\n\n", | |
291 "Options:\n", | |
292 "\t-n num How many high scores to print\n", | |
293 "\t-c num Which category (0 is all, max available is 15)\n", | |
294 "\t-name string print ranking for a particular player\n", | |
295 "\nExample:\t'%s -n 5 -c 1 .players.bak .players'\n\n", | |
296 "\0" | |
297 }; | |
298 | |
299 fprintf(stderr, "--- %s ---\n", PARAVERS); | |
300 for (x = 0; *message[x] != '\0'; x++) | |
301 fprintf(stderr, message[x], argv[0]); | |
302 | |
303 exit(1); | |
304 } | |
305 | |
306 fp = fopen(av[0], "r"); | |
307 if (fp == 0) | |
308 { | |
309 fprintf(stderr, "Couldn't open file %s for read", av[0]); | |
310 perror(""); | |
311 exit(1); | |
312 } | |
313 | |
314 if (fstat(fileno(fp), &fstats) < 0) | |
315 { | |
316 fprintf(stderr, "Couldn't fstat file %s", av[0]); | |
317 perror(""); | |
318 exit(1); | |
319 } | |
320 | |
321 nplayers = fstats.st_size / sizeof(*database); | |
322 database = (struct statentry *) malloc(sizeof(*database) * nplayers); | |
323 | |
324 i = fread(database, sizeof(*database), nplayers, fp); | |
325 | |
326 if (i == 0) | |
327 { | |
328 fprintf(stderr, "failed to read any player records from file %s\n", av[0]); | |
329 exit(1); | |
330 } | |
331 if (i != nplayers) | |
332 { | |
333 fprintf(stderr, "failed to read all player records from file %s (%d of %d)\n", av[0], i, nplayers); | |
334 nplayers = i; | |
335 } | |
336 | |
337 fclose(fp); | |
338 | |
339 fp = fopen(av[1], "r"); | |
340 if (fp == 0) | |
341 { | |
342 fprintf(stderr, "Couldn't open file %s for read", av[1]); | |
343 perror(""); | |
344 exit(1); | |
345 } | |
346 | |
347 | |
348 scores = (struct highscore *) malloc(sizeof(*scores) * (scoresize = 256)); | |
349 nscores = 0; | |
350 | |
351 while (1) | |
352 { | |
353 int delta; | |
354 int dt; | |
355 struct statentry *prevplayer; | |
356 struct highscore *currscore; | |
357 | |
358 i = fread(&currplayer, sizeof(currplayer), 1, fp); | |
359 if (i < 0) | |
360 { | |
361 fprintf(stderr, "error reading player record, aborting loop\n"); | |
362 perror(""); | |
363 } | |
364 if (i <= 0) | |
365 break; | |
366 | |
367 for (i = 0; i < nplayers; i++) | |
368 { | |
369 if (0 == strcmp(database[i].name, currplayer.name)) | |
370 break; | |
371 } | |
372 if (i < nplayers) | |
373 prevplayer = &database[i]; | |
374 else | |
375 prevplayer = &zeroplayer; | |
376 | |
377 dt = currplayer.stats.st_tticks - prevplayer->stats.st_tticks; | |
378 | |
379 if (dt < mintime /* minutes */ * 60 * 10) | |
380 continue; | |
381 | |
382 if (nscores >= scoresize) | |
383 { | |
384 scores = (struct highscore *) realloc(scores, sizeof(*scores) * (scoresize *= 2)); | |
385 } | |
386 currscore = &scores[nscores++]; | |
387 strcpy(currscore->name, currplayer.name); | |
388 currscore->ticks = dt; | |
389 | |
390 COMPUTE(di); | |
391 COMPUTE(tkills); | |
392 COMPUTE(tlosses); | |
393 COMPUTE(tarmsbomb); | |
394 COMPUTE(tresbomb); | |
395 COMPUTE(tdooshes); | |
396 COMPUTE(tplanets); | |
397 } | |
398 | |
399 | |
400 #define offset(field) ( (int)&(((struct highscore*)0)->field) ) | |
401 | |
402 if (!code || code == 1) | |
403 { | |
404 qsort(scores, nscores, sizeof(*scores), cmp_rawdi); | |
405 brag("Lord of Destruction", "most destruction inflicted", offset(di)); | |
406 } | |
407 | |
408 if (!code && topn > 5) | |
409 printf("\t@@b\n"); | |
410 | |
411 if (!code || code == 2) | |
412 { | |
413 qsort(scores, nscores, sizeof(*scores), cmp_perdi); | |
414 brag("BlitzMeister", "fastest destruction inflicted", offset(di)); | |
415 } | |
416 | |
417 if (!code && topn > 5) | |
418 printf("\t@@b\n"); | |
419 | |
420 if (!code || code == 3) | |
421 { | |
422 qsort(scores, nscores, sizeof(*scores), cmp_rawtkills); | |
423 brag("Hitler", "most opponents defeated", offset(tkills)); | |
424 } | |
425 | |
426 if (!code && topn > 5) | |
427 printf("\t@@b\n"); | |
428 | |
429 if (!code || code == 4) | |
430 { | |
431 qsort(scores, nscores, sizeof(*scores), cmp_pertkills); | |
432 brag("Terminator", "fastest opponents defeated", offset(tkills)); | |
433 } | |
434 | |
435 if (!code && topn > 5) | |
436 printf("\t@@b\n"); | |
437 | |
438 if (!code || code == 5) | |
439 { | |
440 qsort(scores, nscores, sizeof(*scores), cmp_rawtlosses); | |
441 brag("Kamikaze", "most times down in flames", offset(tlosses)); | |
442 } | |
443 | |
444 if (!code && topn > 5) | |
445 printf("\t@@b\n"); | |
446 | |
447 if (!code || code == 6) | |
448 { | |
449 qsort(scores, nscores, sizeof(*scores), cmp_pertlosses); | |
450 brag("Speed Kamikaze", "fastest times down in flames", offset(tlosses)); | |
451 } | |
452 | |
453 if (!code && topn > 5) | |
454 printf("\t@@b\n"); | |
455 | |
456 if (!code || code == 7) | |
457 { | |
458 qsort(scores, nscores, sizeof(*scores), cmp_rawtarmsbomb); | |
459 brag("Carpet Bomber", "most armies bombed", offset(tarmsbomb)); | |
460 } | |
461 | |
462 if (!code && topn > 5) | |
463 printf("\t@@b\n"); | |
464 | |
465 if (!code || code == 8) | |
466 { | |
467 qsort(scores, nscores, sizeof(*scores), cmp_pertarmsbomb); | |
468 brag("NukeMeister", "fastest armies bombed", offset(tarmsbomb)); | |
469 } | |
470 | |
471 if (!code && topn > 5) | |
472 printf("\t@@b\n"); | |
473 | |
474 if (!code || code == 9) | |
475 { | |
476 qsort(scores, nscores, sizeof(*scores), cmp_rawtresbomb); | |
477 brag("Terrorist", "most resources leveled", offset(tresbomb)); | |
478 } | |
479 | |
480 if (!code && topn > 5) | |
481 printf("\t@@b\n"); | |
482 | |
483 if (!code || code == 10) | |
484 { | |
485 qsort(scores, nscores, sizeof(*scores), cmp_pertresbomb); | |
486 brag("Democrat", "fastest resources leveled", offset(tresbomb)); | |
487 } | |
488 | |
489 if (!code && topn > 5) | |
490 printf("\t@@b\n"); | |
491 | |
492 if (!code || code == 11) | |
493 { | |
494 qsort(scores, nscores, sizeof(*scores), cmp_rawtdooshes); | |
495 brag("Executioner", "most armies dooshed", offset(tdooshes)); | |
496 } | |
497 | |
498 if (!code && topn > 5) | |
499 printf("\t@@b\n"); | |
500 | |
501 if (!code || code == 12) | |
502 { | |
503 qsort(scores, nscores, sizeof(*scores), cmp_pertdooshes); | |
504 brag("DooshMeister", "fastest armies dooshed", offset(tdooshes)); | |
505 } | |
506 | |
507 if (!code && topn > 5) | |
508 printf("\t@@b\n"); | |
509 | |
510 if (!code || code == 13) | |
511 { | |
512 qsort(scores, nscores, sizeof(*scores), cmp_rawtplanets); | |
513 brag("Diplomat", "most planets taken", offset(tplanets)); | |
514 } | |
515 | |
516 if (!code && topn > 5) | |
517 printf("\t@@b\n"); | |
518 | |
519 if (!code || code == 14) | |
520 { | |
521 qsort(scores, nscores, sizeof(*scores), cmp_pertplanets); | |
522 brag("speed Diplomat", "fastest planets taken", offset(tplanets)); | |
523 } | |
524 | |
525 if (!code && topn > 5) | |
526 printf("\t@@b\n"); | |
527 | |
528 if (!code || code == 15) | |
529 { | |
530 qsort(scores, nscores, sizeof(*scores), cmp_ticks); | |
531 if (name[0] != 0) | |
532 { | |
533 for (i = 0; i < nscores; i++) | |
534 { | |
535 if (0 == strcmp(scores[i].name, name)) | |
536 { | |
537 printf("#%5d:%30s with %1.2f hours\n", i + 1, scores[i].name, | |
538 scores[i].ticks / 36000.0); | |
539 break; | |
540 } | |
541 } | |
542 } | |
543 else if (topn > 1) | |
544 { | |
545 int i; | |
546 printf("Addicts:\n"); | |
547 for (i = 0; i < topn && i < nscores; i++) | |
548 { | |
549 printf("%30s with %1.2f hours\n", scores[i].name, scores[i].ticks / 36000.0); | |
550 } | |
551 } | |
552 else | |
553 { | |
554 printf("Addict: %s with %1.2f hours\n", scores[0].name, scores[0].ticks / 36000.0); | |
555 } | |
556 } | |
557 | |
558 exit(0); | |
559 } |