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