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