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