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