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