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.3 2003/08/26 23:52:50 drhodus 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 killed_by(monster, other) 63 const object *monster; 64 short other; 65 { 66 char buf[128]; 67 68 md_ignore_signals(); 69 70 if (other != QUIT) { 71 rogue.gold = ((rogue.gold * 9) / 10); 72 } 73 74 if (other) { 75 switch(other) { 76 case HYPOTHERMIA: 77 (void) strcpy(buf, "died of hypothermia"); 78 break; 79 case STARVATION: 80 (void) strcpy(buf, "died of starvation"); 81 break; 82 case POISON_DART: 83 (void) strcpy(buf, "killed by a dart"); 84 break; 85 case QUIT: 86 (void) strcpy(buf, "quit"); 87 break; 88 case KFIRE: 89 (void) strcpy(buf, "killed by fire"); 90 break; 91 } 92 } else { 93 (void) strcpy(buf, "Killed by "); 94 if (is_vowel(m_names[monster->m_char - 'A'][0])) { 95 (void) strcat(buf, "an "); 96 } else { 97 (void) strcat(buf, "a "); 98 } 99 (void) strcat(buf, m_names[monster->m_char - 'A']); 100 } 101 (void) strcat(buf, " with "); 102 sprintf(buf+strlen(buf), "%ld gold", rogue.gold); 103 if ((!other) && (!no_skull)) { 104 clear(); 105 mvaddstr(4, 32, "__---------__"); 106 mvaddstr(5, 30, "_~ ~_"); 107 mvaddstr(6, 29, "/ \\"); 108 mvaddstr(7, 28, "~ ~"); 109 mvaddstr(8, 27, "/ \\"); 110 mvaddstr(9, 27, "| XXXX XXXX |"); 111 mvaddstr(10, 27, "| XXXX XXXX |"); 112 mvaddstr(11, 27, "| XXX XXX |"); 113 mvaddstr(12, 28, "\\ @ /"); 114 mvaddstr(13, 29, "--\\ @@@ /--"); 115 mvaddstr(14, 30, "| | @@@ | |"); 116 mvaddstr(15, 30, "| | | |"); 117 mvaddstr(16, 30, "| vvVvvvvvvvVvv |"); 118 mvaddstr(17, 30, "| ^^^^^^^^^^^ |"); 119 mvaddstr(18, 31, "\\_ _/"); 120 mvaddstr(19, 33, "~---------~"); 121 center(21, nick_name); 122 center(22, buf); 123 } else { 124 message(buf, 0); 125 } 126 message("", 0); 127 put_scores(monster, other); 128 } 129 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 quit(from_intrpt) 154 boolean from_intrpt; 155 { 156 char buf[128]; 157 short i, orow, ocol; 158 boolean mc; 159 160 md_ignore_signals(); 161 162 if (from_intrpt) { 163 orow = rogue.row; 164 ocol = rogue.col; 165 166 mc = msg_cleared; 167 168 for (i = 0; i < DCOLS; i++) { 169 buf[i] = mvinch(0, i); 170 } 171 } 172 check_message(); 173 message("really quit?", 1); 174 if (rgetchar() != 'y') { 175 md_heed_signals(); 176 check_message(); 177 if (from_intrpt) { 178 for (i = 0; i < DCOLS; i++) { 179 mvaddch(0, i, buf[i]); 180 } 181 msg_cleared = mc; 182 move(orow, ocol); 183 refresh(); 184 } 185 return; 186 } 187 if (from_intrpt) { 188 clean_up(byebye_string); 189 } 190 check_message(); 191 killed_by((object *) 0, QUIT); 192 } 193 194 put_scores(monster, other) 195 const object *monster; 196 short other; 197 { 198 short i, n, rank = 10, x, ne = 0, found_player = -1; 199 char scores[10][82]; 200 char n_names[10][30]; 201 char buf[128]; 202 FILE *fp; 203 long s; 204 boolean pause = score_only; 205 206 md_lock(1); 207 208 if ((fp = fopen(_PATH_SCOREFILE, "r+")) == NULL && 209 (fp = fopen(_PATH_SCOREFILE, "w+")) == NULL) { 210 message("cannot read/write/create score file", 0); 211 sf_error(); 212 } 213 rewind(fp); 214 (void) xxx(1); 215 216 for (i = 0; i < 10; i++) { 217 if (((n = fread(scores[i], sizeof(char), 80, fp)) < 80) && (n != 0)) { 218 sf_error(); 219 } else if (n != 0) { 220 xxxx(scores[i], 80); 221 if ((n = fread(n_names[i], sizeof(char), 30, fp)) < 30) { 222 sf_error(); 223 } 224 xxxx(n_names[i], 30); 225 } else { 226 break; 227 } 228 ne++; 229 if ((!score_only) && (found_player == -1)) { 230 if (!name_cmp(scores[i]+15, login_name)) { 231 x = 5; 232 while (scores[i][x] == ' ') { 233 x++; 234 } 235 s = lget_number(scores[i] + x); 236 if (rogue.gold < s) { 237 score_only = 1; 238 } else { 239 found_player = i; 240 } 241 } 242 } 243 } 244 if (found_player != -1) { 245 ne--; 246 for (i = found_player; i < ne; i++) { 247 (void) strcpy(scores[i], scores[i+1]); 248 (void) strcpy(n_names[i], n_names[i+1]); 249 } 250 } 251 if (!score_only) { 252 for (i = 0; i < ne; i++) { 253 x = 5; 254 while (scores[i][x] == ' ') { 255 x++; 256 } 257 s = lget_number(scores[i] + x); 258 259 if (rogue.gold >= s) { 260 rank = i; 261 break; 262 } 263 } 264 if (ne == 0) { 265 rank = 0; 266 } else if ((ne < 10) && (rank == 10)) { 267 rank = ne; 268 } 269 if (rank < 10) { 270 insert_score(scores, n_names, nick_name, rank, ne, monster, 271 other); 272 if (ne < 10) { 273 ne++; 274 } 275 } 276 rewind(fp); 277 } 278 279 clear(); 280 mvaddstr(3, 30, "Top Ten Rogueists"); 281 mvaddstr(8, 0, "Rank Score Name"); 282 283 md_ignore_signals(); 284 285 (void) xxx(1); 286 287 for (i = 0; i < ne; i++) { 288 if (i == rank) { 289 standout(); 290 } 291 if (i == 9) { 292 scores[i][0] = '1'; 293 scores[i][1] = '0'; 294 } else { 295 scores[i][0] = ' '; 296 scores[i][1] = i + '1'; 297 } 298 nickize(buf, scores[i], n_names[i]); 299 mvaddstr(i+10, 0, buf); 300 if (rank < 10) { 301 xxxx(scores[i], 80); 302 fwrite(scores[i], sizeof(char), 80, fp); 303 xxxx(n_names[i], 30); 304 fwrite(n_names[i], sizeof(char), 30, fp); 305 } 306 if (i == rank) { 307 standend(); 308 } 309 } 310 md_lock(0); 311 refresh(); 312 fclose(fp); 313 message("", 0); 314 if (pause) { 315 message("", 0); 316 } 317 clean_up(""); 318 } 319 320 insert_score(scores, n_names, n_name, rank, n, monster, other) 321 char scores[][82]; 322 char n_names[][30]; 323 const char *n_name; 324 short rank, n; 325 const object *monster; 326 { 327 short i; 328 char buf[128]; 329 330 if (n > 0) { 331 for (i = n; i > rank; i--) { 332 if ((i < 10) && (i > 0)) { 333 (void) strcpy(scores[i], scores[i-1]); 334 (void) strcpy(n_names[i], n_names[i-1]); 335 } 336 } 337 } 338 sprintf(buf, "%2d %6ld %s: ", rank+1, rogue.gold, login_name); 339 340 if (other) { 341 switch(other) { 342 case HYPOTHERMIA: 343 (void) strcat(buf, "died of hypothermia"); 344 break; 345 case STARVATION: 346 (void) strcat(buf, "died of starvation"); 347 break; 348 case POISON_DART: 349 (void) strcat(buf, "killed by a dart"); 350 break; 351 case QUIT: 352 (void) strcat(buf, "quit"); 353 break; 354 case WIN: 355 (void) strcat(buf, "a total winner"); 356 break; 357 case KFIRE: 358 (void) strcpy(buf, "killed by fire"); 359 break; 360 } 361 } else { 362 (void) strcat(buf, "killed by "); 363 if (is_vowel(m_names[monster->m_char - 'A'][0])) { 364 (void) strcat(buf, "an "); 365 } else { 366 (void) strcat(buf, "a "); 367 } 368 (void) strcat(buf, m_names[monster->m_char - 'A']); 369 } 370 sprintf(buf+strlen(buf), " on level %d ", max_level); 371 if ((other != WIN) && has_amulet()) { 372 (void) strcat(buf, "with amulet"); 373 } 374 for (i = strlen(buf); i < 79; i++) { 375 buf[i] = ' '; 376 } 377 buf[79] = 0; 378 (void) strcpy(scores[rank], buf); 379 (void) strcpy(n_names[rank], n_name); 380 } 381 382 is_vowel(ch) 383 short ch; 384 { 385 return( (ch == 'a') || 386 (ch == 'e') || 387 (ch == 'i') || 388 (ch == 'o') || 389 (ch == 'u') ); 390 } 391 392 sell_pack() 393 { 394 object *obj; 395 short row = 2, val; 396 char buf[DCOLS]; 397 398 obj = rogue.pack.next_object; 399 400 clear(); 401 mvaddstr(1, 0, "Value Item"); 402 403 while (obj) { 404 if (obj->what_is != FOOD) { 405 obj->identified = 1; 406 val = get_value(obj); 407 rogue.gold += val; 408 409 if (row < DROWS) { 410 sprintf(buf, "%5d ", val); 411 get_desc(obj, buf+11); 412 mvaddstr(row++, 0, buf); 413 } 414 } 415 obj = obj->next_object; 416 } 417 refresh(); 418 if (rogue.gold > MAX_GOLD) { 419 rogue.gold = MAX_GOLD; 420 } 421 message("", 0); 422 } 423 424 get_value(obj) 425 const object *obj; 426 { 427 short wc; 428 int val; 429 430 wc = obj->which_kind; 431 432 switch(obj->what_is) { 433 case WEAPON: 434 val = id_weapons[wc].value; 435 if ((wc == ARROW) || (wc == DAGGER) || (wc == SHURIKEN) || 436 (wc == DART)) { 437 val *= obj->quantity; 438 } 439 val += (obj->d_enchant * 85); 440 val += (obj->hit_enchant * 85); 441 break; 442 case ARMOR: 443 val = id_armors[wc].value; 444 val += (obj->d_enchant * 75); 445 if (obj->is_protected) { 446 val += 200; 447 } 448 break; 449 case WAND: 450 val = id_wands[wc].value * (obj->class + 1); 451 break; 452 case SCROL: 453 val = id_scrolls[wc].value * obj->quantity; 454 break; 455 case POTION: 456 val = id_potions[wc].value * obj->quantity; 457 break; 458 case AMULET: 459 val = 5000; 460 break; 461 case RING: 462 val = id_rings[wc].value * (obj->class + 1); 463 break; 464 } 465 if (val <= 0) { 466 val = 10; 467 } 468 return(val); 469 } 470 471 id_all() 472 { 473 short i; 474 475 for (i = 0; i < SCROLS; i++) { 476 id_scrolls[i].id_status = IDENTIFIED; 477 } 478 for (i = 0; i < WEAPONS; i++) { 479 id_weapons[i].id_status = IDENTIFIED; 480 } 481 for (i = 0; i < ARMORS; i++) { 482 id_armors[i].id_status = IDENTIFIED; 483 } 484 for (i = 0; i < WANDS; i++) { 485 id_wands[i].id_status = IDENTIFIED; 486 } 487 for (i = 0; i < POTIONS; i++) { 488 id_potions[i].id_status = IDENTIFIED; 489 } 490 } 491 492 name_cmp(s1, s2) 493 char *s1; 494 const char *s2; 495 { 496 short i = 0; 497 int r; 498 499 while(s1[i] != ':') { 500 i++; 501 } 502 s1[i] = 0; 503 r = strcmp(s1, s2); 504 s1[i] = ':'; 505 return(r); 506 } 507 508 xxxx(buf, n) 509 char *buf; 510 short n; 511 { 512 short i; 513 unsigned char c; 514 515 for (i = 0; i < n; i++) { 516 517 /* It does not matter if accuracy is lost during this assignment */ 518 c = (unsigned char) xxx(0); 519 520 buf[i] ^= c; 521 } 522 } 523 524 long 525 xxx(st) 526 boolean st; 527 { 528 static long f, s; 529 long r; 530 531 if (st) { 532 f = 37; 533 s = 7; 534 return(0L); 535 } 536 r = ((f * s) + 9337) % 8887; 537 f = s; 538 s = r; 539 return(r); 540 } 541 542 nickize(buf, score, n_name) 543 char *buf; 544 const char *score, *n_name; 545 { 546 short i = 15, j; 547 548 if (!n_name[0]) { 549 (void) strcpy(buf, score); 550 } else { 551 (void) strncpy(buf, score, 16); 552 553 while (score[i] != ':') { 554 i++; 555 } 556 557 (void) strcpy(buf+15, n_name); 558 j = strlen(buf); 559 560 while (score[i]) { 561 buf[j++] = score[i++]; 562 } 563 buf[j] = 0; 564 buf[79] = 0; 565 } 566 } 567 568 center(row, buf) 569 short row; 570 const char *buf; 571 { 572 short margin; 573 574 margin = ((DCOLS - strlen(buf)) / 2); 575 mvaddstr(row, margin, buf); 576 } 577 578 sf_error() 579 { 580 md_lock(0); 581 message("", 1); 582 clean_up("sorry, score file is out of order"); 583 } 584