1 /*
2  * File with various monster functions in it
3  *
4  * monsters.c	1.4 (A.I. Design)	12/14/84
5  */
6 
7 #include "rogue.h"
8 #include "curses.h"
9 
10 /*
11  * List of monsters in rough order of vorpalness
12  */
13 
14 static char *lvl_mons =  "K BHISOR LCA NYTWFP GMXVJD";
15 static char *wand_mons = "KEBHISORZ CAQ YTW PUGM VJ ";
16 
17 /*
18  * randmonster:
19  *	Pick a monster to show up.  The lower the level,
20  *	the meaner the monster.
21  */
22 randmonster(wander)
23 bool wander;
24 {
25     register int d;
26     register char *mons;
27 
28     mons = wander ? wand_mons : lvl_mons;
29     do {
30     	int r10 = rnd(5) + rnd(6);
31 
32 		d = level + (r10 - 5);
33 		if (d < 1)
34 		    d = rnd(5) + 1;
35 		if (d > 26)
36 		    d = rnd(5) + 22;
37     } while (mons[--d] == ' ');
38     return mons[d];
39 }
40 
41 /*
42  * new_monster:
43  *	Pick a new monster and add it to the list
44  */
45 new_monster(tp, type, cp)
46 THING *tp;
47 byte type;
48 coord *cp;
49 {
50     register struct monster *mp;
51     register int lev_add;
52 
53     if ((lev_add = level - AMULETLEVEL) < 0)
54 		lev_add = 0;
55     attach(mlist, tp);
56     tp->t_type = type;
57     tp->t_disguise = type;
58     bcopy(tp->t_pos,*cp);
59     tp->t_oldch = '@';
60     tp->t_room = roomin(cp);
61     mp = &monsters[tp->t_type-'A'];
62     tp->t_stats.s_lvl = mp->m_stats.s_lvl + lev_add;
63     tp->t_stats.s_maxhp = tp->t_stats.s_hpt = roll(tp->t_stats.s_lvl, 8);
64     tp->t_stats.s_arm = mp->m_stats.s_arm - lev_add;
65     tp->t_stats.s_dmg = mp->m_stats.s_dmg;
66     tp->t_stats.s_str = mp->m_stats.s_str;
67     tp->t_stats.s_exp = mp->m_stats.s_exp + lev_add * 10 + exp_add(tp);
68     tp->t_flags = mp->m_flags;
69     tp->t_turn = TRUE;
70     tp->t_pack = NULL;
71     if (ISWEARING(R_AGGR))
72 		start_run(cp);
73     if (type == 'F') 
74 		tp->t_stats.s_dmg = f_damage;
75     if (type == 'X')
76 		switch (rnd(level > 25 ? 9 : 8)) {
77 	    when 0: tp->t_disguise = GOLD;
78 	    when 1: tp->t_disguise = POTION;
79 	    when 2: tp->t_disguise = SCROLL;
80 	    when 3: tp->t_disguise = STAIRS;
81 	    when 4: tp->t_disguise = WEAPON;
82 	    when 5: tp->t_disguise = ARMOR;
83 	    when 6: tp->t_disguise = RING;
84 	    when 7: tp->t_disguise = STICK;
85 	    when 8: tp->t_disguise = AMULET;
86 	}
87 }
88 
89 /*
90  *  f_restor(): restor initial damage string for flytraps
91  */
92  f_restor()
93  {
94     register struct monster *mp = &monsters['F'-'A'];
95 
96     fung_hit = 0;
97     strcpy(f_damage, mp->m_stats.s_dmg);
98  }
99 
100 /*
101  * expadd:
102  *	Experience to add for this monster's level/hit points
103  */
104 exp_add(tp)
105 register THING *tp;
106 {
107     register int mod;
108 
109     if (tp->t_stats.s_lvl == 1)
110 		mod = tp->t_stats.s_maxhp / 8;
111     else
112 		mod = tp->t_stats.s_maxhp / 6;
113     if (tp->t_stats.s_lvl > 9)
114 		mod *= 20;
115     else if (tp->t_stats.s_lvl > 6)
116 		mod *= 4;
117     return mod;
118 }
119 
120 /*
121  * wanderer:
122  *	Create a new wandering monster and aim it at the player
123  */
124 wanderer()
125 {
126     int i;
127     register struct room *rp;
128     register THING *tp;
129     coord cp;
130 
131 	/*
132 	 * can we allocate a new monster
133 	 */
134     if ((tp = new_item()) == NULL)
135     	return;
136     do {
137 		i = rnd_room();
138 		if ((rp = &rooms[i]) == proom)
139 		    continue;
140 		rnd_pos(rp, &cp);
141     } while (!(rp != proom && step_ok(winat(cp.y, cp.x))));
142     new_monster(tp, randmonster(TRUE), &cp);
143 #ifdef TEST
144     if (bailout && me())
145     	msg("wanderer bailout");
146 #endif TEST
147 #ifdef WIZARD
148     if (wizard)
149     	msg("started a wandering %s", monsters[tp->t_type-'A'].m_name);
150 #endif
151     start_run(&tp->t_pos);
152 }
153 
154 /*
155  * wake_monster:
156  *	What to do when the hero steps next to a monster
157  */
158 THING *
159 wake_monster(y, x)
160 int y, x;
161 {
162     register THING *tp;
163     register struct room *rp;
164     register byte ch;
165 	register int dst;
166 
167     if ((tp = moat(y, x)) == NULL)
168     	return tp;
169     ch = tp->t_type;
170     /*
171      * Every time he sees mean monster, it might start chasing him
172      */
173     if (!on(*tp, ISRUN) && rnd(3) != 0 && on(*tp, ISMEAN) && !on(*tp, ISHELD)
174 		&& !ISWEARING(R_STEALTH))
175     {
176 		tp->t_dest = &hero;
177 		tp->t_flags |= ISRUN;
178     }
179     if (ch == 'M' && !on(player, ISBLIND) && !on(*tp, ISFOUND)
180 		&& !on(*tp, ISCANC) && on(*tp, ISRUN))
181     {
182         rp = proom;
183 		dst = DISTANCE(y, x, hero.y, hero.x);
184 		if ((rp != NULL && !(rp->r_flags & ISDARK)) || dst < LAMPDIST) {
185 		    tp->t_flags |= ISFOUND;
186 		    if (!save(VS_MAGIC)) {
187 				if (on(player, ISHUH))
188 				    lengthen(unconfuse, rnd(20) + HUHDURATION);
189 				else
190 				    fuse(unconfuse, 0, rnd(20) + HUHDURATION);
191 				player.t_flags |= ISHUH;
192 				msg("the medusa's gaze has confused you");
193 		    }
194 		}
195     }
196     /*
197      * Let greedy ones guard gold
198      */
199     if (on(*tp, ISGREED) && !on(*tp, ISRUN)) {
200 		tp->t_flags = tp->t_flags | ISRUN;
201 		if (proom->r_goldval)
202 		    tp->t_dest = &proom->r_gold;
203 		else
204 		    tp->t_dest = &hero;
205     }
206     return tp;
207 }
208 
209 /*
210  * give_pack:
211  *	Give a pack to a monster if it deserves one
212  */
213 give_pack(tp)
214 THING *tp;
215 {
216     /*
217      * check if we can allocate a new item 
218      */
219     if (total < MAXITEMS && rnd(100) < monsters[tp->t_type-'A'].m_carry)
220 		attach(tp->t_pack, new_thing());
221 }
222 
223 /*
224  * pick_mons:
225  *	Choose a sort of monster for the enemy of a vorpally enchanted weapon
226  */
227 
228 pick_mons()
229 {
230     register char *cp = lvl_mons + strlen(lvl_mons);
231 
232     while (--cp >= lvl_mons && rnd(10))
233 		;
234     if (cp < lvl_mons)
235 		return 'M';
236     return *cp;
237 }
238 
239 
240 /*
241  * moat(x,y)
242  *    returns pointer to monster at coordinate
243  *	  if no monster there return NULL
244  */
245 
246 THING *
247 moat(my,mx)
248 	int my, mx;
249 {
250 	register THING *tp;
251 
252 	for (tp = mlist ; tp != NULL ; tp = next(tp))
253 		if (tp->t_pos.x == mx  && tp->t_pos.y == my)
254 			return(tp);
255 	return(NULL);
256 }
257 