Annotation of early-roguelike/srogue/monsters.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * File with various monster functions in it
! 3: *
! 4: * @(#)monsters.c 9.0 (rdk) 7/17/84
! 5: *
! 6: * Super-Rogue
! 7: * Copyright (C) 1984 Robert D. Kindelberger
! 8: * All rights reserved.
! 9: *
! 10: * Based on "Rogue: Exploring the Dungeons of Doom"
! 11: * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
! 12: * All rights reserved.
! 13: *
! 14: * See the file LICENSE.TXT for full copyright and licensing information.
! 15: */
! 16:
! 17: #include <string.h>
! 18: #include "rogue.h"
! 19: #include <ctype.h>
! 20: #include "rogue.ext"
! 21:
! 22: /*
! 23: * rnd_mon:
! 24: * Pick a monster to show up. The lower the level,
! 25: * the meaner the monster.
! 26: */
! 27: char
! 28: rnd_mon(bool wander, bool baddie)
! 29: {
! 30: /* baddie; TRUE when from a polymorph stick */
! 31: reg int i, ok, cnt;
! 32:
! 33: cnt = 0;
! 34: if (levcount == 0) /* if only asmodeus possible */
! 35: return(MAXMONS);
! 36: if (baddie) {
! 37: while (1) {
! 38: i = rnd(MAXMONS); /* pick ANY monster */
! 39: if (monsters[i].m_lev.l_lev < 0) /* skip genocided ones */
! 40: continue;
! 41: return i;
! 42: }
! 43: }
! 44: ok = FALSE;
! 45: do {
! 46: /*
! 47: * get a random monster from this range
! 48: */
! 49: i = rnd(levcount);
! 50: /*
! 51: * Only create a wandering monster if we want one
! 52: * (or the count is exceeded)
! 53: */
! 54: if (!wander || mtlev[i]->m_lev.d_wand || ++cnt > 500)
! 55: ok = TRUE;
! 56: } while(!ok);
! 57: return (midx(mtlev[i]->m_show));
! 58: }
! 59:
! 60: /*
! 61: * lev_mon:
! 62: * This gets all monsters possible on this level
! 63: */
! 64: void
! 65: lev_mon(void)
! 66: {
! 67: reg int i;
! 68: reg struct monster *mm;
! 69:
! 70: levcount = 0;
! 71: for (i = 0; i < MAXMONS; i++) {
! 72: mm = &monsters[i];
! 73: if (mm->m_lev.h_lev >= level && mm->m_lev.l_lev <= level) {
! 74: mtlev[levcount] = mm;
! 75: if (++levcount >= MONRANGE)
! 76: break;
! 77: }
! 78: }
! 79: if (levcount == 0) /* if no monsters are possible */
! 80: mtlev[0] = &monsters[MAXMONS]; /* then asmodeus 'A' */
! 81: }
! 82:
! 83: /*
! 84: * new_monster:
! 85: * Pick a new monster and add it to the list
! 86: */
! 87: struct linked_list *
! 88: new_monster(char type, struct coord *cp, bool treas)
! 89: {
! 90: reg struct linked_list *item;
! 91: reg struct thing *tp;
! 92: reg struct monster *mp;
! 93: reg struct stats *st;
! 94: float killexp; /* experience gotten for killing him */
! 95:
! 96: item = new_item(sizeof(struct thing));
! 97: attach(mlist, item);
! 98: tp = THINGPTR(item);
! 99: st = &tp->t_stats;
! 100: mp = &monsters[type]; /* point to this monsters structure */
! 101: tp->t_type = mp->m_show;
! 102: tp->t_indx = type;
! 103: tp->t_pos = *cp;
! 104: tp->t_room = roomin(cp);
! 105: tp->t_oldch = mvwinch(cw, cp->y, cp->x);
! 106: tp->t_nomove = 0;
! 107: tp->t_nocmd = 0;
! 108: mvwaddch(mw, cp->y, cp->x, tp->t_type);
! 109:
! 110: /*
! 111: * copy monster data
! 112: */
! 113: tp->t_stats = mp->m_stats;
! 114:
! 115: /*
! 116: * If below amulet level, make the monsters meaner the
! 117: * deeper the hero goes.
! 118: */
! 119: if (level > AMLEVEL)
! 120: st->s_lvl += ((level - AMLEVEL) / 4);
! 121:
! 122: /*
! 123: * If monster in treasure room, then tougher.
! 124: */
! 125: if (treas)
! 126: st->s_lvl += 1;
! 127: if (levtype == MAZELEV)
! 128: st->s_lvl += 1;
! 129: /*
! 130: * If the hero is going back up, then the monsters are more
! 131: * prepared for him, so tougher.
! 132: */
! 133: if (goingup())
! 134: st->s_lvl += 1;
! 135:
! 136: /*
! 137: * Get hit points for monster depending on his experience
! 138: */
! 139: st->s_hpt = roll(st->s_lvl, 8);
! 140: st->s_maxhp = st->s_hpt;
! 141: /*
! 142: * Adjust experience point we get for killing it by the
! 143: * strength of this particular monster by ~~ +- 50%
! 144: */
! 145: killexp = mp->m_stats.s_exp * (0.47 + (float)st->s_hpt /
! 146: (8 * (float)st->s_lvl));
! 147:
! 148: st->s_exp = killexp; /* use float for accuracy */
! 149: if(st->s_exp < 1)
! 150: st->s_exp = 1; /* minimum 1 experience point */
! 151: tp->t_flags = mp->m_flags;
! 152: /*
! 153: * If monster in treasure room, then MEAN
! 154: */
! 155: if (treas || levtype == MAZELEV)
! 156: tp->t_flags |= ISMEAN;
! 157: tp->t_turn = TRUE;
! 158: tp->t_pack = NULL;
! 159: /*
! 160: * Dont wander if treas room
! 161: */
! 162: if (iswearing(R_AGGR) && !treas)
! 163: runto(cp, &hero);
! 164: if (tp->t_type == 'M') {
! 165: char mch;
! 166:
! 167: if (tp->t_pack != NULL)
! 168: mch = (OBJPTR(tp->t_pack))->o_type;
! 169: else {
! 170: switch (rnd(level >= AMLEVEL ? 9 : 8)) {
! 171: case 0: mch = GOLD;
! 172: when 1: mch = POTION;
! 173: when 2: mch = SCROLL;
! 174: when 3: mch = STAIRS;
! 175: when 4: mch = WEAPON;
! 176: when 5: mch = ARMOR;
! 177: when 6: mch = RING;
! 178: when 7: mch = STICK;
! 179: when 8: mch = AMULET;
! 180: }
! 181: }
! 182: if (treas)
! 183: mch = 'M'; /* no disguise in treasure room */
! 184: tp->t_disguise = mch;
! 185: }
! 186: return item;
! 187: }
! 188:
! 189: /*
! 190: * wanderer:
! 191: * A wandering monster has awakened and is headed for the player
! 192: */
! 193: void
! 194: wanderer(void)
! 195: {
! 196: reg int ch = '-';
! 197: reg struct room *rp, *hr = player.t_room;
! 198: reg struct linked_list *item;
! 199: reg struct thing *tp;
! 200: struct coord mp;
! 201:
! 202: do {
! 203: rp = &rooms[rnd_room()];
! 204: if (rp != hr || levtype == MAZELEV) {
! 205: mp = *rnd_pos(rp);
! 206: ch = mvinch(mp.y, mp.x);
! 207: }
! 208: } while (!step_ok(ch));
! 209: item = new_monster(rnd_mon(TRUE,FALSE), &mp, FALSE);
! 210: tp = THINGPTR(item);
! 211: tp->t_flags |= ISRUN;
! 212: tp->t_dest = &hero;
! 213: }
! 214:
! 215: /*
! 216: * wake_monster:
! 217: * What to do when the hero steps next to a monster
! 218: */
! 219: struct linked_list *
! 220: wake_monster(int y, int x)
! 221: {
! 222: reg struct thing *tp;
! 223: reg struct linked_list *it;
! 224: reg struct room *rp;
! 225: reg char ch;
! 226: bool treas = FALSE;
! 227:
! 228: if ((it = find_mons(y, x)) == NULL)
! 229: return NULL;
! 230: tp = THINGPTR(it);
! 231: ch = tp->t_type;
! 232: /*
! 233: * Every time he sees mean monster, it might start chasing him
! 234: */
! 235: rp = player.t_room;
! 236: if (rp != NULL && rf_on(rp,ISTREAS)) {
! 237: tp->t_flags &= ~ISHELD;
! 238: treas = TRUE;
! 239: }
! 240: if (treas || (rnd(100) > 33 && on(*tp,ISMEAN) && off(*tp,ISHELD) &&
! 241: !iswearing(R_STEALTH))) {
! 242: tp->t_dest = &hero;
! 243: tp->t_flags |= ISRUN;
! 244: }
! 245: if (ch == 'U' && pl_off(ISBLIND)) {
! 246: if ((rp != NULL && !rf_on(rp,ISDARK) && levtype != MAZELEV)
! 247: || DISTANCE(y, x, hero.y, hero.x) < 3) {
! 248: if (off(*tp,ISFOUND) && !save(VS_PETRIFICATION)
! 249: && !iswearing(R_SUSAB) && pl_off(ISINVINC)) {
! 250: msg("The umber hulk's gaze has confused you.");
! 251: if (pl_on(ISHUH))
! 252: lengthen(unconfuse,rnd(20)+HUHDURATION);
! 253: else
! 254: fuse(unconfuse,TRUE,rnd(20)+HUHDURATION);
! 255: player.t_flags |= ISHUH;
! 256: }
! 257: tp->t_flags |= ISFOUND;
! 258: }
! 259: }
! 260: /*
! 261: * Hide invisible monsters
! 262: */
! 263: if ((tp->t_flags & ISINVIS) && pl_off(CANSEE))
! 264: ch = mvinch(y, x);
! 265: /*
! 266: * Let greedy ones guard gold
! 267: */
! 268: if (on(*tp, ISGREED) && off(*tp, ISRUN)) {
! 269: if (rp != NULL && rp->r_goldval) {
! 270: tp->t_dest = &rp->r_gold;
! 271: tp->t_flags |= ISRUN;
! 272: }
! 273: }
! 274: return it;
! 275: }
! 276:
! 277: /*
! 278: * genocide:
! 279: * Eradicate a monster forevermore
! 280: */
! 281: void
! 282: genocide(void)
! 283: {
! 284: reg struct linked_list *ip, *nip;
! 285: reg struct thing *mp;
! 286: struct monster *mm;
! 287: reg int i, ii, c;
! 288:
! 289: if (levcount == 0) {
! 290: mpos = 0;
! 291: msg("You cannot genocide Asmodeus !!");
! 292: return;
! 293: }
! 294: tryagain:
! 295: i = TRUE; /* assume an error now */
! 296: while (i) {
! 297: msg("Which monster (remember UPPER & lower case)?");
! 298: c = readchar(); /* get a char */
! 299: if (c == ESCAPE) { /* he can abort (the fool) */
! 300: msg("");
! 301: return;
! 302: }
! 303: if (isalpha(c)) /* valid char here */
! 304: i = FALSE; /* exit the loop */
! 305: else { /* he didn't type a letter */
! 306: mpos = 0;
! 307: msg("Please specify a letter between 'A' and 'z'");
! 308: }
! 309: }
! 310: i = midx(c); /* get index to monster */
! 311: mm = &monsters[i];
! 312: if (mm->m_lev.l_lev < 0) {
! 313: mpos = 0;
! 314: msg("You have already eliminated the %s.",mm->m_name);
! 315: goto tryagain;
! 316: }
! 317: for (ip = mlist; ip != NULL; ip = nip) {
! 318: mp = THINGPTR(ip);
! 319: nip = next(ip);
! 320: if (mp->t_type == c)
! 321: remove_monster(&mp->t_pos, ip);
! 322: }
! 323: mm->m_lev.l_lev = -1; /* get rid of it */
! 324: mm->m_lev.h_lev = -1;
! 325: lev_mon(); /* redo monster list */
! 326: mpos = 0;
! 327: msg("You have wiped out the %s.",mm->m_name);
! 328: }
! 329:
! 330: /*
! 331: * unhold:
! 332: * Release the player from being held
! 333: */
! 334: void
! 335: unhold(char whichmon)
! 336: {
! 337: struct linked_list *item;
! 338: struct thing *mon;
! 339:
! 340: switch (whichmon) {
! 341: case 'F':
! 342: fung_hit = 0;
! 343: for (item = mlist; item != NULL; item = next(item)) {
! 344: mon = THINGPTR(item);
! 345: if (mon->t_type == 'F')
! 346: strcpy(mon->t_stats.s_dmg, "000d0");
! 347: }
! 348: case 'd':
! 349: player.t_flags &= ~ISHELD;
! 350: }
! 351: }
! 352:
! 353: /*
! 354: * midx:
! 355: * This returns an index to 'whichmon'
! 356: */
! 357: int
! 358: midx(char whichmon)
! 359: {
! 360: if (isupper(whichmon))
! 361: return(whichmon - 'A'); /* 0 to 25 for uppercase */
! 362: else if (islower(whichmon))
! 363: return(whichmon - 'a' + 26); /* 26 to 51 for lowercase */
! 364: else
! 365: return(MAXMONS); /* 52 for Asmodeus */
! 366: }
! 367:
! 368: /*
! 369: * monhurt:
! 370: * See when monster should run or fight. Return
! 371: * TRUE if hit points less than acceptable.
! 372: */
! 373: bool
! 374: monhurt(struct thing *th)
! 375: {
! 376: reg int ewis, crithp, f1, f2;
! 377: reg struct stats *st;
! 378:
! 379: st = &th->t_stats;
! 380: ewis = st->s_ef.a_wis;
! 381: if (ewis <= MONWIS) /* stupid monsters dont know */
! 382: return FALSE;
! 383: f1 = st->s_maxhp / 4; /* base hpt for being hurt */
! 384: f2 = (ewis - MONWIS) * 5 / 3; /* bonus for smart monsters */
! 385: if (th->t_flags & ISWOUND) /* if recovering from being */
! 386: f1 *= 2; /* wounded, then double the base */
! 387: crithp = f1 + f2; /* get critical hpt for hurt */
! 388: if (crithp > st->s_maxhp) /* only up to max hpt */
! 389: crithp = st->s_maxhp;
! 390: if (st->s_hpt < crithp) /* if < critical, then still hurt */
! 391: return TRUE;
! 392: return FALSE;
! 393: }
CVSweb