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