1 /* 2 * fight.c Phantasia monster fighting routines 3 * 4 * $FreeBSD: src/games/phantasia/fight.c,v 1.7 1999/11/16 02:57:33 billf Exp $ 5 * $DragonFly: src/games/phantasia/fight.c,v 1.3 2005/05/31 00:06:26 swildner Exp $ 6 */ 7 8 #include <string.h> 9 #include "include.h" 10 11 /* functions which we need to know about */ 12 /* io.c */ 13 extern int getanswer(const char *, bool); 14 extern void getstring(char *, int); 15 extern double infloat(void); 16 extern int inputoption(void); 17 extern void more(int); 18 /* misc.c */ 19 extern void altercoordinates(double, double, int); 20 extern void collecttaxes(double, double); 21 extern void death(const char *); 22 extern void displaystats(void); 23 extern void readmessage(void); 24 extern void truncstring(char *); 25 extern void writerecord(struct player *, long); 26 /* phantglobs.c */ 27 extern double drandom(void); 28 29 void awardtreasure(void); 30 void callmonster(int); 31 void cancelmonster(void); 32 void cursedtreasure(void); 33 void encounter(int); 34 void hitmonster(double); 35 int pickmonster(void); 36 void monsthits(void); 37 void playerhits(void); 38 void scramblestats(void); 39 void throwspell(void); 40 41 /* 42 * FUNCTION: monster battle routine 43 * 44 * ARGUMENTS: 45 * int particular - particular monster to fight if >= 0 46 * 47 * GLOBAL INPUTS: Curmonster, Whichmonster, LINES, Lines, Circle, Shield, 48 * Player, *stdscr, Fileloc, Fightenv[], *Enemyname 49 * 50 * GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player, Luckout 51 * 52 * DESCRIPTION: 53 * Choose a monster and check against some special types. 54 * Arbitrate between monster and player. Watch for either 55 * dying. 56 */ 57 58 void 59 encounter(int particular) 60 { 61 volatile bool firsthit = Player.p_blessing; /* set if player gets the first hit */ 62 int flockcnt = 1; /* how many time flocked */ 63 64 /* let others know what we are doing */ 65 Player.p_status = S_MONSTER; 66 writerecord(&Player, Fileloc); 67 68 #ifdef SYS5 69 flushinp(); 70 #endif 71 72 Shield = 0.0; /* no shield up yet */ 73 74 if (particular >= 0) 75 /* monster is specified */ 76 Whichmonster = particular; 77 else 78 /* pick random monster */ 79 Whichmonster = pickmonster(); 80 81 setjmp(Fightenv); /* this is to enable changing fight state */ 82 83 move(6, 0); 84 clrtobot(); /* clear bottom area of screen */ 85 86 Lines = 9; 87 callmonster(Whichmonster); /* set up monster to fight */ 88 89 Luckout = FALSE; /* haven't tried to luckout yet */ 90 91 if (Curmonster.m_type == SM_MORGOTH) 92 mvprintw(4, 0, "You've encountered %s, Bane of the Council and Valar.\n", 93 Enemyname); 94 95 if (Curmonster.m_type == SM_UNICORN) { 96 if (Player.p_virgin) { 97 printw("You just subdued %s, thanks to the virgin.\n", Enemyname); 98 Player.p_virgin = FALSE; 99 } else { 100 printw("You just saw %s running away!\n", Enemyname); 101 Curmonster.m_experience = 0.0; 102 Curmonster.m_treasuretype = 0; 103 } 104 } else 105 /* not a special monster */ 106 for (;;) { 107 /* print header, and arbitrate between player and monster */ 108 mvprintw(6, 0, "You are being attacked by %s, EXP: %.0f (Size: %.0f)\n", 109 Enemyname, Curmonster.m_experience, Circle); 110 111 displaystats(); 112 mvprintw(1, 26, "%20.0f", Player.p_energy + Shield); /* overprint energy */ 113 readmessage(); 114 115 if (Curmonster.m_type == SM_DARKLORD 116 && Player.p_blessing 117 && Player.p_charms > 0) { 118 /* overpower Dark Lord with blessing and charm */ 119 mvprintw(7, 0, "You just overpowered %s!", Enemyname); 120 Lines = 8; 121 Player.p_blessing = FALSE; 122 --Player.p_charms; 123 break; 124 } 125 126 /* allow paralyzed monster to wake up */ 127 Curmonster.m_speed = MIN(Curmonster.m_speed + 1.0, Curmonster.m_maxspeed); 128 129 if (drandom() * Curmonster.m_speed > drandom() * Player.p_speed 130 /* monster is faster */ 131 && Curmonster.m_type != SM_DARKLORD 132 /* not D. L. */ 133 && Curmonster.m_type != SM_SHRIEKER 134 /* not mimic */ 135 && !firsthit) 136 /* monster gets a hit */ 137 monsthits(); 138 else { 139 /* player gets a hit */ 140 firsthit = FALSE; 141 playerhits(); 142 } 143 144 refresh(); 145 146 if (Lines > LINES - 2) { 147 /* near bottom of screen - pause */ 148 more(Lines); 149 move(Lines = 8, 0); 150 clrtobot(); 151 } 152 153 if (Player.p_energy <= 0.0) { 154 /* player died */ 155 more(Lines); 156 death(Enemyname); 157 cancelmonster(); 158 break; /* fight ends if the player is saved from death */ 159 } 160 161 if (Curmonster.m_energy <= 0.0) 162 /* monster died */ 163 break; 164 } 165 166 /* give player credit for killing monster */ 167 Player.p_experience += Curmonster.m_experience; 168 169 if (drandom() < Curmonster.m_flock / 100.0) { 170 /* monster flocks */ 171 more(Lines); 172 ++flockcnt; 173 longjmp(Fightenv, 0); 174 /* NOTREACHED */ 175 } else if (Circle > 1.0 && 176 Curmonster.m_treasuretype > 0 && 177 drandom() > 0.2 + pow(0.4, (double)(flockcnt / 3 + Circle / 3.0))) { 178 /* monster has treasure; this takes # of flocks and size into account */ 179 more(Lines); 180 awardtreasure(); 181 } 182 183 /* pause before returning */ 184 getyx(stdscr, Lines, flockcnt); 185 more(Lines + 1); 186 187 Player.p_ring.ring_inuse = FALSE; /* not using ring */ 188 189 /* clean up the screen */ 190 move(4, 0); 191 clrtobot(); 192 } 193 194 /* 195 * FUNCTION: choose a monster based upon where we are 196 * 197 * RETURN VALUE: monster number to call 198 * 199 * GLOBAL INPUTS: Marsh, Circle, Player 200 * 201 * DESCRIPTION: 202 * Certain monsters can be found in certain areas of the grid. 203 * We take care of rolling them here. 204 * Unfortunately, this routine assumes that the monster data 205 * base is arranged in a particular order. If the data base 206 * is altered (to add monsters, or make them tougher), this 207 * routine may also need to be changed. 208 */ 209 210 int 211 pickmonster(void) 212 { 213 if (Player.p_specialtype == SC_VALAR) 214 /* even chance of any monster */ 215 return ((int)ROLL(0.0, 100.0)); 216 217 if (Marsh) 218 /* water monsters */ 219 return ((int)ROLL(0.0, 15.0)); 220 221 else if (Circle > 24) 222 /* even chance of all non-water monsters */ 223 return ((int)ROLL(14.0, 86.0)); 224 225 else if (Circle > 15) 226 /* chance of all non-water monsters, weighted toward middle */ 227 return ((int)(ROLL(0.0, 50.0) + ROLL(14.0, 37.0))); 228 229 else if (Circle > 8) 230 /* not all non-water monsters, weighted toward middle */ 231 return ((int)(ROLL(0.0, 50.0) + ROLL(14.0, 26.0))); 232 233 else if (Circle > 3) 234 /* even chance of some tamer non-water monsters */ 235 return ((int)ROLL(14.0, 50.0)); 236 237 else 238 /* even chance of some of the tamest non-water monsters */ 239 return ((int)ROLL(14.0, 25.0)); 240 } 241 242 /* 243 * FUNCTION: prompt player for action in monster battle, and process 244 * 245 * GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, Luckout, *Enemyname 246 * 247 * GLOBAL OUTPUTS: Curmonster, Lines, Player, Luckout 248 * 249 * DESCRIPTION: 250 * Process all monster battle options. 251 */ 252 253 void 254 playerhits(void) 255 { 256 double inflict; /* damage inflicted */ 257 int ch; /* input */ 258 259 mvaddstr(7, 0, "1:Melee 2:Skirmish 3:Evade 4:Spell 5:Nick "); 260 261 if (!Luckout) { 262 /* haven't tried to luckout yet */ 263 if (Curmonster.m_type == SM_MORGOTH) 264 /* cannot luckout against Morgoth */ 265 addstr("6:Ally "); 266 else 267 addstr("6:Luckout "); 268 } 269 270 if (Player.p_ring.ring_type != R_NONE) 271 /* player has a ring */ 272 addstr("7:Use Ring "); 273 else 274 clrtoeol(); 275 276 ch = inputoption(); 277 278 move(8, 0); 279 clrtobot(); /* clear any messages from before */ 280 Lines = 9; 281 mvaddstr(4, 0, "\n\n"); /* clear status area */ 282 283 switch (ch) { 284 case 'T': /* timeout; lose turn */ 285 break; 286 287 case ' ': 288 case '1': /* melee */ 289 /* melee affects monster's energy and strength */ 290 inflict = ROLL(Player.p_might / 2.0 + 5.0, 1.3 * Player.p_might) + 291 (Player.p_ring.ring_inuse ? Player.p_might : 0.0); 292 293 Curmonster.m_melee += inflict; 294 Curmonster.m_strength = Curmonster.m_o_strength - 295 Curmonster.m_melee / Curmonster.m_o_energy * 296 Curmonster.m_o_strength / 4.0; 297 hitmonster(inflict); 298 break; 299 300 case '2': /* skirmish */ 301 /* skirmish affects monter's energy and speed */ 302 inflict = ROLL(Player.p_might / 3.0 + 3.0, 1.1 * Player.p_might) + 303 (Player.p_ring.ring_inuse ? Player.p_might : 0.0); 304 305 Curmonster.m_skirmish += inflict; 306 Curmonster.m_maxspeed = Curmonster.m_o_speed - 307 Curmonster.m_skirmish / Curmonster.m_o_energy * 308 Curmonster.m_o_speed / 4.0; 309 hitmonster(inflict); 310 break; 311 312 case '3': /* evade */ 313 /* use brains and speed to try to evade */ 314 if ((Curmonster.m_type == SM_DARKLORD || 315 Curmonster.m_type == SM_SHRIEKER 316 /* can always run from D. L. and shrieker */ 317 || drandom() * Player.p_speed * Player.p_brains 318 > drandom() * Curmonster.m_speed * Curmonster.m_brains) && 319 (Curmonster.m_type != SM_MIMIC)) { 320 /* cannot run from mimic */ 321 mvaddstr(Lines++, 0, "You got away!"); 322 cancelmonster(); 323 altercoordinates(0.0, 0.0, A_NEAR); 324 } else 325 mvprintw(Lines++, 0, "%s is still after you!", Enemyname); 326 327 break; 328 329 case 'M': 330 case '4': /* magic spell */ 331 throwspell(); 332 break; 333 334 case '5': /* nick */ 335 /* hit 1 plus sword; give some experience */ 336 inflict = 1.0 + Player.p_sword; 337 Player.p_experience += floor(Curmonster.m_experience / 10.0); 338 Curmonster.m_experience *= 0.92; 339 /* monster gets meaner */ 340 Curmonster.m_maxspeed += 2.0; 341 Curmonster.m_speed = (Curmonster.m_speed < 0.0) ? 0.0 : Curmonster.m_speed + 2.0; 342 if (Curmonster.m_type == SM_DARKLORD) { 343 /* Dark Lord; doesn't like to be nicked */ 344 mvprintw(Lines++, 0, 345 "You hit %s %.0f times, and made him mad!", Enemyname, inflict); 346 Player.p_quickness /= 2.0; 347 altercoordinates(0.0, 0.0, A_FAR); 348 cancelmonster(); 349 } else 350 hitmonster(inflict); 351 break; 352 353 case 'B': 354 case '6': /* luckout */ 355 if (Luckout) 356 mvaddstr(Lines++, 0, "You already tried that."); 357 else { 358 Luckout = TRUE; 359 if (Curmonster.m_type == SM_MORGOTH) { 360 /* Morgoth; ally */ 361 if (drandom() < Player.p_sin / 100.0) { 362 mvprintw(Lines++, 0, "%s accepted!", Enemyname); 363 cancelmonster(); 364 } else 365 mvaddstr(Lines++, 0, "Nope, he's not interested."); 366 } else { 367 /* normal monster; use brains for success */ 368 if ((drandom() + 0.333) * Player.p_brains 369 < (drandom() + 0.333) * Curmonster.m_brains) 370 mvprintw(Lines++, 0, "You blew it, %s.", Player.p_name); 371 else { 372 mvaddstr(Lines++, 0, "You made it!"); 373 Curmonster.m_energy = 0.0; 374 } 375 } 376 } 377 break; 378 379 case '7': /* use ring */ 380 if (Player.p_ring.ring_type != R_NONE) { 381 mvaddstr(Lines++, 0, "Now using ring."); 382 Player.p_ring.ring_inuse = TRUE; 383 if (Player.p_ring.ring_type != R_DLREG) 384 /* age ring */ 385 --Player.p_ring.ring_duration; 386 } 387 break; 388 } 389 } 390 391 /* 392 * FUNCTION: process a monster hitting the player 393 * 394 * GLOBAL INPUTS: Curmonster, Lines, Circle, Shield, Player, *stdscr, 395 * Fightenv[], *Enemyname 396 * 397 * GLOBAL OUTPUTS: Curmonster, Whichmonster, Lines, Shield, Player, 398 * *Enemyname 399 * 400 * DESCRIPTION: 401 * Handle all special monsters here. If the monster is not a special 402 * one, simply roll a hit against the player. 403 */ 404 405 void 406 monsthits(void) 407 { 408 double inflict; /* damage inflicted */ 409 int ch; /* input */ 410 411 switch (Curmonster.m_type) { 412 /* may be a special monster */ 413 case SM_DARKLORD: 414 /* hits just enough to kill player */ 415 inflict = (Player.p_energy + Shield) * 1.02; 416 goto SPECIALHIT; 417 418 case SM_SHRIEKER: 419 /* call a big monster */ 420 mvaddstr(Lines++, 0, 421 "Shrieeeek!! You scared it, and it called one of its friends."); 422 more(Lines); 423 Whichmonster = (int)ROLL(70.0, 30.0); 424 longjmp(Fightenv, 0); 425 /* NOTREACHED */ 426 427 case SM_BALROG: 428 /* take experience away */ 429 inflict = ROLL(10.0, Curmonster.m_strength); 430 inflict = MIN(Player.p_experience, inflict); 431 mvprintw(Lines++, 0, 432 "%s took away %.0f experience points.", Enemyname, inflict); 433 Player.p_experience -= inflict; 434 return; 435 436 case SM_FAERIES: 437 if (Player.p_holywater > 0) { 438 /* holy water kills when monster tries to hit */ 439 mvprintw(Lines++, 0, "Your holy water killed it!"); 440 --Player.p_holywater; 441 Curmonster.m_energy = 0.0; 442 return; 443 } 444 break; 445 446 case SM_NONE: 447 /* normal hit */ 448 break; 449 450 default: 451 if (drandom() > 0.2) 452 /* normal hit */ 453 break; 454 455 /* else special things */ 456 switch (Curmonster.m_type) { 457 case SM_LEANAN: 458 /* takes some of the player's strength */ 459 inflict = ROLL(1.0, (Circle - 1.0) / 2.0); 460 inflict = MIN(Player.p_strength, inflict); 461 mvprintw(Lines++, 0, "%s sapped %0.f of your strength!", 462 Enemyname, inflict); 463 Player.p_strength -= inflict; 464 Player.p_might -= inflict; 465 break; 466 467 case SM_SARUMAN: 468 if (Player.p_palantir) { 469 /* take away palantir */ 470 mvprintw(Lines++, 0, "Wormtongue stole your palantir!"); 471 Player.p_palantir = FALSE; 472 } else if (drandom() > 0.5) { 473 /* gems turn to gold */ 474 mvprintw(Lines++, 0, 475 "%s transformed your gems into gold!", Enemyname); 476 Player.p_gold += Player.p_gems; 477 Player.p_gems = 0.0; 478 } else { 479 /* scramble some stats */ 480 mvprintw(Lines++, 0, "%s scrambled your stats!", Enemyname); 481 scramblestats(); 482 } 483 break; 484 485 case SM_THAUMATURG: 486 /* transport player */ 487 mvprintw(Lines++, 0, "%s transported you!", Enemyname); 488 altercoordinates(0.0, 0.0, A_FAR); 489 cancelmonster(); 490 break; 491 492 case SM_VORTEX: 493 /* suck up some mana */ 494 inflict = ROLL(0, 7.5 * Circle); 495 inflict = MIN(Player.p_mana, floor(inflict)); 496 mvprintw(Lines++, 0, 497 "%s sucked up %.0f of your mana!", Enemyname, inflict); 498 Player.p_mana -= inflict; 499 break; 500 501 case SM_NAZGUL: 502 /* try to take ring if player has one */ 503 if (Player.p_ring.ring_type != R_NONE) { 504 /* player has a ring */ 505 mvaddstr(Lines++, 0, "Will you relinguish your ring ? "); 506 ch = getanswer("YN", FALSE); 507 if (ch == 'Y') { 508 /* take ring away */ 509 Player.p_ring.ring_type = R_NONE; 510 Player.p_ring.ring_inuse = FALSE; 511 cancelmonster(); 512 break; 513 } 514 } 515 516 /* otherwise, take some brains */ 517 mvprintw(Lines++, 0, 518 "%s neutralized 1/5 of your brain!", Enemyname); 519 Player.p_brains *= 0.8; 520 break; 521 522 case SM_TIAMAT: 523 /* take some gold and gems */ 524 mvprintw(Lines++, 0, 525 "%s took half your gold and gems and flew off.", Enemyname); 526 Player.p_gold /= 2.0; 527 Player.p_gems /= 2.0; 528 cancelmonster(); 529 break; 530 531 case SM_KOBOLD: 532 /* steal a gold piece and run */ 533 mvprintw(Lines++, 0, 534 "%s stole one gold piece and ran away.", Enemyname); 535 Player.p_gold = MAX(0.0, Player.p_gold - 1.0); 536 cancelmonster(); 537 break; 538 539 case SM_SHELOB: 540 /* bite and (medium) poison */ 541 mvprintw(Lines++, 0, 542 "%s has bitten and poisoned you!", Enemyname); 543 Player.p_poison -= 1.0; 544 break; 545 546 case SM_LAMPREY: 547 /* bite and (small) poison */ 548 mvprintw(Lines++, 0, "%s bit and poisoned you!", Enemyname); 549 Player.p_poison += 0.25; 550 break; 551 552 case SM_BONNACON: 553 /* fart and run */ 554 mvprintw(Lines++, 0, "%s farted and scampered off.", Enemyname); 555 Player.p_energy /= 2.0; /* damage from fumes */ 556 cancelmonster(); 557 break; 558 559 case SM_SMEAGOL: 560 if (Player.p_ring.ring_type != R_NONE) { 561 /* try to steal ring */ 562 mvprintw(Lines++, 0, 563 "%s tried to steal your ring, ", Enemyname); 564 if (drandom() > 0.1) 565 addstr("but was unsuccessful."); 566 else { 567 addstr("and ran away with it!"); 568 Player.p_ring.ring_type = R_NONE; 569 cancelmonster(); 570 } 571 } 572 break; 573 574 case SM_SUCCUBUS: 575 /* inflict damage through shield */ 576 inflict = ROLL(15.0, Circle * 10.0); 577 inflict = MIN(inflict, Player.p_energy); 578 mvprintw(Lines++, 0, "%s sapped %.0f of your energy.", 579 Enemyname, inflict); 580 Player.p_energy -= inflict; 581 break; 582 583 case SM_CERBERUS: 584 /* take all metal treasures */ 585 mvprintw(Lines++, 0, 586 "%s took all your metal treasures!", Enemyname); 587 Player.p_crowns = 0; 588 Player.p_sword = 589 Player.p_shield = 590 Player.p_gold = 0.0; 591 cancelmonster(); 592 break; 593 594 case SM_UNGOLIANT: 595 /* (large) poison and take a quickness */ 596 mvprintw(Lines++, 0, 597 "%s poisoned you, and took one quik.", Enemyname); 598 Player.p_poison += 5.0; 599 Player.p_quickness -= 1.0; 600 break; 601 602 case SM_JABBERWOCK: 603 /* fly away, and leave either a Jubjub bird or Bonnacon */ 604 mvprintw(Lines++, 0, 605 "%s flew away, and left you to contend with one of its friends.", 606 Enemyname); 607 Whichmonster = (drandom() > 0.5) ? 77 : 55; 608 longjmp(Fightenv, 0); 609 /* NOTREACHED */ 610 611 case SM_TROLL: 612 /* partially regenerate monster */ 613 mvprintw(Lines++, 0, 614 "%s partially regenerated his energy.!", Enemyname); 615 Curmonster.m_energy += 616 floor((Curmonster.m_o_energy - Curmonster.m_energy) / 2.0); 617 Curmonster.m_strength = Curmonster.m_o_strength; 618 Curmonster.m_melee = Curmonster.m_skirmish = 0.0; 619 Curmonster.m_maxspeed = Curmonster.m_o_speed; 620 break; 621 622 case SM_WRAITH: 623 if (!Player.p_blindness) { 624 /* make blind */ 625 mvprintw(Lines++, 0, "%s blinded you!", Enemyname); 626 Player.p_blindness = TRUE; 627 Enemyname = "A monster"; 628 } 629 break; 630 } 631 return; 632 } 633 634 /* fall through to here if monster inflicts a normal hit */ 635 inflict = drandom() * Curmonster.m_strength + 0.5; 636 SPECIALHIT: 637 mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, inflict); 638 639 if ((Shield -= inflict) < 0) { 640 Player.p_energy += Shield; 641 Shield = 0.0; 642 } 643 } 644 645 /* 646 * FUNCTION: mark current monster as no longer active 647 * 648 * GLOBAL OUTPUTS: Curmonster 649 * 650 * DESCRIPTION: 651 * Clear current monster's energy, experience, treasure type, and 652 * flock. This is the same as having the monster run away. 653 */ 654 655 void 656 cancelmonster(void) 657 { 658 Curmonster.m_energy = 0.0; 659 Curmonster.m_experience = 0.0; 660 Curmonster.m_treasuretype = 0; 661 Curmonster.m_flock = 0.0; 662 } 663 664 /* 665 * FUNCTION: inflict damage upon current monster 666 * 667 * ARGUMENTS: 668 * double inflict - damage to inflict upon monster 669 * 670 * GLOBAL INPUTS: Curmonster, Lines, Player, *stdscr, *Enemyname 671 * 672 * GLOBAL OUTPUTS: Curmonster, Lines 673 * 674 * DESCRIPTION: 675 * Hit monster specified number of times. Handle when monster dies, 676 * and a few special monsters. 677 */ 678 679 void 680 hitmonster(double inflict) 681 { 682 mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, inflict); 683 Curmonster.m_energy -= inflict; 684 if (Curmonster.m_energy > 0.0) { 685 if (Curmonster.m_type == SM_DARKLORD || Curmonster.m_type == SM_SHRIEKER) 686 /* special monster didn't die */ 687 monsthits(); 688 } else { 689 /* monster died. print message. */ 690 if (Curmonster.m_type == SM_MORGOTH) 691 mvaddstr(Lines++, 0, "You have defeated Morgoth, but he may return. . ."); 692 else { 693 /* all other types of monsters */ 694 mvprintw(Lines++, 0, "You killed it. Good work, %s.", Player.p_name); 695 696 if (Curmonster.m_type == SM_MIMIC 697 && strcmp(Curmonster.m_name, "A Mimic") != 0 698 && !Player.p_blindness) 699 mvaddstr(Lines++, 0, "The body slowly changes into the form of a mimic."); 700 } 701 } 702 } 703 704 /* 705 * FUNCTION: throw a magic spell 706 * 707 * GLOBAL INPUTS: Curmonster, Whichmonster, Nomana[], Player, *stdscr, 708 * Fightenv[], Illspell[], *Enemyname 709 * 710 * GLOBAL OUTPUTS: Curmonster, Whichmonster, Shield, Player 711 * 712 * DESCRIPTION: 713 * Prompt player and process magic spells. 714 */ 715 716 void 717 throwspell(void) 718 { 719 double inflict; /* damage inflicted */ 720 double dtemp; /* for dtemporary calculations */ 721 int ch; /* input */ 722 723 inflict = 0; 724 mvaddstr(7, 0, "\n\n"); /* clear menu area */ 725 726 if (Player.p_magiclvl >= ML_ALLORNOTHING) 727 mvaddstr(7, 0, "1:All or Nothing "); 728 if (Player.p_magiclvl >= ML_MAGICBOLT) 729 addstr("2:Magic Bolt "); 730 if (Player.p_magiclvl >= ML_FORCEFIELD) 731 addstr("3:Force Field "); 732 if (Player.p_magiclvl >= ML_XFORM) 733 addstr("4:Transform "); 734 if (Player.p_magiclvl >= ML_INCRMIGHT) 735 addstr("5:Increase Might\n"); 736 if (Player.p_magiclvl >= ML_INVISIBLE) 737 mvaddstr(8, 0, "6:Invisibility "); 738 if (Player.p_magiclvl >= ML_XPORT) 739 addstr("7:Transport "); 740 if (Player.p_magiclvl >= ML_PARALYZE) 741 addstr("8:Paralyze "); 742 if (Player.p_specialtype >= SC_COUNCIL) 743 addstr("9:Specify"); 744 mvaddstr(4, 0, "Spell ? "); 745 746 ch = getanswer(" ", TRUE); 747 748 mvaddstr(7, 0, "\n\n"); /* clear menu area */ 749 750 if (Curmonster.m_type == SM_MORGOTH && ch != '3') 751 /* can only throw force field against Morgoth */ 752 ILLSPELL(); 753 else 754 switch (ch) { 755 case '1': /* all or nothing */ 756 if (drandom() < 0.25) { 757 /* success */ 758 inflict = Curmonster.m_energy * 1.01 + 1.0; 759 760 if (Curmonster.m_type == SM_DARKLORD) 761 /* all or nothing doesn't quite work against D. L. */ 762 inflict *= 0.9; 763 } else { 764 /* failure -- monster gets stronger and quicker */ 765 Curmonster.m_o_strength = Curmonster.m_strength *= 2.0; 766 Curmonster.m_maxspeed *= 2.0; 767 Curmonster.m_o_speed *= 2.0; 768 769 /* paralyzed monsters wake up a bit */ 770 Curmonster.m_speed = MAX(1.0, Curmonster.m_speed * 2.0); 771 } 772 773 if (Player.p_mana >= MM_ALLORNOTHING) 774 /* take a mana if player has one */ 775 Player.p_mana -= MM_ALLORNOTHING; 776 777 hitmonster(inflict); 778 break; 779 780 case '2': /* magic bolt */ 781 if (Player.p_magiclvl < ML_MAGICBOLT) 782 ILLSPELL(); 783 else { 784 do { 785 /* prompt for amount to expend */ 786 mvaddstr(4, 0, "How much mana for bolt? "); 787 dtemp = floor(infloat()); 788 } while (dtemp < 0.0 || dtemp > Player.p_mana); 789 790 Player.p_mana -= dtemp; 791 792 if (Curmonster.m_type == SM_DARKLORD) 793 /* magic bolts don't work against D. L. */ 794 inflict = 0.0; 795 else 796 inflict = dtemp * ROLL(15.0, sqrt(Player.p_magiclvl / 3.0 + 1.0)); 797 mvaddstr(5, 0, "Magic Bolt fired!\n"); 798 hitmonster(inflict); 799 } 800 break; 801 802 case '3': /* force field */ 803 if (Player.p_magiclvl < ML_FORCEFIELD) 804 ILLSPELL(); 805 else if (Player.p_mana < MM_FORCEFIELD) 806 NOMANA(); 807 else { 808 Player.p_mana -= MM_FORCEFIELD; 809 Shield = (Player.p_maxenergy + Player.p_shield) * 4.2 + 45.0; 810 mvaddstr(5, 0, "Force Field up.\n"); 811 } 812 break; 813 814 case '4': /* transform */ 815 if (Player.p_magiclvl < ML_XFORM) 816 ILLSPELL(); 817 else if (Player.p_mana < MM_XFORM) 818 NOMANA(); 819 else { 820 Player.p_mana -= MM_XFORM; 821 Whichmonster = (int)ROLL(0.0, 100.0); 822 longjmp(Fightenv, 0); 823 /* NOTREACHED */ 824 } 825 break; 826 827 case '5': /* increase might */ 828 if (Player.p_magiclvl < ML_INCRMIGHT) 829 ILLSPELL(); 830 else if (Player.p_mana < MM_INCRMIGHT) 831 NOMANA(); 832 else { 833 Player.p_mana -= MM_INCRMIGHT; 834 Player.p_might += 835 (1.2 * (Player.p_strength + Player.p_sword) + 836 5.0 - Player.p_might) / 2.0; 837 mvprintw(5, 0, "New strength: %.0f\n", Player.p_might); 838 } 839 break; 840 841 case '6': /* invisible */ 842 if (Player.p_magiclvl < ML_INVISIBLE) 843 ILLSPELL(); 844 else if (Player.p_mana < MM_INVISIBLE) 845 NOMANA(); 846 else { 847 Player.p_mana -= MM_INVISIBLE; 848 Player.p_speed += 849 (1.2 * (Player.p_quickness + Player.p_quksilver) + 850 5.0 - Player.p_speed) / 2.0; 851 mvprintw(5, 0, "New quickness: %.0f\n", Player.p_speed); 852 } 853 break; 854 855 case '7': /* transport */ 856 if (Player.p_magiclvl < ML_XPORT) 857 ILLSPELL(); 858 else if (Player.p_mana < MM_XPORT) 859 NOMANA(); 860 else { 861 Player.p_mana -= MM_XPORT; 862 if (Player.p_brains + Player.p_magiclvl 863 < Curmonster.m_experience / 200.0 * drandom()) { 864 mvaddstr(5, 0, "Transport backfired!\n"); 865 altercoordinates(0.0, 0.0, A_FAR); 866 cancelmonster(); 867 } else { 868 mvprintw(5, 0, "%s is transported.\n", Enemyname); 869 if (drandom() < 0.3) 870 /* monster didn't drop its treasure */ 871 Curmonster.m_treasuretype = 0; 872 873 Curmonster.m_energy = 0.0; 874 } 875 } 876 break; 877 878 case '8': /* paralyze */ 879 if (Player.p_magiclvl < ML_PARALYZE) 880 ILLSPELL(); 881 else if (Player.p_mana < MM_PARALYZE) 882 NOMANA(); 883 else { 884 Player.p_mana -= MM_PARALYZE; 885 if (Player.p_magiclvl > 886 Curmonster.m_experience / 1000.0 * drandom()) { 887 mvprintw(5, 0, "%s is held.\n", Enemyname); 888 Curmonster.m_speed = -2.0; 889 } else 890 mvaddstr(5, 0, "Monster unaffected.\n"); 891 } 892 break; 893 894 case '9': /* specify */ 895 if (Player.p_specialtype < SC_COUNCIL) 896 ILLSPELL(); 897 else if (Player.p_mana < MM_SPECIFY) 898 NOMANA(); 899 else { 900 Player.p_mana -= MM_SPECIFY; 901 mvaddstr(5, 0, "Which monster do you want [0-99] ? "); 902 Whichmonster = (int)infloat(); 903 Whichmonster = MAX(0, MIN(99, Whichmonster)); 904 longjmp(Fightenv, 0); 905 /* NOTREACHED */ 906 } 907 break; 908 } 909 } 910 911 /* 912 * FUNCTION: read monster from file, and fill structure 913 * 914 * ARGUMENTS: 915 * int which - which monster to call 916 * 917 * GLOBAL INPUTS: Curmonster, Circle, Player, *Monstfp 918 * 919 * GLOBAL OUTPUTS: Curmonster, Player, *Enemyname 920 * 921 * DESCRIPTION: 922 * Read specified monster from monster database and fill up 923 * current monster structure. 924 * Adjust statistics based upon current size. 925 * Handle some special monsters. 926 */ 927 928 void 929 callmonster(int which) 930 { 931 struct monster Othermonster; /* to find a name for mimics */ 932 933 which = MIN(which, 99); /* make sure within range */ 934 935 /* fill structure */ 936 fseek(Monstfp, (long)which * (long)SZ_MONSTERSTRUCT, SEEK_SET); 937 fread((char *)&Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp); 938 939 /* handle some special monsters */ 940 if (Curmonster.m_type == SM_MODNAR) { 941 if (Player.p_specialtype < SC_COUNCIL) { 942 /* randomize some stats */ 943 Curmonster.m_strength *= drandom() + 0.5; 944 Curmonster.m_brains *= drandom() + 0.5; 945 Curmonster.m_speed *= drandom() + 0.5; 946 Curmonster.m_energy *= drandom() + 0.5; 947 Curmonster.m_experience *= drandom() + 0.5; 948 Curmonster.m_treasuretype = 949 (int)ROLL(0.0, (double)Curmonster.m_treasuretype); 950 } else { 951 /* make Modnar into Morgoth */ 952 strcpy(Curmonster.m_name, "Morgoth"); 953 Curmonster.m_strength = drandom() * (Player.p_maxenergy + Player.p_shield) / 1.4 954 + drandom() * (Player.p_maxenergy + Player.p_shield) / 1.5; 955 Curmonster.m_brains = Player.p_brains; 956 Curmonster.m_energy = Player.p_might * 30.0; 957 Curmonster.m_type = SM_MORGOTH; 958 Curmonster.m_speed = Player.p_speed * 959 ((Player.p_specialtype == SC_EXVALAR) ? 2.1 : 1.1); 960 Curmonster.m_flock = 0.0; 961 Curmonster.m_treasuretype = 0; 962 Curmonster.m_experience = 0.0; 963 } 964 } else if (Curmonster.m_type == SM_MIMIC) { 965 /* pick another name */ 966 which = (int)ROLL(0.0, 100.0); 967 fseek(Monstfp, (long)which * (long)SZ_MONSTERSTRUCT, SEEK_SET); 968 fread(&Othermonster, SZ_MONSTERSTRUCT, 1, Monstfp); 969 strcpy(Curmonster.m_name, Othermonster.m_name); 970 } 971 972 truncstring(Curmonster.m_name); 973 974 if (Curmonster.m_type != SM_MORGOTH) { 975 /* adjust stats based on which circle player is in */ 976 Curmonster.m_strength *= (1.0 + Circle / 2.0); 977 Curmonster.m_brains *= Circle; 978 Curmonster.m_speed += Circle * 1.e-9; 979 Curmonster.m_energy *= Circle; 980 Curmonster.m_experience *= Circle; 981 } 982 983 if (Player.p_blindness) 984 /* cannot see monster if blind */ 985 Enemyname = "A monster"; 986 else 987 Enemyname = Curmonster.m_name; 988 989 if (Player.p_speed <= 0.0) { 990 /* make Player.p_speed positive */ 991 Curmonster.m_speed += -Player.p_speed; 992 Player.p_speed = 1.0; 993 } 994 995 /* fill up the rest of the structure */ 996 Curmonster.m_o_strength = Curmonster.m_strength; 997 Curmonster.m_o_speed = Curmonster.m_maxspeed = Curmonster.m_speed; 998 Curmonster.m_o_energy = Curmonster.m_energy; 999 Curmonster.m_melee = Curmonster.m_skirmish = 0.0; 1000 } 1001 1002 /* 1003 * FUNCTION: select a treasure 1004 * 1005 * GLOBAL INPUTS: Somebetter[], Curmonster, Whichmonster, Circle, Player, 1006 * *stdscr, Databuf[], *Statptr, Fightenv[] 1007 * 1008 * GLOBAL OUTPUTS: Whichmonster, Shield, Player 1009 * 1010 * DESCRIPTION: 1011 * Roll up a treasure based upon monster type and size, and 1012 * certain player statistics. 1013 * Handle cursed treasure. 1014 */ 1015 1016 void 1017 awardtreasure(void) 1018 { 1019 int whichtreasure; /* calculated treasure to grant */ 1020 int temp; /* temporary */ 1021 int ch; /* input */ 1022 double treasuretype; /* monster's treasure type */ 1023 double gold = 0.0; /* gold awarded */ 1024 double gems = 0.0; /* gems awarded */ 1025 double dtemp; /* for temporary calculations */ 1026 1027 whichtreasure = (int)ROLL(1.0, 3.0); /* pick a treasure */ 1028 treasuretype = (double)Curmonster.m_treasuretype; 1029 1030 move(4, 0); 1031 clrtobot(); 1032 move(6, 0); 1033 1034 if (drandom() > 0.65) { 1035 /* gold and gems */ 1036 if (Curmonster.m_treasuretype > 7) { 1037 /* gems */ 1038 gems = ROLL(1.0, (treasuretype - 7.0) 1039 * (treasuretype - 7.0) * (Circle - 1.0) / 4.0); 1040 printw("You have discovered %.0f gems!", gems); 1041 } else { 1042 /* gold */ 1043 gold = ROLL(treasuretype * 10.0, treasuretype 1044 * treasuretype * 10.0 * (Circle - 1.0)); 1045 printw("You have found %.0f gold pieces.", gold); 1046 } 1047 1048 addstr(" Do you want to pick them up ? "); 1049 ch = getanswer("NY", FALSE); 1050 addstr("\n\n"); 1051 1052 if (ch == 'Y') { 1053 if (drandom() < treasuretype / 35.0 + 0.04) { 1054 /* cursed */ 1055 addstr("They were cursed!\n"); 1056 cursedtreasure(); 1057 } else 1058 collecttaxes(gold, gems); 1059 } 1060 1061 return; 1062 } else { 1063 /* other treasures */ 1064 addstr("You have found some treasure. Do you want to inspect it ? "); 1065 ch = getanswer("NY", FALSE); 1066 addstr("\n\n"); 1067 1068 if (ch != 'Y') 1069 return; 1070 else if (drandom() < 0.08 && Curmonster.m_treasuretype != 4) { 1071 addstr("It was cursed!\n"); 1072 cursedtreasure(); 1073 return; 1074 } else 1075 switch (Curmonster.m_treasuretype) { 1076 case 1: /* treasure type 1 */ 1077 switch (whichtreasure) { 1078 case 1: 1079 addstr("You've discovered a power booster!\n"); 1080 Player.p_mana += ROLL(Circle * 4.0, Circle * 30.0); 1081 break; 1082 1083 case 2: 1084 addstr("You have encountered a druid.\n"); 1085 Player.p_experience += 1086 ROLL(0.0, 2000.0 + Circle * 400.0); 1087 break; 1088 1089 case 3: 1090 addstr("You have found a holy orb.\n"); 1091 Player.p_sin = MAX(0.0, Player.p_sin - 0.25); 1092 break; 1093 } 1094 break; 1095 /* end treasure type 1 */ 1096 1097 case 2: /* treasure type 2 */ 1098 switch (whichtreasure) { 1099 case 1: 1100 addstr("You have found an amulet.\n"); 1101 ++Player.p_amulets; 1102 break; 1103 1104 case 2: 1105 addstr("You've found some holy water!\n"); 1106 ++Player.p_holywater; 1107 break; 1108 1109 case 3: 1110 addstr("You've met a hermit!\n"); 1111 Player.p_sin *= 0.75; 1112 Player.p_mana += 12.0 * Circle; 1113 break; 1114 } 1115 break; 1116 /* end treasure type 2 */ 1117 1118 case 3: /* treasure type 3 */ 1119 switch (whichtreasure) { 1120 case 1: 1121 dtemp = ROLL(7.0, 30.0 + Circle / 10.0); 1122 printw("You've found a +%.0f shield!\n", dtemp); 1123 if (dtemp >= Player.p_shield) 1124 Player.p_shield = dtemp; 1125 else 1126 SOMEBETTER(); 1127 break; 1128 1129 case 2: 1130 addstr("You have rescued a virgin. Will you be honorable ? "); 1131 ch = getanswer("NY", FALSE); 1132 addstr("\n\n"); 1133 if (ch == 'Y') 1134 Player.p_virgin = TRUE; 1135 else { 1136 Player.p_experience += 2000.0 * Circle; 1137 ++Player.p_sin; 1138 } 1139 break; 1140 1141 case 3: 1142 addstr("You've discovered some athelas!\n"); 1143 --Player.p_poison; 1144 break; 1145 } 1146 break; 1147 /* end treasure type 3 */ 1148 1149 case 4: /* treasure type 4 */ 1150 addstr("You've found a scroll. Will you read it ? "); 1151 ch = getanswer("NY", FALSE); 1152 addstr("\n\n"); 1153 1154 if (ch == 'Y') 1155 switch ((int)ROLL(1, 6)) { 1156 case 1: 1157 addstr("It throws up a shield for you next monster.\n"); 1158 getyx(stdscr, whichtreasure, ch); 1159 more(whichtreasure); 1160 Shield = 1161 (Player.p_maxenergy + Player.p_energy) * 5.5 + Circle * 50.0; 1162 Whichmonster = pickmonster(); 1163 longjmp(Fightenv, 0); 1164 /*NOTREACHED*/ 1165 1166 case 2: 1167 addstr("It makes you invisible for you next monster.\n"); 1168 getyx(stdscr, whichtreasure, ch); 1169 more(whichtreasure); 1170 Player.p_speed = 1e6; 1171 Whichmonster = pickmonster(); 1172 longjmp(Fightenv, 0); 1173 /* NOTREACHED */ 1174 1175 case 3: 1176 addstr("It increases your strength ten fold to fight your next monster.\n"); 1177 getyx(stdscr, whichtreasure, ch); 1178 more(whichtreasure); 1179 Player.p_might *= 10.0; 1180 Whichmonster = pickmonster(); 1181 longjmp(Fightenv, 0); 1182 /* NOTREACHED */ 1183 1184 case 4: 1185 addstr("It is a general knowledge scroll.\n"); 1186 Player.p_brains += ROLL(2.0, Circle); 1187 Player.p_magiclvl += ROLL(1.0, Circle / 2.0); 1188 break; 1189 1190 case 5: 1191 addstr("It tells you how to pick your next monster.\n"); 1192 addstr("Which monster do you want [0-99] ? "); 1193 Whichmonster = (int)infloat(); 1194 Whichmonster = MIN(99, MAX(0, Whichmonster)); 1195 longjmp(Fightenv, 0); 1196 1197 case 6: 1198 addstr("It was cursed!\n"); 1199 cursedtreasure(); 1200 break; 1201 } 1202 break; 1203 /* end treasure type 4 */ 1204 1205 case 5: /* treasure type 5 */ 1206 switch (whichtreasure) { 1207 case 1: 1208 dtemp = ROLL(Circle / 4.0 + 5.0, Circle / 2.0 + 9.0); 1209 printw("You've discovered a +%.0f dagger.\n", dtemp); 1210 if (dtemp >= Player.p_sword) 1211 Player.p_sword = dtemp; 1212 else 1213 SOMEBETTER(); 1214 break; 1215 1216 case 2: 1217 dtemp = ROLL(7.5 + Circle * 3.0, Circle * 2.0 + 160.0); 1218 printw("You have found some +%.0f armour!\n", dtemp); 1219 if (dtemp >= Player.p_shield) 1220 Player.p_shield = dtemp; 1221 else 1222 SOMEBETTER(); 1223 break; 1224 1225 case 3: 1226 addstr("You've found a tablet.\n"); 1227 Player.p_brains += 4.5 * Circle; 1228 break; 1229 } 1230 break; 1231 /* end treasure type 5 */ 1232 1233 case 6: /* treasure type 6 */ 1234 switch (whichtreasure) { 1235 case 1: 1236 addstr("You've found a priest.\n"); 1237 Player.p_energy = Player.p_maxenergy + Player.p_shield; 1238 Player.p_sin /= 2.0; 1239 Player.p_mana += 24.0 * Circle; 1240 Player.p_brains += Circle; 1241 break; 1242 1243 case 2: 1244 addstr("You have come upon Robin Hood!\n"); 1245 Player.p_shield += Circle * 2.0; 1246 Player.p_strength += Circle / 2.5 + 1.0; 1247 break; 1248 1249 case 3: 1250 dtemp = ROLL(2.0 + Circle / 4.0, Circle / 1.2 + 10.0); 1251 printw("You have found a +%.0f axe!\n", dtemp); 1252 if (dtemp >= Player.p_sword) 1253 Player.p_sword = dtemp; 1254 else 1255 SOMEBETTER(); 1256 break; 1257 } 1258 break; 1259 /* end treasure type 6 */ 1260 1261 case 7: /* treasure type 7 */ 1262 switch (whichtreasure) { 1263 case 1: 1264 addstr("You've discovered a charm!\n"); 1265 ++Player.p_charms; 1266 break; 1267 1268 case 2: 1269 addstr("You have encountered Merlyn!\n"); 1270 Player.p_brains += Circle + 5.0; 1271 Player.p_magiclvl += Circle / 3.0 + 5.0; 1272 Player.p_mana += Circle * 10.0; 1273 break; 1274 1275 case 3: 1276 dtemp = ROLL(5.0 + Circle / 3.0, Circle / 1.5 + 20.0); 1277 printw("You have found a +%.0f war hammer!\n", dtemp); 1278 if (dtemp >= Player.p_sword) 1279 Player.p_sword = dtemp; 1280 else 1281 SOMEBETTER(); 1282 break; 1283 } 1284 break; 1285 /* end treasure type 7 */ 1286 1287 case 8: /* treasure type 8 */ 1288 switch (whichtreasure) { 1289 case 1: 1290 addstr("You have found a healing potion.\n"); 1291 Player.p_poison = MIN(-2.0, Player.p_poison - 2.0); 1292 break; 1293 1294 case 2: 1295 addstr("You have discovered a transporter. Do you wish to go anywhere ? "); 1296 ch = getanswer("NY", FALSE); 1297 addstr("\n\n"); 1298 if (ch == 'Y') { 1299 double x, y; 1300 1301 addstr("X Y Coordinates ? "); 1302 getstring(Databuf, SZ_DATABUF); 1303 sscanf(Databuf, "%lf %lf", &x, &y); 1304 altercoordinates(x, y, A_FORCED); 1305 } 1306 break; 1307 1308 case 3: 1309 dtemp = ROLL(10.0 + Circle / 1.2, Circle * 3.0 + 30.0); 1310 printw("You've found a +%.0f sword!\n", dtemp); 1311 if (dtemp >= Player.p_sword) 1312 Player.p_sword = dtemp; 1313 else 1314 SOMEBETTER(); 1315 break; 1316 } 1317 break; 1318 /* end treasure type 8 */ 1319 1320 case 10: 1321 case 11: 1322 case 12: 1323 case 13: /* treasure types 10 - 13 */ 1324 if (drandom() < 0.33) { 1325 if (Curmonster.m_treasuretype == 10) { 1326 addstr("You've found a pair of elven boots!\n"); 1327 Player.p_quickness += 2.0; 1328 break; 1329 } else if (Curmonster.m_treasuretype == 11 && 1330 !Player.p_palantir) { 1331 addstr("You've acquired Saruman's palantir.\n"); 1332 Player.p_palantir = TRUE; 1333 break; 1334 } else if (Player.p_ring.ring_type == R_NONE && 1335 Player.p_specialtype < SC_COUNCIL && 1336 (Curmonster.m_treasuretype == 12 || 1337 Curmonster.m_treasuretype == 13)) { 1338 /* roll up a ring */ 1339 if (drandom() < 0.8) { 1340 /* regular rings */ 1341 if (Curmonster.m_treasuretype == 12) { 1342 whichtreasure = R_NAZREG; 1343 temp = 35; 1344 } else { 1345 whichtreasure = R_DLREG; 1346 temp = 0; 1347 } 1348 } else { 1349 /* bad rings */ 1350 whichtreasure = R_BAD; 1351 temp = 15 + Statptr->c_ringduration + (int)ROLL(0, 5); 1352 } 1353 1354 addstr("You've discovered a ring. Will you pick it up ? "); 1355 ch = getanswer("NY", FALSE); 1356 addstr("\n\n"); 1357 1358 if (ch == 'Y') { 1359 Player.p_ring.ring_type = whichtreasure; 1360 Player.p_ring.ring_duration = temp; 1361 } 1362 1363 break; 1364 } 1365 } 1366 /* end treasure types 10 - 13 */ 1367 /* fall through to treasure type 9 if no treasure from above */ 1368 1369 case 9: /* treasure type 9 */ 1370 switch (whichtreasure) { 1371 case 1: 1372 if (Player.p_level <= 1000.0 && 1373 Player.p_crowns <= 3 && 1374 Player.p_level >= 10.0) { 1375 addstr("You have found a golden crown!\n"); 1376 ++Player.p_crowns; 1377 break; 1378 } 1379 /* fall through otherwise */ 1380 1381 case 2: 1382 addstr("You've been blessed!\n"); 1383 Player.p_blessing = TRUE; 1384 Player.p_sin /= 3.0; 1385 Player.p_energy = Player.p_maxenergy + Player.p_shield; 1386 Player.p_mana += 100.0 * Circle; 1387 break; 1388 1389 case 3: 1390 dtemp = ROLL(1.0, Circle / 5.0 + 5.0); 1391 dtemp = MIN(dtemp, 99.0); 1392 printw("You have discovered some +%.0f quicksilver!\n", dtemp); 1393 if (dtemp >= Player.p_quksilver) 1394 Player.p_quksilver = dtemp; 1395 else 1396 SOMEBETTER(); 1397 break; 1398 } 1399 break; 1400 /* end treasure type 9 */ 1401 } 1402 } 1403 } 1404 1405 /* 1406 * FUNCTION: take care of cursed treasure 1407 * 1408 * GLOBAL INPUTS: Player, *stdscr 1409 * 1410 * GLOBAL OUTPUTS: Player 1411 * 1412 * DESCRIPTION: 1413 * Handle cursed treasure. Look for amulets and charms to save 1414 * the player from the curse. 1415 */ 1416 1417 void 1418 cursedtreasure(void) 1419 { 1420 if (Player.p_charms > 0) { 1421 addstr("But your charm saved you!\n"); 1422 --Player.p_charms; 1423 } else if (Player.p_amulets > 0) { 1424 addstr("But your amulet saved you!\n"); 1425 --Player.p_amulets; 1426 } else { 1427 Player.p_energy = (Player.p_maxenergy + Player.p_shield) / 10.0; 1428 Player.p_poison += 0.25; 1429 } 1430 } 1431 1432 /* 1433 * FUNCTION: scramble some selected statistics 1434 * 1435 * GLOBAL INPUTS: Player 1436 * 1437 * GLOBAL OUTPUTS: Player 1438 * 1439 * DESCRIPTION: 1440 * Swap a few player statistics randomly. 1441 */ 1442 1443 void 1444 scramblestats(void) 1445 { 1446 double dbuf[6]; /* to put statistic in */ 1447 double dtemp1, dtemp2; /* for swapping values */ 1448 int first, second; /* indices for swapping */ 1449 double *dptr; /* pointer for filling and emptying buf[] */ 1450 1451 /* fill buffer */ 1452 dptr = &dbuf[0]; 1453 *dptr++ = Player.p_strength; 1454 *dptr++ = Player.p_mana; 1455 *dptr++ = Player.p_brains; 1456 *dptr++ = Player.p_magiclvl; 1457 *dptr++ = Player.p_energy; 1458 *dptr = Player.p_sin; 1459 1460 /* pick values to swap */ 1461 first = (int)ROLL(0, 5); 1462 second = (int)ROLL(0, 5); 1463 1464 /* swap values */ 1465 dptr = &dbuf[0]; 1466 dtemp1 = dptr[first]; 1467 /* this expression is split to prevent a compiler loop on some compilers */ 1468 dtemp2 = dptr[second]; 1469 dptr[first] = dtemp2; 1470 dptr[second] = dtemp1; 1471 1472 /* empty buffer */ 1473 Player.p_strength = *dptr++; 1474 Player.p_mana = *dptr++; 1475 Player.p_brains = *dptr++; 1476 Player.p_magiclvl = *dptr++; 1477 Player.p_energy = *dptr++; 1478 Player.p_sin = *dptr; 1479 } 1480