Mercurial > hg > early-roguelike
diff srogue/monsters.c @ 36:2128c7dc8a40
Import Super-Rogue 9.0 from the Roguelike Restoration Project (r1490)
author | elwin |
---|---|
date | Thu, 25 Nov 2010 12:21:41 +0000 |
parents | |
children | 7bdac632ab9d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srogue/monsters.c Thu Nov 25 12:21:41 2010 +0000 @@ -0,0 +1,386 @@ +/* + * File with various monster functions in it + * + * @(#)monsters.c 9.0 (rdk) 7/17/84 + * + * Super-Rogue + * Copyright (C) 1984 Robert D. Kindelberger + * All rights reserved. + * + * Based on "Rogue: Exploring the Dungeons of Doom" + * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include "rogue.h" +#include <ctype.h> +#include "rogue.ext" + +/* + * rnd_mon: + * Pick a monster to show up. The lower the level, + * the meaner the monster. + */ +rnd_mon(wander,baddie) +bool wander; +bool baddie; /* TRUE when from a polymorph stick */ +{ + reg int i, ok, cnt; + + cnt = 0; + if (levcount == 0) /* if only asmodeus possible */ + return(MAXMONS); + if (baddie) { + while (1) { + i = rnd(MAXMONS); /* pick ANY monster */ + if (monsters[i].m_lev.l_lev < 0) /* skip genocided ones */ + continue; + return i; + } + } + ok = FALSE; + do { + /* + * get a random monster from this range + */ + i = rnd(levcount); + /* + * Only create a wandering monster if we want one + * (or the count is exceeded) + */ + if (!wander || mtlev[i]->m_lev.d_wand || ++cnt > 500) + ok = TRUE; + } while(!ok); + return (midx(mtlev[i]->m_show)); +} + +/* + * lev_mon: + * This gets all monsters possible on this level + */ +lev_mon() +{ + reg int i; + reg struct monster *mm; + + levcount = 0; + for (i = 0; i < MAXMONS; i++) { + mm = &monsters[i]; + if (mm->m_lev.h_lev >= level && mm->m_lev.l_lev <= level) { + mtlev[levcount] = mm; + if (++levcount >= MONRANGE) + break; + } + } + if (levcount == 0) /* if no monsters are possible */ + mtlev[0] = &monsters[MAXMONS]; /* then asmodeus 'A' */ +} + +/* + * new_monster: + * Pick a new monster and add it to the list + */ +struct linked_list * +new_monster(type, cp, treas) +struct coord *cp; +bool treas; +char type; +{ + reg struct linked_list *item; + reg struct thing *tp; + reg struct monster *mp; + reg struct stats *st; + float killexp; /* experience gotten for killing him */ + + item = new_item(sizeof(struct thing)); + attach(mlist, item); + tp = THINGPTR(item); + st = &tp->t_stats; + mp = &monsters[type]; /* point to this monsters structure */ + tp->t_type = mp->m_show; + tp->t_indx = type; + tp->t_pos = *cp; + tp->t_room = roomin(cp); + tp->t_oldch = mvwinch(cw, cp->y, cp->x); + tp->t_nomove = 0; + tp->t_nocmd = 0; + mvwaddch(mw, cp->y, cp->x, tp->t_type); + + /* + * copy monster data + */ + tp->t_stats = mp->m_stats; + + /* + * If below amulet level, make the monsters meaner the + * deeper the hero goes. + */ + if (level > AMLEVEL) + st->s_lvl += ((level - AMLEVEL) / 4); + + /* + * If monster in treasure room, then tougher. + */ + if (treas) + st->s_lvl += 1; + if (levtype == MAZELEV) + st->s_lvl += 1; + /* + * If the hero is going back up, then the monsters are more + * prepared for him, so tougher. + */ + if (goingup()) + st->s_lvl += 1; + + /* + * Get hit points for monster depending on his experience + */ + st->s_hpt = roll(st->s_lvl, 8); + st->s_maxhp = st->s_hpt; + /* + * Adjust experience point we get for killing it by the + * strength of this particular monster by ~~ +- 50% + */ + killexp = mp->m_stats.s_exp * (0.47 + (float)st->s_hpt / + (8 * (float)st->s_lvl)); + + st->s_exp = killexp; /* use float for accuracy */ + if(st->s_exp < 1) + st->s_exp = 1; /* minimum 1 experience point */ + tp->t_flags = mp->m_flags; + /* + * If monster in treasure room, then MEAN + */ + if (treas || levtype == MAZELEV) + tp->t_flags |= ISMEAN; + tp->t_turn = TRUE; + tp->t_pack = NULL; + /* + * Dont wander if treas room + */ + if (iswearing(R_AGGR) && !treas) + runto(cp, &hero); + if (tp->t_type == 'M') { + char mch; + + if (tp->t_pack != NULL) + mch = (OBJPTR(tp->t_pack))->o_type; + else { + switch (rnd(level >= AMLEVEL ? 9 : 8)) { + case 0: mch = GOLD; + when 1: mch = POTION; + when 2: mch = SCROLL; + when 3: mch = STAIRS; + when 4: mch = WEAPON; + when 5: mch = ARMOR; + when 6: mch = RING; + when 7: mch = STICK; + when 8: mch = AMULET; + } + } + if (treas) + mch = 'M'; /* no disguise in treasure room */ + tp->t_disguise = mch; + } + return item; +} + +/* + * wanderer: + * A wandering monster has awakened and is headed for the player + */ +wanderer() +{ + reg int ch; + reg struct room *rp, *hr = player.t_room; + reg struct linked_list *item; + reg struct thing *tp; + struct coord mp; + + do { + rp = &rooms[rnd_room()]; + if (rp != hr || levtype == MAZELEV) { + mp = *rnd_pos(rp); + ch = mvinch(mp.y, mp.x); + } + } while (!step_ok(ch)); + item = new_monster(rnd_mon(TRUE,FALSE), &mp, FALSE); + tp = THINGPTR(item); + tp->t_flags |= ISRUN; + tp->t_dest = &hero; +} + +/* + * wake_monster: + * What to do when the hero steps next to a monster + */ +struct linked_list * +wake_monster(y, x) +int y, x; +{ + reg struct thing *tp; + reg struct linked_list *it; + reg struct room *rp; + reg char ch; + bool treas = FALSE; + + if ((it = find_mons(y, x)) == NULL) + return NULL; + tp = THINGPTR(it); + ch = tp->t_type; + /* + * Every time he sees mean monster, it might start chasing him + */ + rp = player.t_room; + if (rp != NULL && rf_on(rp,ISTREAS)) { + tp->t_flags &= ~ISHELD; + treas = TRUE; + } + if (treas || (rnd(100) > 33 && on(*tp,ISMEAN) && off(*tp,ISHELD) && + !iswearing(R_STEALTH))) { + tp->t_dest = &hero; + tp->t_flags |= ISRUN; + } + if (ch == 'U' && pl_off(ISBLIND)) { + if ((rp != NULL && !rf_on(rp,ISDARK) && levtype != MAZELEV) + || DISTANCE(y, x, hero.y, hero.x) < 3) { + if (off(*tp,ISFOUND) && !save(VS_PETRIFICATION) + && !iswearing(R_SUSAB) && pl_off(ISINVINC)) { + msg("The umber hulk's gaze has confused you."); + if (pl_on(ISHUH)) + lengthen(unconfuse,rnd(20)+HUHDURATION); + else + fuse(unconfuse,TRUE,rnd(20)+HUHDURATION); + player.t_flags |= ISHUH; + } + tp->t_flags |= ISFOUND; + } + } + /* + * Hide invisible monsters + */ + if ((tp->t_flags & ISINVIS) && pl_off(CANSEE)) + ch = mvinch(y, x); + /* + * Let greedy ones guard gold + */ + if (on(*tp, ISGREED) && off(*tp, ISRUN)) { + if (rp != NULL && rp->r_goldval) { + tp->t_dest = &rp->r_gold; + tp->t_flags |= ISRUN; + } + } + return it; +} + +/* + * genocide: + * Eradicate a monster forevermore + */ +genocide() +{ + reg struct linked_list *ip, *nip; + reg struct thing *mp; + struct monster *mm; + reg int i, ii, c; + + if (levcount == 0) { + mpos = 0; + msg("You cannot genocide Asmodeus !!"); + return; + } +tryagain: + i = TRUE; /* assume an error now */ + while (i) { + msg("Which monster (remember UPPER & lower case)?"); + c = readchar(); /* get a char */ + if (c == ESCAPE) { /* he can abort (the fool) */ + msg(""); + return; + } + if (isalpha(c)) /* valid char here */ + i = FALSE; /* exit the loop */ + else { /* he didn't type a letter */ + mpos = 0; + msg("Please specify a letter between 'A' and 'z'"); + } + } + i = midx(c); /* get index to monster */ + mm = &monsters[i]; + if (mm->m_lev.l_lev < 0) { + mpos = 0; + msg("You have already eliminated the %s.",mm->m_name); + goto tryagain; + } + for (ip = mlist; ip != NULL; ip = nip) { + mp = THINGPTR(ip); + nip = next(ip); + if (mp->t_type == c) + remove_monster(&mp->t_pos, ip); + } + mm->m_lev.l_lev = -1; /* get rid of it */ + mm->m_lev.h_lev = -1; + lev_mon(); /* redo monster list */ + mpos = 0; + msg("You have wiped out the %s.",mm->m_name); +} + +/* + * unhold: + * Release the player from being held + */ +unhold(whichmon) +char whichmon; +{ + switch (whichmon) { + case 'F': + fung_hit = 0; + strcpy(monsters[midx('F')].m_stats.s_dmg, "000d0"); + case 'd': + player.t_flags &= ~ISHELD; + } +} + +/* + * midx: + * This returns an index to 'whichmon' + */ +midx(whichmon) +char whichmon; +{ + if (isupper(whichmon)) + return(whichmon - 'A'); /* 0 to 25 for uppercase */ + else if (islower(whichmon)) + return(whichmon - 'a' + 26); /* 26 to 51 for lowercase */ + else + return(MAXMONS); /* 52 for Asmodeus */ +} + +/* + * monhurt: + * See when monster should run or fight. Return + * TRUE if hit points less than acceptable. + */ +monhurt(th) +struct thing *th; +{ + reg int ewis, crithp, f1, f2; + reg struct stats *st; + + st = &th->t_stats; + ewis = st->s_ef.a_wis; + if (ewis <= MONWIS) /* stupid monsters dont know */ + return FALSE; + f1 = st->s_maxhp / 4; /* base hpt for being hurt */ + f2 = (ewis - MONWIS) * 5 / 3; /* bonus for smart monsters */ + if (th->t_flags & ISWOUND) /* if recovering from being */ + f1 *= 2; /* wounded, then double the base */ + crithp = f1 + f2; /* get critical hpt for hurt */ + if (crithp > st->s_maxhp) /* only up to max hpt */ + crithp = st->s_maxhp; + if (st->s_hpt < crithp) /* if < critical, then still hurt */ + return TRUE; + return FALSE; +}