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