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