8
|
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 }
|