diff rogue5/monsters.c @ 33:f502bf60e6e4

Import Rogue 5.4 from the Roguelike Restoration Project (r1490)
author elwin
date Mon, 24 May 2010 20:10:59 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rogue5/monsters.c	Mon May 24 20:10:59 2010 +0000
@@ -0,0 +1,261 @@
+/*
+ * File with various monster functions in it
+ *
+ * @(#)monsters.c	4.46 (Berkeley) 02/05/99
+ *
+ * Rogue: Exploring the Dungeons of Doom
+ * Copyright (C) 1980-1983, 1985, 1999 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 "rogue.h"
+#include <ctype.h>
+
+/*
+ * List of monsters in rough order of vorpalness
+ */
+static const int lvl_mons[] =  {
+    'K', 'E', 'B', 'S', 'H', 'I', 'R', 'O', 'Z', 'L', 'C', 'Q', 'A',
+    'N', 'Y', 'F', 'T', 'W', 'P', 'X', 'U', 'M', 'V', 'G', 'J', 'D'
+};
+
+static const int wand_mons[] = {
+    'K', 'E', 'B', 'S', 'H',   0, 'R', 'O', 'Z',   0, 'C', 'Q', 'A',
+      0, 'Y',   0, 'T', 'W', 'P',   0, 'U', 'M', 'V', 'G', 'J',   0
+};
+
+/*
+ * randmonster:
+ *	Pick a monster to show up.  The lower the level,
+ *	the meaner the monster.
+ */
+int
+randmonster(int wander)
+{
+    int d;
+    const int *mons;
+
+    mons = (wander ? wand_mons : lvl_mons);
+    do
+    {
+	d = level + (rnd(10) - 6);
+	if (d < 0)
+	    d = rnd(5);
+	if (d > 25)
+	    d = rnd(5) + 21;
+    } while (mons[d] == 0);
+    return mons[d];
+}
+
+/*
+ * new_monster:
+ *	Pick a new monster and add it to the list
+ */
+
+void
+new_monster(THING *tp, int type, const coord *cp)
+{
+    struct monster *mp;
+    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;
+    move(cp->y, cp->x);
+    tp->t_oldch = CCHAR( inch() );
+    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;
+    strcpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg);
+    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;
+    if (level > 29)
+	tp->t_flags |= ISHASTE;
+    tp->t_turn = TRUE;
+    tp->t_pack = NULL;
+    if (ISWEARING(R_AGGR))
+	runto(cp);
+    if (type == 'X')
+	tp->t_disguise = rnd_thing();
+}
+
+/*
+ * expadd:
+ *	Experience to add for this monster's level/hit points
+ */
+int
+exp_add(const THING *tp)
+{
+    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)
+{
+    THING *tp;
+    coord cp;
+    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;
+	}
+	find_floor(NULL, &cp, FALSE, TRUE);
+    } while (roomin(&cp) == proom && moat(cp.y, cp.x) == NULL);
+    new_monster(tp, randmonster(TRUE), &cp);
+    if (on(player, SEEMONST))
+    {
+	standout();
+	if (!on(player, ISHALU))
+	    addch(tp->t_type);
+	else
+	    addch(rnd(26) + 'A');
+	standend();
+    }
+    runto(&tp->t_pos);
+#ifdef MASTER
+    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
+ */
+const THING *
+wake_monster(int y, int x)
+{
+    THING *tp;
+    struct room *rp;
+	int ch;
+    const char *mname;
+
+	if ((tp = moat(y, x)) == NULL) {
+#ifdef MASTER
+		msg("can't find monster in wake_monster");
+#endif
+		return NULL;
+	}
+
+    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) && !on(player, ISLEVIT))
+    {
+	tp->t_dest = &hero;
+	tp->t_flags |= ISRUN;
+    }
+    if (ch == 'M' && !on(player, ISBLIND) && !on(player, ISHALU)
+	&& !on(*tp, ISFOUND) && !on(*tp, ISCANC) && on(*tp, ISRUN))
+    {
+        rp = proom;
+	if ((rp != NULL && !(rp->r_flags & ISDARK))
+	    || dist(y, x, hero.y, hero.x) < LAMPDIST)
+	{
+	    tp->t_flags |= ISFOUND;
+	    if (!save(VS_MAGIC))
+	    {
+		if (on(player, ISHUH))
+		    lengthen(unconfuse, spread(HUHDURATION));
+		else
+		    fuse(unconfuse, 0, spread(HUHDURATION), AFTER);
+		player.t_flags |= ISHUH;
+		mname = set_mname(tp);
+		addmsg("%s", mname);
+		if (strcmp(mname, "it") != 0)
+		    addmsg("'");
+		msg("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;
+}
+
+/*
+ * give_pack:
+ *	Give a pack to a monster if it deserves one
+ */
+
+void
+give_pack(THING *tp)
+{
+    if (level >= max_level && rnd(100) < monsters[tp->t_type-'A'].m_carry)
+	attach(tp->t_pack, new_thing());
+}
+
+/*
+ * save_throw:
+ *	See if a creature save against something
+ */
+int
+save_throw(int which, const THING *tp)
+{
+    int need;
+
+    need = 14 + which - tp->t_stats.s_lvl / 2;
+    return (roll(1, 20) >= need);
+}
+
+/*
+ * save:
+ *	See if he saves against various nasty things
+ */
+int
+save(int which)
+{
+    if (which == VS_MAGIC)
+    {
+	if (ISRING(LEFT, R_PROTECT))
+	    which -= cur_ring[LEFT]->o_arm;
+	if (ISRING(RIGHT, R_PROTECT))
+	    which -= cur_ring[RIGHT]->o_arm;
+    }
+    return save_throw(which, &player);
+}