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