Initial import from FreeBSD RELENG_4:
[dragonfly.git] / games / rogue / score.c
1 /*
2  * Copyright (c) 1988, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Timothy C. Stoehr.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)score.c     8.1 (Berkeley) 5/31/93";
40 #endif
41 static const char rcsid[] =
42  "$FreeBSD: src/games/rogue/score.c,v 1.4 1999/11/30 03:49:27 billf Exp $";
43 #endif /* not lint */
44
45 /*
46  * score.c
47  *
48  * This source herein may be modified and/or distributed by anybody who
49  * so desires, with the following restrictions:
50  *    1.)  No portion of this notice shall be removed.
51  *    2.)  Credit shall not be taken for the creation of this source.
52  *    3.)  This code is not to be traded, sold, or used for personal
53  *         gain or profit.
54  *
55  */
56
57 #include <stdio.h>
58 #include "rogue.h"
59 #include "pathnames.h"
60
61 extern char login_name[];
62 extern char *m_names[];
63 extern short max_level;
64 extern boolean score_only, no_skull, msg_cleared;
65 extern char *byebye_string, *nick_name;
66
67 killed_by(monster, other)
68 const object *monster;
69 short other;
70 {
71         char buf[128];
72
73         md_ignore_signals();
74
75         if (other != QUIT) {
76                 rogue.gold = ((rogue.gold * 9) / 10);
77         }
78
79         if (other) {
80                 switch(other) {
81                 case HYPOTHERMIA:
82                         (void) strcpy(buf, "died of hypothermia");
83                         break;
84                 case STARVATION:
85                         (void) strcpy(buf, "died of starvation");
86                         break;
87                 case POISON_DART:
88                         (void) strcpy(buf, "killed by a dart");
89                         break;
90                 case QUIT:
91                         (void) strcpy(buf, "quit");
92                         break;
93                 case KFIRE:
94                         (void) strcpy(buf, "killed by fire");
95                         break;
96                 }
97         } else {
98                 (void) strcpy(buf, "Killed by ");
99                 if (is_vowel(m_names[monster->m_char - 'A'][0])) {
100                         (void) strcat(buf, "an ");
101                 } else {
102                         (void) strcat(buf, "a ");
103                 }
104                 (void) strcat(buf, m_names[monster->m_char - 'A']);
105         }
106         (void) strcat(buf, " with ");
107         sprintf(buf+strlen(buf), "%ld gold", rogue.gold);
108         if ((!other) && (!no_skull)) {
109                 clear();
110                 mvaddstr(4, 32, "__---------__");
111                 mvaddstr(5, 30, "_~             ~_");
112                 mvaddstr(6, 29, "/                 \\");
113                 mvaddstr(7, 28, "~                   ~");
114                 mvaddstr(8, 27, "/                     \\");
115                 mvaddstr(9, 27, "|    XXXX     XXXX    |");
116                 mvaddstr(10, 27, "|    XXXX     XXXX    |");
117                 mvaddstr(11, 27, "|    XXX       XXX    |");
118                 mvaddstr(12, 28, "\\         @         /");
119                 mvaddstr(13, 29, "--\\     @@@     /--");
120                 mvaddstr(14, 30, "| |    @@@    | |");
121                 mvaddstr(15, 30, "| |           | |");
122                 mvaddstr(16, 30, "| vvVvvvvvvvVvv |");
123                 mvaddstr(17, 30, "|  ^^^^^^^^^^^  |");
124                 mvaddstr(18, 31, "\\_           _/");
125                 mvaddstr(19, 33, "~---------~");
126                 center(21, nick_name);
127                 center(22, buf);
128         } else {
129                 message(buf, 0);
130         }
131         message("", 0);
132         put_scores(monster, other);
133 }
134
135 win()
136 {
137         unwield(rogue.weapon);          /* disarm and relax */
138         unwear(rogue.armor);
139         un_put_on(rogue.left_ring);
140         un_put_on(rogue.right_ring);
141
142         clear();
143         mvaddstr(10, 11, "@   @  @@@   @   @      @  @  @   @@@   @   @   @");
144         mvaddstr(11, 11, " @ @  @   @  @   @      @  @  @  @   @  @@  @   @");
145         mvaddstr(12, 11, "  @   @   @  @   @      @  @  @  @   @  @ @ @   @");
146         mvaddstr(13, 11, "  @   @   @  @   @      @  @  @  @   @  @  @@");
147         mvaddstr(14, 11, "  @    @@@    @@@        @@ @@    @@@   @   @   @");
148         mvaddstr(17, 11, "Congratulations,  you have  been admitted  to  the");
149         mvaddstr(18, 11, "Fighters' Guild.   You return home,  sell all your");
150         mvaddstr(19, 11, "treasures at great profit and retire into comfort.");
151         message("", 0);
152         message("", 0);
153         id_all();
154         sell_pack();
155         put_scores((object *) 0, WIN);
156 }
157
158 quit(from_intrpt)
159 boolean from_intrpt;
160 {
161         char buf[128];
162         short i, orow, ocol;
163         boolean mc;
164
165         md_ignore_signals();
166
167         if (from_intrpt) {
168                 orow = rogue.row;
169                 ocol = rogue.col;
170
171                 mc = msg_cleared;
172
173                 for (i = 0; i < DCOLS; i++) {
174                         buf[i] = mvinch(0, i);
175                 }
176         }
177         check_message();
178         message("really quit?", 1);
179         if (rgetchar() != 'y') {
180                 md_heed_signals();
181                 check_message();
182                 if (from_intrpt) {
183                         for (i = 0; i < DCOLS; i++) {
184                                 mvaddch(0, i, buf[i]);
185                         }
186                         msg_cleared = mc;
187                         move(orow, ocol);
188                         refresh();
189                 }
190                 return;
191         }
192         if (from_intrpt) {
193                 clean_up(byebye_string);
194         }
195         check_message();
196         killed_by((object *) 0, QUIT);
197 }
198
199 put_scores(monster, other)
200 const object *monster;
201 short other;
202 {
203         short i, n, rank = 10, x, ne = 0, found_player = -1;
204         char scores[10][82];
205         char n_names[10][30];
206         char buf[128];
207         FILE *fp;
208         long s;
209         boolean pause = score_only;
210
211         md_lock(1);
212
213         if ((fp = fopen(_PATH_SCOREFILE, "r+")) == NULL &&
214             (fp = fopen(_PATH_SCOREFILE, "w+")) == NULL) {
215                 message("cannot read/write/create score file", 0);
216                 sf_error();
217         }
218         rewind(fp);
219         (void) xxx(1);
220
221         for (i = 0; i < 10; i++) {
222                 if (((n = fread(scores[i], sizeof(char), 80, fp)) < 80) && (n != 0)) {
223                         sf_error();
224                 } else if (n != 0) {
225                         xxxx(scores[i], 80);
226                         if ((n = fread(n_names[i], sizeof(char), 30, fp)) < 30) {
227                                 sf_error();
228                         }
229                         xxxx(n_names[i], 30);
230                 } else {
231                         break;
232                 }
233                 ne++;
234                 if ((!score_only) && (found_player == -1)) {
235                         if (!name_cmp(scores[i]+15, login_name)) {
236                                 x = 5;
237                                 while (scores[i][x] == ' ') {
238                                         x++;
239                                 }
240                                 s = lget_number(scores[i] + x);
241                                 if (rogue.gold < s) {
242                                         score_only = 1;
243                                 } else {
244                                         found_player = i;
245                                 }
246                         }
247                 }
248         }
249         if (found_player != -1) {
250                 ne--;
251                 for (i = found_player; i < ne; i++) {
252                         (void) strcpy(scores[i], scores[i+1]);
253                         (void) strcpy(n_names[i], n_names[i+1]);
254                 }
255         }
256         if (!score_only) {
257                 for (i = 0; i < ne; i++) {
258                         x = 5;
259                         while (scores[i][x] == ' ') {
260                                 x++;
261                         }
262                         s = lget_number(scores[i] + x);
263
264                         if (rogue.gold >= s) {
265                                 rank = i;
266                                 break;
267                         }
268                 }
269                 if (ne == 0) {
270                         rank = 0;
271                 } else if ((ne < 10) && (rank == 10)) {
272                         rank = ne;
273                 }
274                 if (rank < 10) {
275                         insert_score(scores, n_names, nick_name, rank, ne, monster,
276                                 other);
277                         if (ne < 10) {
278                                 ne++;
279                         }
280                 }
281                 rewind(fp);
282         }
283
284         clear();
285         mvaddstr(3, 30, "Top  Ten  Rogueists");
286         mvaddstr(8, 0, "Rank   Score   Name");
287
288         md_ignore_signals();
289
290         (void) xxx(1);
291
292         for (i = 0; i < ne; i++) {
293                 if (i == rank) {
294                         standout();
295                 }
296                 if (i == 9) {
297                         scores[i][0] = '1';
298                         scores[i][1] = '0';
299                 } else {
300                         scores[i][0] = ' ';
301                         scores[i][1] = i + '1';
302                 }
303                 nickize(buf, scores[i], n_names[i]);
304                 mvaddstr(i+10, 0, buf);
305                 if (rank < 10) {
306                         xxxx(scores[i], 80);
307                         fwrite(scores[i], sizeof(char), 80, fp);
308                         xxxx(n_names[i], 30);
309                         fwrite(n_names[i], sizeof(char), 30, fp);
310                 }
311                 if (i == rank) {
312                         standend();
313                 }
314         }
315         md_lock(0);
316         refresh();
317         fclose(fp);
318         message("", 0);
319         if (pause) {
320                 message("", 0);
321         }
322         clean_up("");
323 }
324
325 insert_score(scores, n_names, n_name, rank, n, monster, other)
326 char scores[][82];
327 char n_names[][30];
328 const char *n_name;
329 short rank, n;
330 const object *monster;
331 {
332         short i;
333         char buf[128];
334
335         if (n > 0) {
336                 for (i = n; i > rank; i--) {
337                         if ((i < 10) && (i > 0)) {
338                                 (void) strcpy(scores[i], scores[i-1]);
339                                 (void) strcpy(n_names[i], n_names[i-1]);
340                         }
341                 }
342         }
343         sprintf(buf, "%2d    %6ld   %s: ", rank+1, rogue.gold, login_name);
344
345         if (other) {
346                 switch(other) {
347                 case HYPOTHERMIA:
348                         (void) strcat(buf, "died of hypothermia");
349                         break;
350                 case STARVATION:
351                         (void) strcat(buf, "died of starvation");
352                         break;
353                 case POISON_DART:
354                         (void) strcat(buf, "killed by a dart");
355                         break;
356                 case QUIT:
357                         (void) strcat(buf, "quit");
358                         break;
359                 case WIN:
360                         (void) strcat(buf, "a total winner");
361                         break;
362                 case KFIRE:
363                         (void) strcpy(buf, "killed by fire");
364                         break;
365                 }
366         } else {
367                 (void) strcat(buf, "killed by ");
368                 if (is_vowel(m_names[monster->m_char - 'A'][0])) {
369                         (void) strcat(buf, "an ");
370                 } else {
371                         (void) strcat(buf, "a ");
372                 }
373                 (void) strcat(buf, m_names[monster->m_char - 'A']);
374         }
375         sprintf(buf+strlen(buf), " on level %d ",  max_level);
376         if ((other != WIN) && has_amulet()) {
377                 (void) strcat(buf, "with amulet");
378         }
379         for (i = strlen(buf); i < 79; i++) {
380                 buf[i] = ' ';
381         }
382         buf[79] = 0;
383         (void) strcpy(scores[rank], buf);
384         (void) strcpy(n_names[rank], n_name);
385 }
386
387 is_vowel(ch)
388 short ch;
389 {
390         return( (ch == 'a') ||
391                 (ch == 'e') ||
392                 (ch == 'i') ||
393                 (ch == 'o') ||
394                 (ch == 'u') );
395 }
396
397 sell_pack()
398 {
399         object *obj;
400         short row = 2, val;
401         char buf[DCOLS];
402
403         obj = rogue.pack.next_object;
404
405         clear();
406         mvaddstr(1, 0, "Value      Item");
407
408         while (obj) {
409                 if (obj->what_is != FOOD) {
410                         obj->identified = 1;
411                         val = get_value(obj);
412                         rogue.gold += val;
413
414                         if (row < DROWS) {
415                                 sprintf(buf, "%5d      ", val);
416                                 get_desc(obj, buf+11);
417                                 mvaddstr(row++, 0, buf);
418                         }
419                 }
420                 obj = obj->next_object;
421         }
422         refresh();
423         if (rogue.gold > MAX_GOLD) {
424                 rogue.gold = MAX_GOLD;
425         }
426         message("", 0);
427 }
428
429 get_value(obj)
430 const object *obj;
431 {
432         short wc;
433         int val;
434
435         wc = obj->which_kind;
436
437         switch(obj->what_is) {
438         case WEAPON:
439                 val = id_weapons[wc].value;
440                 if ((wc == ARROW) || (wc == DAGGER) || (wc == SHURIKEN) ||
441                         (wc == DART)) {
442                         val *= obj->quantity;
443                 }
444                 val += (obj->d_enchant * 85);
445                 val += (obj->hit_enchant * 85);
446                 break;
447         case ARMOR:
448                 val = id_armors[wc].value;
449                 val += (obj->d_enchant * 75);
450                 if (obj->is_protected) {
451                         val += 200;
452                 }
453                 break;
454         case WAND:
455                 val = id_wands[wc].value * (obj->class + 1);
456                 break;
457         case SCROL:
458                 val = id_scrolls[wc].value * obj->quantity;
459                 break;
460         case POTION:
461                 val = id_potions[wc].value * obj->quantity;
462                 break;
463         case AMULET:
464                 val = 5000;
465                 break;
466         case RING:
467                 val = id_rings[wc].value * (obj->class + 1);
468                 break;
469         }
470         if (val <= 0) {
471                 val = 10;
472         }
473         return(val);
474 }
475
476 id_all()
477 {
478         short i;
479
480         for (i = 0; i < SCROLS; i++) {
481                 id_scrolls[i].id_status = IDENTIFIED;
482         }
483         for (i = 0; i < WEAPONS; i++) {
484                 id_weapons[i].id_status = IDENTIFIED;
485         }
486         for (i = 0; i < ARMORS; i++) {
487                 id_armors[i].id_status = IDENTIFIED;
488         }
489         for (i = 0; i < WANDS; i++) {
490                 id_wands[i].id_status = IDENTIFIED;
491         }
492         for (i = 0; i < POTIONS; i++) {
493                 id_potions[i].id_status = IDENTIFIED;
494         }
495 }
496
497 name_cmp(s1, s2)
498 char *s1;
499 const char *s2;
500 {
501         short i = 0;
502         int r;
503
504         while(s1[i] != ':') {
505                 i++;
506         }
507         s1[i] = 0;
508         r = strcmp(s1, s2);
509         s1[i] = ':';
510         return(r);
511 }
512
513 xxxx(buf, n)
514 char *buf;
515 short n;
516 {
517         short i;
518         unsigned char c;
519
520         for (i = 0; i < n; i++) {
521
522                 /* It does not matter if accuracy is lost during this assignment */
523                 c = (unsigned char) xxx(0);
524
525                 buf[i] ^= c;
526         }
527 }
528
529 long
530 xxx(st)
531 boolean st;
532 {
533         static long f, s;
534         long r;
535
536         if (st) {
537                 f = 37;
538                 s = 7;
539                 return(0L);
540         }
541         r = ((f * s) + 9337) % 8887;
542         f = s;
543         s = r;
544         return(r);
545 }
546
547 nickize(buf, score, n_name)
548 char *buf;
549 const char *score, *n_name;
550 {
551         short i = 15, j;
552
553         if (!n_name[0]) {
554                 (void) strcpy(buf, score);
555         } else {
556                 (void) strncpy(buf, score, 16);
557
558                 while (score[i] != ':') {
559                         i++;
560                 }
561
562                 (void) strcpy(buf+15, n_name);
563                 j = strlen(buf);
564
565                 while (score[i]) {
566                         buf[j++] = score[i++];
567                 }
568                 buf[j] = 0;
569                 buf[79] = 0;
570         }
571 }
572
573 center(row, buf)
574 short row;
575 const char *buf;
576 {
577         short margin;
578
579         margin = ((DCOLS - strlen(buf)) / 2);
580         mvaddstr(row, margin, buf);
581 }
582
583 sf_error()
584 {
585         md_lock(0);
586         message("", 1);
587         clean_up("sorry, score file is out of order");
588 }