|
|
1.1 ! root 1: /* ! 2: * All the fighting gets done here ! 3: * ! 4: * @(#)fight.c 3.28 (Berkeley) 6/15/81 ! 5: */ ! 6: ! 7: #include <curses.h> ! 8: #include <ctype.h> ! 9: #include "rogue.h" ! 10: ! 11: long e_levels[] = { ! 12: 10L,20L,40L,80L,160L,320L,640L,1280L,2560L,5120L,10240L,20480L, ! 13: 40920L, 81920L, 163840L, 327680L, 655360L, 1310720L, 2621440L, 0L }; ! 14: ! 15: /* ! 16: * fight: ! 17: * The player attacks the monster. ! 18: */ ! 19: ! 20: fight(mp, mn, weap, thrown) ! 21: register coord *mp; ! 22: char mn; ! 23: struct object *weap; ! 24: bool thrown; ! 25: { ! 26: register struct thing *tp; ! 27: register struct linked_list *item; ! 28: register bool did_hit = TRUE; ! 29: ! 30: /* ! 31: * Find the monster we want to fight ! 32: */ ! 33: if ((item = find_mons(mp->y, mp->x)) == NULL) ! 34: debug("Fight what @ %d,%d", mp->y, mp->x); ! 35: tp = (struct thing *) ldata(item); ! 36: /* ! 37: * Since we are fighting, things are not quiet so no healing takes ! 38: * place. ! 39: */ ! 40: quiet = 0; ! 41: runto(mp, &hero); ! 42: /* ! 43: * Let him know it was really a mimic (if it was one). ! 44: */ ! 45: if (tp->t_type == 'M' && tp->t_disguise != 'M' && off(player, ISBLIND)) ! 46: { ! 47: msg("Wait! That's a mimic!"); ! 48: tp->t_disguise = 'M'; ! 49: did_hit = thrown; ! 50: } ! 51: if (did_hit) ! 52: { ! 53: register char *mname; ! 54: ! 55: did_hit = FALSE; ! 56: if (on(player, ISBLIND)) ! 57: mname = "it"; ! 58: else ! 59: mname = monsters[mn-'A'].m_name; ! 60: if (roll_em(&pstats, &tp->t_stats, weap, thrown)) ! 61: { ! 62: did_hit = TRUE; ! 63: if (thrown) ! 64: thunk(weap, mname); ! 65: else ! 66: hit(NULL, mname); ! 67: if (on(player, CANHUH)) ! 68: { ! 69: msg("Your hands stop glowing red"); ! 70: msg("The %s appears confused.", mname); ! 71: tp->t_flags |= ISHUH; ! 72: player.t_flags &= ~CANHUH; ! 73: } ! 74: if (tp->t_stats.s_hpt <= 0) ! 75: killed(item, TRUE); ! 76: } ! 77: else ! 78: if (thrown) ! 79: bounce(weap, mname); ! 80: else ! 81: miss(NULL, mname); ! 82: } ! 83: count = 0; ! 84: return did_hit; ! 85: } ! 86: ! 87: /* ! 88: * attack: ! 89: * The monster attacks the player ! 90: */ ! 91: ! 92: attack(mp) ! 93: register struct thing *mp; ! 94: { ! 95: register char *mname; ! 96: ! 97: /* ! 98: * Since this is an attack, stop running and any healing that was ! 99: * going on at the time. ! 100: */ ! 101: running = FALSE; ! 102: quiet = 0; ! 103: if (mp->t_type == 'M' && off(player, ISBLIND)) ! 104: mp->t_disguise = 'M'; ! 105: if (on(player, ISBLIND)) ! 106: mname = "it"; ! 107: else ! 108: mname = monsters[mp->t_type-'A'].m_name; ! 109: if (roll_em(&mp->t_stats, &pstats, NULL, FALSE)) ! 110: { ! 111: if (mp->t_type != 'E') ! 112: hit(mname, NULL); ! 113: if (pstats.s_hpt <= 0) ! 114: death(mp->t_type); /* Bye bye life ... */ ! 115: if (off(*mp, ISCANC)) ! 116: switch (mp->t_type) ! 117: { ! 118: when 'R': ! 119: /* ! 120: * If a rust monster hits, you lose armor ! 121: */ ! 122: if (cur_armor != NULL && cur_armor->o_ac < 9) ! 123: { ! 124: if (!terse) ! 125: msg("Your armor appears to be weaker now. Oh my!"); ! 126: else ! 127: msg("Your armor weakens"); ! 128: cur_armor->o_ac++; ! 129: } ! 130: when 'E': ! 131: /* ! 132: * The gaze of the floating eye hypnotizes you ! 133: */ ! 134: if (on(player, ISBLIND)) ! 135: break; ! 136: if (!no_command) ! 137: { ! 138: addmsg("You are transfixed"); ! 139: if (!terse) ! 140: addmsg(" by the gaze of the floating eye."); ! 141: endmsg(); ! 142: } ! 143: no_command += rnd(2)+2; ! 144: when 'A': ! 145: /* ! 146: * Ants have poisonous bites ! 147: */ ! 148: if (!save(VS_POISON)) ! 149: if (!ISWEARING(R_SUSTSTR)) ! 150: { ! 151: chg_str(-1); ! 152: if (!terse) ! 153: msg("You feel a sting in your arm and now feel weaker"); ! 154: else ! 155: msg("A sting has weakened you"); ! 156: } ! 157: else ! 158: if (!terse) ! 159: msg("A sting momentarily weakens you"); ! 160: else ! 161: msg("Sting has no effect"); ! 162: when 'W': ! 163: /* ! 164: * Wraiths might drain energy levels ! 165: */ ! 166: if (rnd(100) < 15) ! 167: { ! 168: int fewer; ! 169: ! 170: if (pstats.s_exp == 0) ! 171: death('W'); /* All levels gone */ ! 172: msg("You suddenly feel weaker."); ! 173: if (--pstats.s_lvl == 0) ! 174: { ! 175: pstats.s_exp = 0; ! 176: pstats.s_lvl = 1; ! 177: } ! 178: else ! 179: pstats.s_exp = e_levels[pstats.s_lvl-1]+1; ! 180: fewer = roll(1, 10); ! 181: pstats.s_hpt -= fewer; ! 182: max_hp -= fewer; ! 183: if (pstats.s_hpt < 1) ! 184: pstats.s_hpt = 1; ! 185: if (max_hp < 1) ! 186: death('W'); ! 187: } ! 188: when 'F': ! 189: /* ! 190: * Violet fungi stops the poor guy from moving ! 191: */ ! 192: player.t_flags |= ISHELD; ! 193: sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dd1",++fung_hit); ! 194: when 'L': ! 195: { ! 196: /* ! 197: * Leperachaun steals some gold ! 198: */ ! 199: register long lastpurse; ! 200: ! 201: lastpurse = purse; ! 202: purse -= GOLDCALC; ! 203: if (!save(VS_MAGIC)) ! 204: purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; ! 205: if (purse < 0) ! 206: purse = 0; ! 207: if (purse != lastpurse) ! 208: msg("Your purse feels lighter"); ! 209: remove(&mp->t_pos, find_mons(mp->t_pos.y, mp->t_pos.x)); ! 210: } ! 211: when 'N': ! 212: { ! 213: register struct linked_list *list, *steal; ! 214: register struct object *obj; ! 215: register int nobj; ! 216: ! 217: /* ! 218: * Nymph's steal a magic item, look through the pack ! 219: * and pick out one we like. ! 220: */ ! 221: steal = NULL; ! 222: for (nobj = 0, list = pack; list != NULL; list = next(list)) ! 223: { ! 224: obj = (struct object *) ldata(list); ! 225: if (obj != cur_armor && obj != cur_weapon && ! 226: obj != cur_ring[0] && obj != cur_ring[1] && ! 227: is_magic(obj) && rnd(++nobj) == 0) ! 228: steal = list; ! 229: } ! 230: if (steal != NULL) ! 231: { ! 232: register struct object *obj; ! 233: ! 234: obj = (struct object *) ldata(steal); ! 235: remove(&mp->t_pos, find_mons(mp->t_pos.y, mp->t_pos.x)); ! 236: if (obj->o_count > 1 && obj->o_group == 0) ! 237: { ! 238: register int oc; ! 239: ! 240: oc = obj->o_count--; ! 241: obj->o_count = 1; ! 242: msg("She stole %s!", inv_name(obj, TRUE)); ! 243: obj->o_count = oc; ! 244: } ! 245: else ! 246: { ! 247: msg("She stole %s!", inv_name(obj, TRUE)); ! 248: detach(pack, steal); ! 249: discard(steal); ! 250: } ! 251: inpack--; ! 252: } ! 253: } ! 254: otherwise: ! 255: break; ! 256: } ! 257: } ! 258: else if (mp->t_type != 'E') ! 259: { ! 260: if (mp->t_type == 'F') ! 261: { ! 262: pstats.s_hpt -= fung_hit; ! 263: if (pstats.s_hpt <= 0) ! 264: death(mp->t_type); /* Bye bye life ... */ ! 265: } ! 266: miss(mname, NULL); ! 267: } ! 268: /* ! 269: * Check to see if this is a regenerating monster and let it heal if ! 270: * it is. ! 271: */ ! 272: if (on(*mp, ISREGEN) && rnd(100) < 33) ! 273: mp->t_stats.s_hpt++; ! 274: if (fight_flush) ! 275: { ! 276: #if USG==1 ! 277: ioctl(_tty_ch, TCFLSH, 0); ! 278: #else ! 279: raw(); /* flush typeahead */ ! 280: noraw(); ! 281: #endif ! 282: } ! 283: count = 0; ! 284: status(); ! 285: } ! 286: ! 287: /* ! 288: * swing: ! 289: * returns true if the swing hits ! 290: */ ! 291: ! 292: swing(at_lvl, op_arm, wplus) ! 293: int at_lvl, op_arm, wplus; ! 294: { ! 295: register int res = rnd(20)+1; ! 296: register int need = (21-at_lvl)-op_arm; ! 297: ! 298: return (res+wplus >= need); ! 299: } ! 300: ! 301: /* ! 302: * check_level: ! 303: * Check to see if the guy has gone up a level. ! 304: */ ! 305: ! 306: check_level() ! 307: { ! 308: register int i, add; ! 309: ! 310: for (i = 0; e_levels[i] != 0; i++) ! 311: if (e_levels[i] > pstats.s_exp) ! 312: break; ! 313: i++; ! 314: if (i > pstats.s_lvl) ! 315: { ! 316: add = roll(i-pstats.s_lvl,10); ! 317: max_hp += add; ! 318: if ((pstats.s_hpt += add) > max_hp) ! 319: pstats.s_hpt = max_hp; ! 320: msg("Welcome to level %d", i); ! 321: } ! 322: pstats.s_lvl = i; ! 323: } ! 324: ! 325: /* ! 326: * roll_em: ! 327: * Roll several attacks ! 328: */ ! 329: ! 330: roll_em(att, def, weap, hurl) ! 331: struct stats *att, *def; ! 332: struct object *weap; ! 333: bool hurl; ! 334: { ! 335: register char *cp; ! 336: register int ndice, nsides, def_arm; ! 337: register bool did_hit = FALSE; ! 338: register int prop_hplus, prop_dplus; ! 339: #define index strchr ! 340: char *index(); ! 341: ! 342: prop_hplus = prop_dplus = 0; ! 343: if (weap == NULL) ! 344: cp = att->s_dmg; ! 345: else if (hurl) ! 346: if ((weap->o_flags&ISMISL) && cur_weapon != NULL && ! 347: cur_weapon->o_which == weap->o_launch) ! 348: { ! 349: cp = weap->o_hurldmg; ! 350: prop_hplus = cur_weapon->o_hplus; ! 351: prop_dplus = cur_weapon->o_dplus; ! 352: } ! 353: else ! 354: cp = (weap->o_flags&ISMISL ? weap->o_damage : weap->o_hurldmg); ! 355: else ! 356: { ! 357: cp = weap->o_damage; ! 358: /* ! 359: * Drain a staff of striking ! 360: */ ! 361: if (weap->o_type == STICK && weap->o_which == WS_HIT ! 362: && weap->o_charges == 0) ! 363: { ! 364: weap->o_damage = "0d0"; ! 365: weap->o_hplus = weap->o_dplus = 0; ! 366: } ! 367: } ! 368: for (;;) ! 369: { ! 370: int damage; ! 371: int hplus = prop_hplus + (weap == NULL ? 0 : weap->o_hplus); ! 372: int dplus = prop_dplus + (weap == NULL ? 0 : weap->o_dplus); ! 373: ! 374: if (weap == cur_weapon) ! 375: { ! 376: if (ISRING(LEFT, R_ADDDAM)) ! 377: dplus += cur_ring[LEFT]->o_ac; ! 378: else if (ISRING(LEFT, R_ADDHIT)) ! 379: hplus += cur_ring[LEFT]->o_ac; ! 380: if (ISRING(RIGHT, R_ADDDAM)) ! 381: dplus += cur_ring[RIGHT]->o_ac; ! 382: else if (ISRING(RIGHT, R_ADDHIT)) ! 383: hplus += cur_ring[RIGHT]->o_ac; ! 384: } ! 385: ndice = atoi(cp); ! 386: if ((cp = index(cp, 'd')) == NULL) ! 387: break; ! 388: nsides = atoi(++cp); ! 389: if (def == &pstats) ! 390: { ! 391: if (cur_armor != NULL) ! 392: def_arm = cur_armor->o_ac; ! 393: else ! 394: def_arm = def->s_arm; ! 395: if (ISRING(LEFT, R_PROTECT)) ! 396: def_arm -= cur_ring[LEFT]->o_ac; ! 397: else if (ISRING(RIGHT, R_PROTECT)) ! 398: def_arm -= cur_ring[RIGHT]->o_ac; ! 399: } ! 400: else ! 401: def_arm = def->s_arm; ! 402: if (swing(att->s_lvl, def_arm, hplus+str_plus(&att->s_str))) ! 403: { ! 404: register int proll; ! 405: ! 406: proll = roll(ndice, nsides); ! 407: if (ndice + nsides > 0 && proll < 1) ! 408: debug("Damage for %dd%d came out %d.", ndice, nsides, proll); ! 409: damage = dplus + proll + add_dam(&att->s_str); ! 410: def->s_hpt -= max(0, damage); ! 411: did_hit = TRUE; ! 412: } ! 413: if ((cp = index(cp, '/')) == NULL) ! 414: break; ! 415: cp++; ! 416: } ! 417: return did_hit; ! 418: } ! 419: #undef index ! 420: ! 421: /* ! 422: * prname: ! 423: * The print name of a combatant ! 424: */ ! 425: ! 426: char * ! 427: prname(who, upper) ! 428: register char *who; ! 429: bool upper; ! 430: { ! 431: static char tbuf[80]; ! 432: ! 433: *tbuf = '\0'; ! 434: if (who == 0) ! 435: strcpy(tbuf, "you"); ! 436: else if (on(player, ISBLIND)) ! 437: strcpy(tbuf, "it"); ! 438: else ! 439: { ! 440: strcpy(tbuf, "the "); ! 441: strcat(tbuf, who); ! 442: } ! 443: if (upper) ! 444: *tbuf = toupper(*tbuf); ! 445: return tbuf; ! 446: } ! 447: ! 448: /* ! 449: * hit: ! 450: * Print a message to indicate a succesful hit ! 451: */ ! 452: ! 453: hit(er, ee) ! 454: register char *er, *ee; ! 455: { ! 456: register char *s; ! 457: ! 458: addmsg(prname(er, TRUE)); ! 459: if (terse) ! 460: s = " hit."; ! 461: else ! 462: switch (rnd(4)) ! 463: { ! 464: when 0: s = " scored an excellent hit on "; ! 465: when 1: s = " hit "; ! 466: when 2: s = (er == 0 ? " have injured " : " has injured "); ! 467: when 3: s = (er == 0 ? " swing and hit " : " swings and hits "); ! 468: } ! 469: addmsg(s); ! 470: if (!terse) ! 471: addmsg(prname(ee, FALSE)); ! 472: endmsg(); ! 473: } ! 474: ! 475: /* ! 476: * miss: ! 477: * Print a message to indicate a poor swing ! 478: */ ! 479: ! 480: miss(er, ee) ! 481: register char *er, *ee; ! 482: { ! 483: register char *s; ! 484: ! 485: addmsg(prname(er, TRUE)); ! 486: switch (terse ? 0 : rnd(4)) ! 487: { ! 488: when 0: s = (er == 0 ? " miss" : " misses"); ! 489: when 1: s = (er == 0 ? " swing and miss" : " swings and misses"); ! 490: when 2: s = (er == 0 ? " barely miss" : " barely misses"); ! 491: when 3: s = (er == 0 ? " don't hit" : " doesn't hit"); ! 492: } ! 493: addmsg(s); ! 494: if (!terse) ! 495: addmsg(" %s", prname(ee, FALSE)); ! 496: endmsg(); ! 497: } ! 498: ! 499: /* ! 500: * save_throw: ! 501: * See if a creature save against something ! 502: */ ! 503: save_throw(which, tp) ! 504: int which; ! 505: struct thing *tp; ! 506: { ! 507: register int need; ! 508: ! 509: need = 14 + which - tp->t_stats.s_lvl / 2; ! 510: return (roll(1, 20) >= need); ! 511: } ! 512: /* ! 513: * save: ! 514: * See if he saves against various nasty things ! 515: */ ! 516: ! 517: save(which) ! 518: int which; ! 519: { ! 520: return save_throw(which, &player); ! 521: } ! 522: ! 523: /* ! 524: * str_plus: ! 525: * compute bonus/penalties for strength on the "to hit" roll ! 526: */ ! 527: ! 528: str_plus(str) ! 529: register str_t *str; ! 530: { ! 531: if (str->st_str == 18) ! 532: { ! 533: if (str->st_add == 100) ! 534: return 3; ! 535: if (str->st_add > 50) ! 536: return 2; ! 537: } ! 538: if (str->st_str >= 17) ! 539: return 1; ! 540: if (str->st_str > 6) ! 541: return 0; ! 542: return str->st_str - 7; ! 543: } ! 544: ! 545: /* ! 546: * add_dam: ! 547: * compute additional damage done for exceptionally high or low strength ! 548: */ ! 549: ! 550: add_dam(str) ! 551: register str_t *str; ! 552: { ! 553: if (str->st_str == 18) ! 554: { ! 555: if (str->st_add == 100) ! 556: return 6; ! 557: if (str->st_add > 90) ! 558: return 5; ! 559: if (str->st_add > 75) ! 560: return 4; ! 561: if (str->st_add != 0) ! 562: return 3; ! 563: return 2; ! 564: } ! 565: if (str->st_str > 15) ! 566: return 1; ! 567: if (str->st_str > 6) ! 568: return 0; ! 569: return str->st_str - 7; ! 570: } ! 571: ! 572: /* ! 573: * raise_level: ! 574: * The guy just magically went up a level. ! 575: */ ! 576: ! 577: raise_level() ! 578: { ! 579: pstats.s_exp = e_levels[pstats.s_lvl-1] + 1L; ! 580: check_level(); ! 581: } ! 582: ! 583: /* ! 584: * thunk: ! 585: * A missile hits a monster ! 586: */ ! 587: ! 588: thunk(weap, mname) ! 589: register struct object *weap; ! 590: register char *mname; ! 591: { ! 592: if (weap->o_type == WEAPON) ! 593: msg("The %s hits the %s", w_names[weap->o_which], mname); ! 594: else ! 595: msg("You hit the %s.", mname); ! 596: } ! 597: ! 598: /* ! 599: * bounce: ! 600: * A missile misses a monster ! 601: */ ! 602: ! 603: bounce(weap, mname) ! 604: register struct object *weap; ! 605: register char *mname; ! 606: { ! 607: if (weap->o_type == WEAPON) ! 608: msg("The %s misses the %s", w_names[weap->o_which], mname); ! 609: else ! 610: msg("You missed the %s.", mname); ! 611: } ! 612: ! 613: /* ! 614: * remove a monster from the screen ! 615: */ ! 616: remove(mp, item) ! 617: register coord *mp; ! 618: register struct linked_list *item; ! 619: { ! 620: mvwaddch(mw, mp->y, mp->x, ' '); ! 621: mvwaddch(cw, mp->y, mp->x, ((struct thing *) ldata(item))->t_oldch); ! 622: detach(mlist, item); ! 623: discard(item); ! 624: } ! 625: ! 626: /* ! 627: * is_magic: ! 628: * Returns true if an object radiates magic ! 629: */ ! 630: ! 631: is_magic(obj) ! 632: register struct object *obj; ! 633: { ! 634: switch (obj->o_type) ! 635: { ! 636: case ARMOR: ! 637: return obj->o_ac != a_class[obj->o_which]; ! 638: when WEAPON: ! 639: return obj->o_hplus != 0 || obj->o_dplus != 0; ! 640: when POTION: ! 641: case SCROLL: ! 642: case STICK: ! 643: case RING: ! 644: case AMULET: ! 645: return TRUE; ! 646: } ! 647: return FALSE; ! 648: } ! 649: ! 650: /* ! 651: * killed: ! 652: * Called to put a monster to death ! 653: */ ! 654: ! 655: killed(item, pr) ! 656: register struct linked_list *item; ! 657: bool pr; ! 658: { ! 659: register struct thing *tp; ! 660: register struct linked_list *pitem, *nexti; ! 661: ! 662: tp = (struct thing *) ldata(item); ! 663: if (pr) ! 664: { ! 665: addmsg(terse ? "Defeated " : "You have defeated "); ! 666: if (on(player, ISBLIND)) ! 667: msg("it."); ! 668: else ! 669: { ! 670: if (!terse) ! 671: addmsg("the "); ! 672: msg("%s.", monsters[tp->t_type-'A'].m_name); ! 673: } ! 674: } ! 675: pstats.s_exp += tp->t_stats.s_exp; ! 676: /* ! 677: * Do adjustments if he went up a level ! 678: */ ! 679: check_level(); ! 680: /* ! 681: * If the monster was a violet fungi, un-hold him ! 682: */ ! 683: switch (tp->t_type) ! 684: { ! 685: when 'F': ! 686: player.t_flags &= ~ISHELD; ! 687: fung_hit = 0; ! 688: strcpy(monsters['F'-'A'].m_stats.s_dmg, "000d0"); ! 689: when 'L': ! 690: { ! 691: register struct room *rp; ! 692: ! 693: if ((rp = roomin(&tp->t_pos)) == NULL) ! 694: break; ! 695: if (rp->r_goldval != 0 || fallpos(&tp->t_pos,&rp->r_gold,FALSE)) ! 696: { ! 697: rp->r_goldval += GOLDCALC; ! 698: if (save(VS_MAGIC)) ! 699: rp->r_goldval += GOLDCALC + GOLDCALC ! 700: + GOLDCALC + GOLDCALC; ! 701: mvwaddch(stdscr, rp->r_gold.y, rp->r_gold.x, GOLD); ! 702: if (!(rp->r_flags & ISDARK)) ! 703: { ! 704: light(&hero); ! 705: mvwaddch(cw, hero.y, hero.x, PLAYER); ! 706: } ! 707: } ! 708: } ! 709: } ! 710: /* ! 711: * Empty the monsters pack ! 712: */ ! 713: pitem = tp->t_pack; ! 714: /* ! 715: * Get rid of the monster. ! 716: */ ! 717: remove(&tp->t_pos, item); ! 718: while (pitem != NULL) ! 719: { ! 720: register struct object *obj; ! 721: ! 722: nexti = next(tp->t_pack); ! 723: obj = (struct object *) ldata(pitem); ! 724: obj->o_pos = tp->t_pos; ! 725: detach(tp->t_pack, pitem); ! 726: fall(pitem, FALSE); ! 727: pitem = nexti; ! 728: } ! 729: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.