xref: /dragonfly/games/rogue/score.c (revision 3536f98c)
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. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * @(#)score.c	8.1 (Berkeley) 5/31/93
33  * $FreeBSD: src/games/rogue/score.c,v 1.4 1999/11/30 03:49:27 billf Exp $
34  */
35 
36 /*
37  * score.c
38  *
39  * This source herein may be modified and/or distributed by anybody who
40  * so desires, with the following restrictions:
41  *    1.)  No portion of this notice shall be removed.
42  *    2.)  Credit shall not be taken for the creation of this source.
43  *    3.)  This code is not to be traded, sold, or used for personal
44  *         gain or profit.
45  *
46  */
47 
48 #include <stdio.h>
49 #include "rogue.h"
50 #include "pathnames.h"
51 
52 static void center(short, const char *);
53 static int get_value(const object *);
54 static void id_all(void);
55 static void insert_score(char [][82], char [][30], const char *, short, short,
56 			const object *, short);
57 static int name_cmp(char *, const char *);
58 static void nickize(char *, const char *, const char *);
59 static void sell_pack(void);
60 static void sf_error(void) __dead2;
61 
62 void
killed_by(const object * monster,short other)63 killed_by(const object *monster, short other)
64 {
65 	char buf[128];
66 
67 	md_ignore_signals();
68 
69 	if (other != QUIT) {
70 		rogue.gold = ((rogue.gold * 9) / 10);
71 	}
72 
73 	if (other) {
74 		switch(other) {
75 		case HYPOTHERMIA:
76 			strcpy(buf, "died of hypothermia");
77 			break;
78 		case STARVATION:
79 			strcpy(buf, "died of starvation");
80 			break;
81 		case POISON_DART:
82 			strcpy(buf, "killed by a dart");
83 			break;
84 		case QUIT:
85 			strcpy(buf, "quit");
86 			break;
87 		case KFIRE:
88 			strcpy(buf, "killed by fire");
89 			break;
90 		}
91 	} else {
92 		strcpy(buf, "Killed by ");
93 		if (is_vowel(m_names[monster->m_char - 'A'][0])) {
94 			strcat(buf, "an ");
95 		} else {
96 			strcat(buf, "a ");
97 		}
98 		strcat(buf, m_names[monster->m_char - 'A']);
99 	}
100 	strcat(buf, " with ");
101 	sprintf(buf+strlen(buf), "%ld gold", rogue.gold);
102 	if ((!other) && (!no_skull)) {
103 		clear();
104 		mvaddstr(4, 32, "__---------__");
105 		mvaddstr(5, 30, "_~             ~_");
106 		mvaddstr(6, 29, "/                 \\");
107 		mvaddstr(7, 28, "~                   ~");
108 		mvaddstr(8, 27, "/                     \\");
109 		mvaddstr(9, 27, "|    XXXX     XXXX    |");
110 		mvaddstr(10, 27, "|    XXXX     XXXX    |");
111 		mvaddstr(11, 27, "|    XXX       XXX    |");
112 		mvaddstr(12, 28, "\\         @         /");
113 		mvaddstr(13, 29, "--\\     @@@     /--");
114 		mvaddstr(14, 30, "| |    @@@    | |");
115 		mvaddstr(15, 30, "| |           | |");
116 		mvaddstr(16, 30, "| vvVvvvvvvvVvv |");
117 		mvaddstr(17, 30, "|  ^^^^^^^^^^^  |");
118 		mvaddstr(18, 31, "\\_           _/");
119 		mvaddstr(19, 33, "~---------~");
120 		center(21, nick_name);
121 		center(22, buf);
122 	} else {
123 		message(buf, 0);
124 	}
125 	message("", 0);
126 	put_scores(monster, other);
127 }
128 
129 void
win(void)130 win(void)
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(NULL, WIN);
151 }
152 
153 void
quit(boolean from_intrpt)154 quit(boolean from_intrpt)
155 {
156 	char buf[128];
157 	short i, orow, ocol;
158 	boolean mc;
159 
160 	orow = ocol = 0;
161 	mc = FALSE;
162 	md_ignore_signals();
163 
164 	if (from_intrpt) {
165 		orow = rogue.row;
166 		ocol = rogue.col;
167 
168 		mc = msg_cleared;
169 
170 		for (i = 0; i < DCOLS; i++) {
171 			buf[i] = mvinch(0, i);
172 		}
173 	}
174 	check_message();
175 	message("really quit?", 1);
176 	if (rgetchar() != 'y') {
177 		md_heed_signals();
178 		check_message();
179 		if (from_intrpt) {
180 			for (i = 0; i < DCOLS; i++) {
181 				mvaddch(0, i, buf[i]);
182 			}
183 			msg_cleared = mc;
184 			move(orow, ocol);
185 			refresh();
186 		}
187 		return;
188 	}
189 	if (from_intrpt) {
190 		clean_up(byebye_string);
191 	}
192 	check_message();
193 	killed_by(NULL, QUIT);
194 }
195 
196 void
put_scores(const object * monster,short other)197 put_scores(const object *monster, short other)
198 {
199 	short i, n, rank = 10, x, ne = 0, found_player = -1;
200 	char scores[10][82];
201 	char n_names[10][30];
202 	char buf[128];
203 	FILE *fp;
204 	long s;
205 	boolean pause = score_only;
206 
207 	md_lock(1);
208 
209 	if ((fp = fopen(_PATH_SCOREFILE, "r+")) == NULL &&
210 	    (fp = fopen(_PATH_SCOREFILE, "w+")) == NULL) {
211 		message("cannot read/write/create score file", 0);
212 		sf_error();
213 	}
214 	rewind(fp);
215 	xxx(1);
216 
217 	for (i = 0; i < 10; i++) {
218 		if (((n = fread(scores[i], sizeof(char), 80, fp)) < 80) && (n != 0)) {
219 			sf_error();
220 		} else if (n != 0) {
221 			xxxx(scores[i], 80);
222 			if ((n = fread(n_names[i], sizeof(char), 30, fp)) < 30) {
223 				sf_error();
224 			}
225 			xxxx(n_names[i], 30);
226 		} else {
227 			break;
228 		}
229 		ne++;
230 		if ((!score_only) && (found_player == -1)) {
231 			if (!name_cmp(scores[i]+15, login_name)) {
232 				x = 5;
233 				while (scores[i][x] == ' ') {
234 					x++;
235 				}
236 				s = lget_number(scores[i] + x);
237 				if (rogue.gold < s) {
238 					score_only = 1;
239 				} else {
240 					found_player = i;
241 				}
242 			}
243 		}
244 	}
245 
246 	/* Remove a superseded entry, if any. */
247 	if (found_player != -1) {
248 		ne--;
249 		for (i = found_player; i < ne; i++) {
250 			strcpy(scores[i], scores[i+1]);
251 			strcpy(n_names[i], n_names[i+1]);
252 		}
253 	}
254 
255 	/* If we're going to insert ourselves, do it now */
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 	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 static void
insert_score(char scores[][82],char n_names[][30],const char * n_name,short rank,short n,const object * monster,short other)326 insert_score(char scores[][82], char n_names[][30], const char *n_name,
327 	     short rank, short n, const object *monster, short other)
328 {
329 	short i;
330 	char buf[128];
331 
332 	if (n > 0) {
333 		for (i = n; i > rank; i--) {
334 			if ((i < 10) && (i > 0)) {
335 				strcpy(scores[i], scores[i-1]);
336 				strcpy(n_names[i], n_names[i-1]);
337 			}
338 		}
339 	}
340 	sprintf(buf, "%2d    %6ld   %s: ", rank+1, rogue.gold, login_name);
341 
342 	if (other) {
343 		switch(other) {
344 		case HYPOTHERMIA:
345 			strcat(buf, "died of hypothermia");
346 			break;
347 		case STARVATION:
348 			strcat(buf, "died of starvation");
349 			break;
350 		case POISON_DART:
351 			strcat(buf, "killed by a dart");
352 			break;
353 		case QUIT:
354 			strcat(buf, "quit");
355 			break;
356 		case WIN:
357 			strcat(buf, "a total winner");
358 			break;
359 		case KFIRE:
360 			strcpy(buf, "killed by fire");
361 			break;
362 		}
363 	} else {
364 		strcat(buf, "killed by ");
365 		if (is_vowel(m_names[monster->m_char - 'A'][0])) {
366 			strcat(buf, "an ");
367 		} else {
368 			strcat(buf, "a ");
369 		}
370 		strcat(buf, m_names[monster->m_char - 'A']);
371 	}
372 	sprintf(buf+strlen(buf), " on level %d ",  max_level);
373 	if ((other != WIN) && has_amulet()) {
374 		strcat(buf, "with amulet");
375 	}
376 	for (i = strlen(buf); i < 79; i++) {
377 		buf[i] = ' ';
378 	}
379 	buf[79] = 0;
380 	strcpy(scores[rank], buf);
381 	strcpy(n_names[rank], n_name);
382 }
383 
384 boolean
is_vowel(short ch)385 is_vowel(short ch)
386 {
387 	return( (ch == 'a') ||
388 		(ch == 'e') ||
389 		(ch == 'i') ||
390 		(ch == 'o') ||
391 		(ch == 'u') );
392 }
393 
394 static void
sell_pack(void)395 sell_pack(void)
396 {
397 	object *obj;
398 	short row = 2, val;
399 	char buf[DCOLS];
400 
401 	obj = rogue.pack.next_object;
402 
403 	clear();
404 	mvaddstr(1, 0, "Value      Item");
405 
406 	while (obj) {
407 		if (obj->what_is != FOOD) {
408 			obj->identified = 1;
409 			val = get_value(obj);
410 			rogue.gold += val;
411 
412 			if (row < DROWS) {
413 				sprintf(buf, "%5d      ", val);
414 				get_desc(obj, buf+11);
415 				mvaddstr(row++, 0, buf);
416 			}
417 		}
418 		obj = obj->next_object;
419 	}
420 	refresh();
421 	if (rogue.gold > MAX_GOLD) {
422 		rogue.gold = MAX_GOLD;
423 	}
424 	message("", 0);
425 }
426 
427 static int
get_value(const object * obj)428 get_value(const object *obj)
429 {
430 	short wc;
431 	int val;
432 
433 	val = 0;
434 	wc = obj->which_kind;
435 
436 	switch(obj->what_is) {
437 	case WEAPON:
438 		val = id_weapons[wc].value;
439 		if ((wc == ARROW) || (wc == DAGGER) || (wc == SHURIKEN) ||
440 			(wc == DART)) {
441 			val *= obj->quantity;
442 		}
443 		val += (obj->d_enchant * 85);
444 		val += (obj->hit_enchant * 85);
445 		break;
446 	case ARMOR:
447 		val = id_armors[wc].value;
448 		val += (obj->d_enchant * 75);
449 		if (obj->is_protected) {
450 			val += 200;
451 		}
452 		break;
453 	case WAND:
454 		val = id_wands[wc].value * (obj->class + 1);
455 		break;
456 	case SCROL:
457 		val = id_scrolls[wc].value * obj->quantity;
458 		break;
459 	case POTION:
460 		val = id_potions[wc].value * obj->quantity;
461 		break;
462 	case AMULET:
463 		val = 5000;
464 		break;
465 	case RING:
466 		val = id_rings[wc].value * (obj->class + 1);
467 		break;
468 	}
469 	if (val <= 0) {
470 		val = 10;
471 	}
472 	return(val);
473 }
474 
475 static void
id_all(void)476 id_all(void)
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 static int
name_cmp(char * s1,const char * s2)498 name_cmp(char *s1, const char *s2)
499 {
500 	short i = 0;
501 	int r;
502 
503 	while(s1[i] != ':') {
504 		i++;
505 	}
506 	s1[i] = 0;
507 	r = strcmp(s1, s2);
508 	s1[i] = ':';
509 	return(r);
510 }
511 
512 void
xxxx(char * buf,short n)513 xxxx(char *buf, short n)
514 {
515 	short i;
516 	unsigned char c;
517 
518 	for (i = 0; i < n; i++) {
519 
520 		/* It does not matter if accuracy is lost during this assignment */
521 		c = (unsigned char)xxx(0);
522 
523 		buf[i] ^= c;
524 	}
525 }
526 
527 long
xxx(boolean st)528 xxx(boolean st)
529 {
530 	static long f, s;
531 	long r;
532 
533 	if (st) {
534 		f = 37;
535 		s = 7;
536 		return(0L);
537 	}
538 	r = ((f * s) + 9337) % 8887;
539 	f = s;
540 	s = r;
541 	return(r);
542 }
543 
544 static void
nickize(char * buf,const char * score,const char * n_name)545 nickize(char *buf, const char *score, const char *n_name)
546 {
547 	short i = 15, j;
548 
549 	if (!n_name[0]) {
550 		strcpy(buf, score);
551 	} else {
552 		strncpy(buf, score, 16);
553 
554 		while (score[i] != ':') {
555 			i++;
556 		}
557 
558 		strcpy(buf+15, n_name);
559 		j = strlen(buf);
560 
561 		while (score[i]) {
562 			buf[j++] = score[i++];
563 		}
564 		buf[j] = 0;
565 		buf[79] = 0;
566 	}
567 }
568 
569 static void
center(short row,const char * buf)570 center(short row, const char *buf)
571 {
572 	short margin;
573 
574 	margin = ((DCOLS - strlen(buf)) / 2);
575 	mvaddstr(row, margin, buf);
576 }
577 
578 static void
sf_error(void)579 sf_error(void)
580 {
581 	md_lock(0);
582 	message("", 1);
583 	clean_up("sorry, score file is out of order");
584 }
585