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