There should only be two changes in behavior: arogue7/fight.c, arogue7/fight.c: a to-hit bonus is now correctly applied to characters who are not monks instead of monks who are not empty-handed. urogue/fight.c: fixed an interaction with the "debug" macro that could cause the wrong message to be displayed.
279 lines
6 KiB
C
279 lines
6 KiB
C
/*
|
|
* File with various monster functions in it
|
|
*
|
|
* @(#)monsters.c 4.24 (Berkeley) 4/6/82
|
|
*
|
|
* Rogue: Exploring the Dungeons of Doom
|
|
* Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman
|
|
* All rights reserved.
|
|
*
|
|
* See the file LICENSE.TXT for full copyright and licensing information.
|
|
*/
|
|
|
|
#include <curses.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "rogue.h"
|
|
|
|
int exp_add(THING *tp);
|
|
|
|
/*
|
|
* List of monsters in rough order of vorpalness
|
|
*
|
|
* NOTE: This not initialized using strings so that xstr doesn't set up
|
|
* the string not to be saved. Otherwise genocide is lost through
|
|
* saving a game.
|
|
*/
|
|
char lvl_mons[] = {
|
|
'K', 'J', 'B', 'S', 'H', 'E', 'A', 'O', 'Z', 'G', 'L', 'C', 'R',
|
|
'Q', 'N', 'Y', 'T', 'W', 'F', 'I', 'X', 'U', 'M', 'V', 'P', 'D',
|
|
'\0'
|
|
};
|
|
|
|
char wand_mons[] = {
|
|
'K', 'J', 'B', 'S', 'H', ' ', 'A', 'O', 'Z', 'G', ' ', 'C', 'R',
|
|
'Q', ' ', 'Y', 'T', 'W', ' ', 'I', 'X', 'U', ' ', 'V', 'P', ' ',
|
|
'\0'
|
|
};
|
|
|
|
/*
|
|
* randmonster:
|
|
* Pick a monster to show up. The lower the level,
|
|
* the meaner the monster.
|
|
*/
|
|
char
|
|
randmonster(bool wander)
|
|
{
|
|
register int d;
|
|
register char *mons;
|
|
|
|
mons = wander ? wand_mons : lvl_mons;
|
|
do
|
|
{
|
|
d = level + (rnd(10) - 5);
|
|
if (d < 1)
|
|
d = rnd(5) + 1;
|
|
if (d > 26)
|
|
d = rnd(5) + 22;
|
|
} while (mons[--d] == ' ');
|
|
return mons[d];
|
|
}
|
|
|
|
/*
|
|
* new_monster:
|
|
* Pick a new monster and add it to the list
|
|
*/
|
|
void
|
|
new_monster(THING *tp, char type, coord *cp)
|
|
{
|
|
register struct monster *mp;
|
|
register int lev_add;
|
|
|
|
if ((lev_add = level - AMULETLEVEL) < 0)
|
|
lev_add = 0;
|
|
attach(mlist, tp);
|
|
tp->t_type = type;
|
|
tp->t_disguise = type;
|
|
tp->t_pos = *cp;
|
|
tp->t_oldch = mvinch(cp->y, cp->x) & A_CHARTEXT;
|
|
tp->t_room = roomin(cp);
|
|
moat(cp->y, cp->x) = tp;
|
|
mp = &monsters[tp->t_type-'A'];
|
|
tp->t_stats.s_lvl = mp->m_stats.s_lvl + lev_add;
|
|
tp->t_stats.s_maxhp = tp->t_stats.s_hpt = roll(tp->t_stats.s_lvl, 8);
|
|
tp->t_stats.s_arm = mp->m_stats.s_arm - lev_add;
|
|
strncpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg,16);
|
|
tp->t_stats.s_str = mp->m_stats.s_str;
|
|
tp->t_stats.s_exp = mp->m_stats.s_exp + lev_add * 10 + exp_add(tp);
|
|
tp->t_flags = mp->m_flags;
|
|
tp->t_turn = TRUE;
|
|
tp->t_pack = NULL;
|
|
if (ISWEARING(R_AGGR))
|
|
runto(cp, &hero);
|
|
if (type == 'M')
|
|
switch (rnd(level > 25 ? 9 : 8))
|
|
{
|
|
case 0: tp->t_disguise = GOLD;
|
|
when 1: tp->t_disguise = POTION;
|
|
when 2: tp->t_disguise = SCROLL;
|
|
when 3: tp->t_disguise = STAIRS;
|
|
when 4: tp->t_disguise = WEAPON;
|
|
when 5: tp->t_disguise = ARMOR;
|
|
when 6: tp->t_disguise = RING;
|
|
when 7: tp->t_disguise = STICK;
|
|
when 8: tp->t_disguise = AMULET;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* expadd:
|
|
* Experience to add for this monster's level/hit points
|
|
*/
|
|
int
|
|
exp_add(THING *tp)
|
|
{
|
|
register int mod;
|
|
|
|
if (tp->t_stats.s_lvl == 1)
|
|
mod = tp->t_stats.s_maxhp / 8;
|
|
else
|
|
mod = tp->t_stats.s_maxhp / 6;
|
|
if (tp->t_stats.s_lvl > 9)
|
|
mod *= 20;
|
|
else if (tp->t_stats.s_lvl > 6)
|
|
mod *= 4;
|
|
return mod;
|
|
}
|
|
|
|
/*
|
|
* wanderer:
|
|
* Create a new wandering monster and aim it at the player
|
|
*/
|
|
void
|
|
wanderer(void)
|
|
{
|
|
register int i;
|
|
register struct room *rp;
|
|
register THING *tp;
|
|
coord cp = {0,0};
|
|
register int cnt = 0;
|
|
|
|
tp = new_item();
|
|
do
|
|
{
|
|
/* Avoid endless loop when all rooms are filled with monsters
|
|
* and the player room is not accessible to the monsters.
|
|
*/
|
|
if (cnt++ >= 500)
|
|
{
|
|
discard(tp);
|
|
return;
|
|
}
|
|
i = rnd_room();
|
|
if ((rp = &rooms[i]) == proom)
|
|
continue;
|
|
rnd_pos(rp, &cp);
|
|
} until (rp != proom && step_ok(winat(cp.y, cp.x)));
|
|
new_monster(tp, randmonster(TRUE), &cp);
|
|
runto(&tp->t_pos, &hero);
|
|
#ifdef WIZARD
|
|
if (wizard)
|
|
msg("started a wandering %s", monsters[tp->t_type-'A'].m_name);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* wake_monster:
|
|
* What to do when the hero steps next to a monster
|
|
*/
|
|
THING *
|
|
wake_monster(int y, int x)
|
|
{
|
|
register THING *tp;
|
|
register struct room *rp;
|
|
register char ch;
|
|
|
|
#ifdef WIZARD
|
|
if ((tp = moat(y, x)) == NULL)
|
|
msg("can't find monster in wake_monster");
|
|
#else
|
|
tp = moat(y, x);
|
|
#endif
|
|
ch = tp->t_type;
|
|
/*
|
|
* Every time he sees mean monster, it might start chasing him
|
|
*/
|
|
if (!on(*tp, ISRUN) && rnd(3) != 0 && on(*tp, ISMEAN) && !on(*tp, ISHELD)
|
|
&& !ISWEARING(R_STEALTH))
|
|
{
|
|
tp->t_dest = &hero;
|
|
tp->t_flags |= ISRUN;
|
|
}
|
|
if (ch == 'U' && !on(player, ISBLIND) && !on(*tp, ISFOUND)
|
|
&& !on(*tp, ISCANC) && on(*tp, ISRUN))
|
|
{
|
|
rp = proom;
|
|
if ((rp != NULL && !(rp->r_flags & ISDARK))
|
|
|| DISTANCE(y, x, hero.y, hero.x) < LAMPDIST)
|
|
{
|
|
tp->t_flags |= ISFOUND;
|
|
if (!save(VS_MAGIC))
|
|
{
|
|
if (on(player, ISHUH))
|
|
lengthen(unconfuse, rnd(20) + HUHDURATION);
|
|
else
|
|
fuse(unconfuse, 0, rnd(20) + HUHDURATION, AFTER);
|
|
player.t_flags |= ISHUH;
|
|
msg("the umber hulk's gaze has confused you");
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Let greedy ones guard gold
|
|
*/
|
|
if (on(*tp, ISGREED) && !on(*tp, ISRUN))
|
|
{
|
|
tp->t_flags |= ISRUN;
|
|
if (proom->r_goldval)
|
|
tp->t_dest = &proom->r_gold;
|
|
else
|
|
tp->t_dest = &hero;
|
|
}
|
|
return tp;
|
|
}
|
|
|
|
/*
|
|
* genocide:
|
|
* Wipe one monster out of existence (for now...)
|
|
*/
|
|
void
|
|
genocide(void)
|
|
{
|
|
register THING *mp;
|
|
register char c;
|
|
register int i;
|
|
register THING *nmp;
|
|
|
|
addmsg("which monster");
|
|
if (!terse)
|
|
addmsg(" do you wish to wipe out");
|
|
msg("? ");
|
|
while (!isalpha(c = readchar()))
|
|
if (c == ESCAPE)
|
|
return;
|
|
else
|
|
{
|
|
mpos = 0;
|
|
msg("please specifiy a letter between 'A' and 'Z'");
|
|
}
|
|
mpos = 0;
|
|
if (islower(c))
|
|
c = toupper(c);
|
|
for (mp = mlist; mp; mp = nmp)
|
|
{
|
|
nmp = next(mp);
|
|
if (mp->t_type == c)
|
|
remove_monster(&mp->t_pos, mp, FALSE);
|
|
}
|
|
for (i = 0; i < 26; i++)
|
|
if (lvl_mons[i] == c)
|
|
{
|
|
lvl_mons[i] = ' ';
|
|
wand_mons[i] = ' ';
|
|
break;
|
|
}
|
|
if (!terse)
|
|
addmsg("there will be ");
|
|
msg("no more %ss", monsters[c - 'A'].m_name);
|
|
}
|
|
|
|
/*
|
|
* give_pack:
|
|
* Give a pack to a monster if it deserves one
|
|
*/
|
|
void
|
|
give_pack(THING *tp)
|
|
{
|
|
if (rnd(100) < monsters[tp->t_type-'A'].m_carry)
|
|
attach(tp->t_pack, new_thing());
|
|
}
|