1: /* 2: * fight.c Phantasia monster fighting routine 3: * 4: * 1.1 (2.11BSD) 1996/10/26 5: */ 6: 7: /* 8: * The code exists here for fight to the finish. Simply add code to 9: * set 'fgttofin = TRUE' as an option. Everything else is here. 10: */ 11: #include "phant.h" 12: 13: void fight(stat,particular) /* monster fighting routine */ 14: reg struct stats *stat; 15: int particular; 16: { 17: bool fghttofin = FALSE, luckout = FALSE; 18: char aline[80]; 19: double monhit, mdamage, sdamage, monspd, maxspd, inflict, monstr, temp, shield; 20: int ch; 21: reg int whichm, size, hwmany, lines; 22: struct mstats monster; 23: 24: fghting = changed = TRUE; 25: shield = 0.0; 26: if (setjmp(fightenv) == 2) 27: shield = roll(100 + (stat->mxn + stat->shd)*6.2,3000); 28: hwmany = 0; 29: size = (valhala) ? stat->lvl/5 : circ(stat->x,stat->y); 30: if (particular >= 0) 31: whichm = particular; 32: else if (marsh) 33: whichm = roll(0,15); 34: else if (size > 24) 35: whichm = roll(14,86); 36: else if (size > 15) 37: whichm = roll(0,50) + roll(14,37); 38: else if (size > 8) 39: whichm = roll(0,50) + roll(14,26); 40: else if (size > 3) 41: whichm = roll(14,50); 42: else 43: whichm = roll(14,25); 44: 45: CALL: move(3,0); 46: clrtobot(); 47: move(5,0); 48: lines = 6; 49: callmonster(whichm,size,&monster); 50: if (stat->blind) 51: strcpy(monster.name,"a monster"); 52: ++hwmany; 53: if (monster.typ == 1) /* unicorn */ 54: if (stat->vrg) 55: { 56: printw("You just subdued %s, thanx to the virgin.",monster.name); 57: stat->vrg = FALSE; 58: goto FINISH; 59: } 60: else 61: { 62: printw("You just saw %s running away!",monster.name); 63: goto LEAVE; 64: } 65: if (monster.typ == 2 && stat->typ > 20) 66: { 67: strcpy(monster.name,"Morgoth"); 68: monster.str = rnd()*(stat->mxn + stat->shd)/1.4 + rnd()*(stat->mxn + stat->shd)/1.5; 69: monster.brn = stat->brn; 70: monster.hit = stat->str*30; 71: monster.typ = 23; 72: monster.spd = speed*1.1 + speed*(stat->typ == 90); 73: monster.flk = monster.trs = monster.exp = 0; 74: mvprintw(4,0,"You've encountered %s, Bane of the Council and Valar.",monster.name); 75: } 76: fghttofin = luckout = FALSE; 77: monstr = monster.str; 78: monhit = monster.hit; 79: mdamage = sdamage = 0; 80: monspd = maxspd = monster.spd; 81: *monster.name = toupper(*monster.name); 82: 83: TOP: mvprintw(5,0,"You are being attacked by %s, EXP: %.0f (Size: %d)",monster.name,monster.exp,size); 84: printstats(stat); 85: mvprintw(1,26,"%20.0f",stat->nrg + shield); 86: if (monster.typ == 4 && stat->bls && stat->chm) 87: { 88: mvprintw(6,0,"You just overpowered %s!",monster.name); 89: lines = 7; 90: stat->bls = FALSE; 91: --stat->chm; 92: goto FINISH; 93: } 94: monster.spd = min(monster.spd + 1,maxspd); 95: if (rnd()*monster.spd > rnd()*speed && monster.typ != 4 && monster.typ != 16) 96: { 97: if (monster.typ) 98: switch (monster.typ) /* do special things */ 99: { 100: case 5: /* Leanan-Sidhe */ 101: if (rnd() > 0.25) 102: goto NORMALHIT; 103: inflict = roll(1,(size - 1)/2); 104: inflict = min(stat->str,inflict); 105: mvprintw(lines++,0,"%s sapped %0.f of your strength!",monster.name,inflict); 106: stat->str -= inflict; 107: strength -= inflict; 108: break; 109: case 6: /* Saruman */ 110: if (stat->pal) 111: { 112: mvprintw(lines++,0,"Wormtongue stole your palantir!"); 113: stat->pal = FALSE; 114: } 115: else if (rnd() > 0.2) 116: goto NORMALHIT; 117: else if (rnd() > 0.5) 118: { 119: mvprintw(lines++,0,"%s transformed your gems into gold!",monster.name); 120: stat->gld += stat->gem; 121: stat->gem = 0.0; 122: } 123: else 124: { 125: mvprintw(lines++,0,"%s scrambled your stats!",monster.name); 126: scramble(stat); 127: } 128: break; 129: case 7: /* Thaumaturgist */ 130: if (rnd() > 0.15) 131: goto NORMALHIT; 132: mvprintw(lines++,0,"%s transported you!",monster.name); 133: stat->x += sgn(stat->x)*roll(50*size,250*size); 134: stat->y += sgn(stat->y)*roll(50*size,250*size); 135: goto LEAVE; 136: case 8: /* Balrog */ 137: inflict = roll(10,monster.str); 138: inflict = min(stat->exp,inflict); 139: mvprintw(lines++,0,"%s took away %0.f experience points.",monster.name,inflict); 140: stat->exp -= inflict; 141: break; 142: case 9: /* Vortex */ 143: if (rnd() > 0.2) 144: goto NORMALHIT; 145: inflict = roll(0,7.5*size); 146: inflict = min(stat->man,floor(inflict)); 147: mvprintw(lines++,0,"%s sucked up %.0f of your manna!",monster.name,inflict); 148: stat->man -= inflict; 149: break; 150: case 10: /* Nazgul */ 151: if (rnd() > 0.3) 152: goto NORMALHIT; 153: if (stat->rng.type && stat->rng.type < 10) 154: { 155: mvaddstr(lines++,0,"Will you relinguish your ring ? "); 156: ch = rgetch(); 157: if (toupper(ch) == 'Y') 158: { 159: stat->rng.type = NONE; 160: goto LEAVE; 161: } 162: } 163: mvprintw(lines++,0,"%s neutralized 1/5 of your brain!",monster.name); 164: stat->brn *= 0.8; 165: break; 166: case 11: /* Tiamat */ 167: if (rnd() > 0.6) 168: goto NORMALHIT; 169: mvprintw(lines++,0,"%s took half your gold and gems and flew off.",monster.name); 170: stat->gld = floor(stat->gld/2); 171: stat->gem = floor(stat->gem/2); 172: goto LEAVE; 173: case 12: /* Kobold */ 174: if (rnd() >.7) 175: goto NORMALHIT; 176: mvprintw(lines++,0,"%s stole one gold piece and ran away.",monster.name); 177: stat->gld = max(0,stat->gld-1); 178: goto LEAVE; 179: case 13: /* Shelob */ 180: if (rnd() > 0.5) 181: goto NORMALHIT; 182: mvprintw(lines++,0,"%s has bitten and poisoned you!",monster.name); 183: ++stat->psn; 184: break; 185: case 14: /* Faeries */ 186: if (!stat->hw) 187: goto NORMALHIT; 188: mvprintw(lines++,0,"Your holy water killed it!"); 189: --stat->hw; 190: goto FINISH; 191: case 15: /* Lamprey */ 192: if (rnd() > 0.7) 193: goto NORMALHIT; 194: mvprintw(lines++,0,"%s bit and poisoned you!",monster.name); 195: stat->psn += 0.25; 196: break; 197: case 17: /* Bonnacon */ 198: if (rnd() > 0.1) 199: goto NORMALHIT; 200: mvprintw(lines++,0,"%s farted and scampered off.",monster.name); 201: stat->nrg /= 2; 202: goto LEAVE; 203: case 18: /* Smeagol */ 204: if (rnd() > 0.5 || !stat->rng.type) 205: goto NORMALHIT; 206: mvprintw(lines++,0,"%s tried to steal your ring, ",monster.name); 207: if (rnd() > 0.1) 208: addstr("but was unsuccessful."); 209: else 210: { 211: addstr("and ran away with it!"); 212: stat->rng.type = NONE; 213: goto LEAVE; 214: } 215: break; 216: case 19: /* Succubus */ 217: if (rnd() > 0.3) 218: goto NORMALHIT; 219: inflict = roll(15,size*10); 220: inflict = min(inflict,stat->nrg); 221: mvprintw(lines++,0,"%s sapped %0.f of your energy.",monster.name,inflict); 222: stat->nrg -= inflict; 223: break; 224: case 20: /* Cerberus */ 225: if (rnd() > 0.25) 226: goto NORMALHIT; 227: mvprintw(lines++,0,"%s took all your metal treasures!",monster.name); 228: stat->swd = stat->shd =stat->gld = stat->crn = 0; 229: goto LEAVE; 230: case 21: /* Ungoliant */ 231: if (rnd() > 0.1) 232: goto NORMALHIT; 233: mvprintw(lines++,0,"%s poisoned you, and took one quik.",monster.name); 234: stat->psn += 5; 235: --stat->quk; 236: break; 237: case 22: /* Jabberwock */ 238: if (rnd() > 0.1) 239: goto NORMALHIT; 240: mvprintw(lines++,0,"%s flew away, and left you to contend with one of its friends.",monster.name); 241: whichm = 55 + 22*(rnd() > 0.5); 242: goto CALL; 243: case 24: /* Troll */ 244: if (rnd() > 0.5) 245: goto NORMALHIT; 246: mvprintw(lines++,0,"%s partially regenerated his energy.!",monster.name); 247: monster.hit += floor((monhit*size - monster.hit)/2); 248: monster.str = monstr; 249: mdamage = sdamage = 0; 250: maxspd = monspd; 251: break; 252: case 25: /* wraith */ 253: if (rnd() > 0.3 || stat->blind) 254: goto NORMALHIT; 255: mvprintw(lines++,0,"%s blindeed you!",monster.name); 256: stat->blind = TRUE; 257: break; 258: default: 259: goto NORMALHIT; 260: } 261: else 262: NORMALHIT: { 263: inflict = rnd()*monster.str + 0.5; 264: mvprintw(lines++,0,"%s hit you %.0f times!",monster.name,inflict); 265: SPECIALHIT: if ((shield -= inflict) < 0) 266: { 267: stat->nrg += shield; 268: shield = 0; 269: } 270: } 271: } 272: else 273: { 274: if (fghttofin) 275: goto MELEE; 276: mvaddstr(3,0,"1:Melee 2:Skirmish 3:Evade 4:Spell 5:Nick "); 277: if (!luckout) 278: if (monster.typ == 23) 279: addstr("6:Ally "); 280: else 281: addstr("6:Luckout "); 282: if (stat->rng.type > 0) 283: addstr("7:Use Ring "); 284: else 285: clrtoeol(); 286: ch = gch(stat->rng.type); 287: move(lines = 6,0); 288: clrtobot(); 289: switch (ch) 290: { 291: default: 292: case '1': /* melee */ 293: MELEE: inflict = roll(strength/2 + 5,1.3*strength) + (stat->rng.type < 0 ? strength : 0); 294: mdamage += inflict; 295: monster.str = monstr - mdamage/monhit*monstr/4; 296: goto HITMONSTER; 297: case '2': /* skirmish */ 298: inflict = roll(strength/3 + 3,1.1*strength) + (stat->rng.type < 0 ? strength : 0); 299: sdamage += inflict; 300: maxspd = monspd - sdamage/monhit*monspd/4; 301: goto HITMONSTER; 302: case '3': /* evade */ 303: if ((monster.typ == 4 || monster.typ == 16 304: || rnd()*speed*stat->brn > rnd()*monster.spd*monster.brn) 305: && (monster.typ != 23)) 306: { 307: mvaddstr(lines++,0,"You got away!"); 308: stat->x += roll(-2,5); 309: stat->y += roll(-2,5); 310: goto LEAVE; 311: } 312: else 313: mvprintw(lines++,0,"%s is still after you!",monster.name); 314: break; 315: case '4': /* spell */ 316: lines = 7; 317: mvaddstr(3,0,"\n\n"); 318: mvaddstr(3,0,"1:All or Nothing"); 319: if (stat->mag >= 3) 320: mvaddstr(3,18,"2:Magic Bolt"); 321: if (stat->mag >= 7) 322: mvaddstr(3,32,"3:Force Field"); 323: if (stat->mag >= 10) 324: mvaddstr(3,47,"4:Transform"); 325: if(stat->mag >= 15) 326: mvaddstr(3,60,"5:Increase Might\n"); 327: if (stat->mag >= 20) 328: mvaddstr(4,0,"6:Invisibility"); 329: if (stat->mag >= 25) 330: mvaddstr(4,18,"7:Transport"); 331: if (stat->mag >= 30) 332: mvaddstr(4,32,"8:Paralyze"); 333: if (stat->typ > 20) 334: mvaddstr(4,52,"9:Specify"); 335: mvaddstr(6,0,"Spell ? "); 336: ch = rgetch(); 337: mvaddstr(3,0,"\n\n"); 338: if (monster.typ == 23 && ch != '4') 339: illspell(); 340: else 341: switch (ch) 342: { 343: case '1': /* all or nothing */ 344: { 345: inflict = (rnd() < 0.25) ? (monster.hit*1.0001 + 1) : 0; 346: if (monster.typ == 4) 347: inflict *= .9; 348: if (stat->man) 349: --stat->man; 350: maxspd *= 2; 351: monspd *= 2; 352: monster.spd = max(1,monster.spd * 2); 353: monstr = monster.str *= 2; 354: goto HITMONSTER; 355: } 356: case '2': /* magic bolt */ 357: if (stat->mag < 3) 358: illspell(); 359: else 360: { 361: do 362: { 363: mvaddstr(6,0,"How much manna for bolt? "); 364: getstring(aline,80); 365: sscanf(aline,"%F",&temp); 366: } 367: while (temp < 0 || temp > stat->man); 368: stat->man -= floor(temp); 369: inflict = temp*roll(10,sqrt(stat->mag/3.0 + 1.0)); 370: mvaddstr(6,0,"Magic Bolt fired!\n"); 371: if (monster.typ == 4) 372: inflict = 0.0; 373: goto HITMONSTER; 374: } 375: case '5': /* increase might */ 376: { 377: if (stat->mag < 15) 378: illspell(); 379: else if (stat->man < 55) 380: nomanna(); 381: else 382: { 383: stat->man -= 55; 384: strength += (1.2*(stat->str+stat->swd)+5-strength)/2; 385: mvprintw(6,0,"New strength: %.0f\n",strength); 386: } 387: break; 388: } 389: case '3': /* force field */ 390: { 391: if (stat->mag < 7) 392: illspell(); 393: else if (stat->man < 20) 394: nomanna(); 395: else 396: { 397: shield = (stat->mxn + stat->shd)*4.2 + 45; 398: stat->man -= 20; 399: mvaddstr(6,0,"Force Field up.\n"); 400: } 401: break; 402: } 403: case '4': /* transform */ 404: { 405: if (stat->mag < 10) 406: illspell(); 407: else if (stat->man < 35) 408: nomanna(); 409: else 410: { 411: stat->man -= 35; 412: whichm = roll(0,100); 413: goto CALL; 414: } 415: break; 416: } 417: case '6': /* invisible */ 418: { 419: if (stat->mag < 20) 420: illspell(); 421: else if (stat->man < 45) 422: nomanna(); 423: else 424: { 425: stat->man -= 45; 426: speed += (1.2*(stat->quk+stat->quks)+5-speed)/2; 427: mvprintw(6,0,"New quik : %.0f\n",speed); 428: } 429: break; 430: } 431: case '7': /* transport */ 432: { 433: if (stat->mag < 25) 434: illspell(); 435: else if (stat->man < 50) 436: nomanna(); 437: else 438: { 439: stat->man -= 50; 440: if (stat->brn + stat->mag < monster.exp/300*rnd()) 441: { 442: mvaddstr(6,0,"Transport backfired!\n"); 443: stat->x += (250*size*rnd() + 50*size)*sgn(stat->x); 444: stat->y += (250*size*rnd() + 50*size)*sgn(stat->y); 445: goto LEAVE; 446: } 447: else 448: { 449: mvprintw(6,0,"%s is transported.\n",monster.name); 450: monster.trs *= (rnd() > 0.3); 451: goto FINISH; 452: } 453: } 454: break; 455: } 456: case '8': /* paralyze */ 457: { 458: if (stat->mag < 30) 459: illspell(); 460: else if (stat->man < 60) 461: nomanna(); 462: else 463: { 464: stat->man -= 60; 465: if (stat->mag > monster.exp/1000*rnd()) 466: { 467: mvprintw(6,0,"%s is held.\n",monster.name); 468: monster.spd = -2; 469: } 470: else 471: mvaddstr(6,0,"Monster unaffected.\n"); 472: } 473: break; 474: } 475: case '9': /* specify */ 476: { 477: if (stat->typ < 20) 478: illspell(); 479: else if (stat->man < 1000) 480: nomanna(); 481: else 482: { 483: mvaddstr(6,0,"Which monster do you want [0-99] ? "); 484: whichm = inflt(); 485: whichm = max(0,min(99,whichm)); 486: stat->man -= 1000; 487: goto CALL; 488: } 489: break; 490: } 491: } 492: break; 493: case '5': 494: inflict = 1 + stat->swd; 495: stat->exp += floor(monster.exp/10); 496: monster.exp *= 0.92; 497: maxspd += 2; 498: monster.spd = (monster.spd < 0) ? 0 : monster.spd + 2; 499: if (monster.typ == 4) 500: { 501: mvprintw(lines++,0,"You hit %s %.0f times, and made him mad!",monster.name,inflict); 502: stat->quk /= 2; 503: stat->x += sgn(stat->x)*roll(50*size,250*size); 504: stat->y += sgn(stat->y)*roll(50*size,250*size); 505: stat->y += (250*size*rnd() + 50*size)*sgn(stat->y); 506: goto LEAVE; 507: } 508: else 509: goto HITMONSTER; 510: case '6': /* luckout */ 511: if (luckout) 512: mvaddstr(lines++,0,"You already tried that."); 513: else 514: if (monster.typ == 23) 515: if (rnd() < stat->sin/100) { 516: mvprintw(lines++,0,"%s accepted!",monster.name); 517: goto LEAVE; 518: } 519: else 520: { 521: luckout = TRUE; 522: mvaddstr(lines++,0,"Nope, he's not interested."); 523: } 524: else 525: if ((rnd() + .333)*stat->brn < (rnd() + .333)*monster.brn) 526: { 527: luckout = TRUE; 528: mvprintw(lines++,0,"You blew it, %s.",stat->name); 529: } 530: else 531: { 532: mvaddstr(lines++,0,"You made it!"); 533: goto FINISH; 534: } 535: break; 536: case '\014': /* clear screen */ 537: clear(); 538: break; 539: case '7': /* use ring */ 540: if (stat->rng.type > 0) 541: { 542: mvaddstr(lines++,0,"Now using ring."); 543: stat->rng.type = -stat->rng.type; 544: if (abs(stat->rng.type) != DLREG) 545: --stat->rng.duration; 546: goto NORMALHIT; 547: } 548: break; 549: } 550: goto BOT; 551: HITMONSTER: { 552: inflict = floor(inflict); 553: mvprintw(lines++,0,"You hit %s %.0f times!",monster.name,inflict); 554: if ((monster.hit -= inflict) >0) 555: switch (monster.typ) 556: { 557: case 4: /* dark lord */ 558: inflict = stat->nrg + shield +1; 559: goto SPECIALHIT; 560: case 16: /* shrieker */ 561: mvaddstr(lines++,0,"Shreeeek!! You scared it, and it called one of its friends."); 562: paws(lines); 563: whichm = roll(70,30); 564: goto CALL; 565: } 566: else 567: { 568: if (monster.typ == 23) /* morgoth */ 569: mvaddstr(lines++,0,"You have defeated Morgoth, but he may return. . ."); 570: else 571: mvprintw(lines++,0,"You killed it. Good work, %s.",stat->name); 572: goto FINISH; 573: } 574: } 575: } 576: BOT: refresh(); 577: if (lines == 23) 578: { 579: paws(23); 580: move(lines = 6,0); 581: clrtobot(); 582: } 583: if (stat->nrg <= 0) 584: { 585: paws(lines); 586: death(stat); 587: goto LEAVE; 588: } 589: goto TOP; 590: FINISH: stat->exp += monster.exp; 591: if (rnd() < monster.flk/100.0) /* flock monster */ 592: { 593: paws(lines); 594: fghttofin = FALSE; 595: goto CALL; 596: } 597: else if (size > 1 && monster.trs && rnd() > pow(0.6,(double) (hwmany/3 + size/3))) /* this takes # of flocks and size into account */ 598: { 599: paws(lines); 600: treasure(stat,monster.trs,size); 601: } 602: LEAVE: stat->rng.type = abs(stat->rng.type); 603: paws(lines+3); 604: move(4,0); 605: clrtobot(); 606: fghting = FALSE; 607: }