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