Converting all function definitions to ANSI style accounts for most of the change. This has exposed other problems, such as daemons not actually being their stated type, that will require more careful solutions.
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);
|
|
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());
|
|
}
|