comparison 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
comparison
equal deleted inserted replaced
35:05018c63a721 36:2128c7dc8a40
1 /*
2 * File with various monster functions in it
3 *
4 * @(#)monsters.c 9.0 (rdk) 7/17/84
5 *
6 * Super-Rogue
7 * Copyright (C) 1984 Robert D. Kindelberger
8 * All rights reserved.
9 *
10 * Based on "Rogue: Exploring the Dungeons of Doom"
11 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
12 * All rights reserved.
13 *
14 * See the file LICENSE.TXT for full copyright and licensing information.
15 */
16
17 #include "rogue.h"
18 #include <ctype.h>
19 #include "rogue.ext"
20
21 /*
22 * rnd_mon:
23 * Pick a monster to show up. The lower the level,
24 * the meaner the monster.
25 */
26 rnd_mon(wander,baddie)
27 bool wander;
28 bool baddie; /* TRUE when from a polymorph stick */
29 {
30 reg int i, ok, cnt;
31
32 cnt = 0;
33 if (levcount == 0) /* if only asmodeus possible */
34 return(MAXMONS);
35 if (baddie) {
36 while (1) {
37 i = rnd(MAXMONS); /* pick ANY monster */
38 if (monsters[i].m_lev.l_lev < 0) /* skip genocided ones */
39 continue;
40 return i;
41 }
42 }
43 ok = FALSE;
44 do {
45 /*
46 * get a random monster from this range
47 */
48 i = rnd(levcount);
49 /*
50 * Only create a wandering monster if we want one
51 * (or the count is exceeded)
52 */
53 if (!wander || mtlev[i]->m_lev.d_wand || ++cnt > 500)
54 ok = TRUE;
55 } while(!ok);
56 return (midx(mtlev[i]->m_show));
57 }
58
59 /*
60 * lev_mon:
61 * This gets all monsters possible on this level
62 */
63 lev_mon()
64 {
65 reg int i;
66 reg struct monster *mm;
67
68 levcount = 0;
69 for (i = 0; i < MAXMONS; i++) {
70 mm = &monsters[i];
71 if (mm->m_lev.h_lev >= level && mm->m_lev.l_lev <= level) {
72 mtlev[levcount] = mm;
73 if (++levcount >= MONRANGE)
74 break;
75 }
76 }
77 if (levcount == 0) /* if no monsters are possible */
78 mtlev[0] = &monsters[MAXMONS]; /* then asmodeus 'A' */
79 }
80
81 /*
82 * new_monster:
83 * Pick a new monster and add it to the list
84 */
85 struct linked_list *
86 new_monster(type, cp, treas)
87 struct coord *cp;
88 bool treas;
89 char type;
90 {
91 reg struct linked_list *item;
92 reg struct thing *tp;
93 reg struct monster *mp;
94 reg struct stats *st;
95 float killexp; /* experience gotten for killing him */
96
97 item = new_item(sizeof(struct thing));
98 attach(mlist, item);
99 tp = THINGPTR(item);
100 st = &tp->t_stats;
101 mp = &monsters[type]; /* point to this monsters structure */
102 tp->t_type = mp->m_show;
103 tp->t_indx = type;
104 tp->t_pos = *cp;
105 tp->t_room = roomin(cp);
106 tp->t_oldch = mvwinch(cw, cp->y, cp->x);
107 tp->t_nomove = 0;
108 tp->t_nocmd = 0;
109 mvwaddch(mw, cp->y, cp->x, tp->t_type);
110
111 /*
112 * copy monster data
113 */
114 tp->t_stats = mp->m_stats;
115
116 /*
117 * If below amulet level, make the monsters meaner the
118 * deeper the hero goes.
119 */
120 if (level > AMLEVEL)
121 st->s_lvl += ((level - AMLEVEL) / 4);
122
123 /*
124 * If monster in treasure room, then tougher.
125 */
126 if (treas)
127 st->s_lvl += 1;
128 if (levtype == MAZELEV)
129 st->s_lvl += 1;
130 /*
131 * If the hero is going back up, then the monsters are more
132 * prepared for him, so tougher.
133 */
134 if (goingup())
135 st->s_lvl += 1;
136
137 /*
138 * Get hit points for monster depending on his experience
139 */
140 st->s_hpt = roll(st->s_lvl, 8);
141 st->s_maxhp = st->s_hpt;
142 /*
143 * Adjust experience point we get for killing it by the
144 * strength of this particular monster by ~~ +- 50%
145 */
146 killexp = mp->m_stats.s_exp * (0.47 + (float)st->s_hpt /
147 (8 * (float)st->s_lvl));
148
149 st->s_exp = killexp; /* use float for accuracy */
150 if(st->s_exp < 1)
151 st->s_exp = 1; /* minimum 1 experience point */
152 tp->t_flags = mp->m_flags;
153 /*
154 * If monster in treasure room, then MEAN
155 */
156 if (treas || levtype == MAZELEV)
157 tp->t_flags |= ISMEAN;
158 tp->t_turn = TRUE;
159 tp->t_pack = NULL;
160 /*
161 * Dont wander if treas room
162 */
163 if (iswearing(R_AGGR) && !treas)
164 runto(cp, &hero);
165 if (tp->t_type == 'M') {
166 char mch;
167
168 if (tp->t_pack != NULL)
169 mch = (OBJPTR(tp->t_pack))->o_type;
170 else {
171 switch (rnd(level >= AMLEVEL ? 9 : 8)) {
172 case 0: mch = GOLD;
173 when 1: mch = POTION;
174 when 2: mch = SCROLL;
175 when 3: mch = STAIRS;
176 when 4: mch = WEAPON;
177 when 5: mch = ARMOR;
178 when 6: mch = RING;
179 when 7: mch = STICK;
180 when 8: mch = AMULET;
181 }
182 }
183 if (treas)
184 mch = 'M'; /* no disguise in treasure room */
185 tp->t_disguise = mch;
186 }
187 return item;
188 }
189
190 /*
191 * wanderer:
192 * A wandering monster has awakened and is headed for the player
193 */
194 wanderer()
195 {
196 reg int ch;
197 reg struct room *rp, *hr = player.t_room;
198 reg struct linked_list *item;
199 reg struct thing *tp;
200 struct coord mp;
201
202 do {
203 rp = &rooms[rnd_room()];
204 if (rp != hr || levtype == MAZELEV) {
205 mp = *rnd_pos(rp);
206 ch = mvinch(mp.y, mp.x);
207 }
208 } while (!step_ok(ch));
209 item = new_monster(rnd_mon(TRUE,FALSE), &mp, FALSE);
210 tp = THINGPTR(item);
211 tp->t_flags |= ISRUN;
212 tp->t_dest = &hero;
213 }
214
215 /*
216 * wake_monster:
217 * What to do when the hero steps next to a monster
218 */
219 struct linked_list *
220 wake_monster(y, x)
221 int y, x;
222 {
223 reg struct thing *tp;
224 reg struct linked_list *it;
225 reg struct room *rp;
226 reg char ch;
227 bool treas = FALSE;
228
229 if ((it = find_mons(y, x)) == NULL)
230 return NULL;
231 tp = THINGPTR(it);
232 ch = tp->t_type;
233 /*
234 * Every time he sees mean monster, it might start chasing him
235 */
236 rp = player.t_room;
237 if (rp != NULL && rf_on(rp,ISTREAS)) {
238 tp->t_flags &= ~ISHELD;
239 treas = TRUE;
240 }
241 if (treas || (rnd(100) > 33 && on(*tp,ISMEAN) && off(*tp,ISHELD) &&
242 !iswearing(R_STEALTH))) {
243 tp->t_dest = &hero;
244 tp->t_flags |= ISRUN;
245 }
246 if (ch == 'U' && pl_off(ISBLIND)) {
247 if ((rp != NULL && !rf_on(rp,ISDARK) && levtype != MAZELEV)
248 || DISTANCE(y, x, hero.y, hero.x) < 3) {
249 if (off(*tp,ISFOUND) && !save(VS_PETRIFICATION)
250 && !iswearing(R_SUSAB) && pl_off(ISINVINC)) {
251 msg("The umber hulk's gaze has confused you.");
252 if (pl_on(ISHUH))
253 lengthen(unconfuse,rnd(20)+HUHDURATION);
254 else
255 fuse(unconfuse,TRUE,rnd(20)+HUHDURATION);
256 player.t_flags |= ISHUH;
257 }
258 tp->t_flags |= ISFOUND;
259 }
260 }
261 /*
262 * Hide invisible monsters
263 */
264 if ((tp->t_flags & ISINVIS) && pl_off(CANSEE))
265 ch = mvinch(y, x);
266 /*
267 * Let greedy ones guard gold
268 */
269 if (on(*tp, ISGREED) && off(*tp, ISRUN)) {
270 if (rp != NULL && rp->r_goldval) {
271 tp->t_dest = &rp->r_gold;
272 tp->t_flags |= ISRUN;
273 }
274 }
275 return it;
276 }
277
278 /*
279 * genocide:
280 * Eradicate a monster forevermore
281 */
282 genocide()
283 {
284 reg struct linked_list *ip, *nip;
285 reg struct thing *mp;
286 struct monster *mm;
287 reg int i, ii, c;
288
289 if (levcount == 0) {
290 mpos = 0;
291 msg("You cannot genocide Asmodeus !!");
292 return;
293 }
294 tryagain:
295 i = TRUE; /* assume an error now */
296 while (i) {
297 msg("Which monster (remember UPPER & lower case)?");
298 c = readchar(); /* get a char */
299 if (c == ESCAPE) { /* he can abort (the fool) */
300 msg("");
301 return;
302 }
303 if (isalpha(c)) /* valid char here */
304 i = FALSE; /* exit the loop */
305 else { /* he didn't type a letter */
306 mpos = 0;
307 msg("Please specify a letter between 'A' and 'z'");
308 }
309 }
310 i = midx(c); /* get index to monster */
311 mm = &monsters[i];
312 if (mm->m_lev.l_lev < 0) {
313 mpos = 0;
314 msg("You have already eliminated the %s.",mm->m_name);
315 goto tryagain;
316 }
317 for (ip = mlist; ip != NULL; ip = nip) {
318 mp = THINGPTR(ip);
319 nip = next(ip);
320 if (mp->t_type == c)
321 remove_monster(&mp->t_pos, ip);
322 }
323 mm->m_lev.l_lev = -1; /* get rid of it */
324 mm->m_lev.h_lev = -1;
325 lev_mon(); /* redo monster list */
326 mpos = 0;
327 msg("You have wiped out the %s.",mm->m_name);
328 }
329
330 /*
331 * unhold:
332 * Release the player from being held
333 */
334 unhold(whichmon)
335 char whichmon;
336 {
337 switch (whichmon) {
338 case 'F':
339 fung_hit = 0;
340 strcpy(monsters[midx('F')].m_stats.s_dmg, "000d0");
341 case 'd':
342 player.t_flags &= ~ISHELD;
343 }
344 }
345
346 /*
347 * midx:
348 * This returns an index to 'whichmon'
349 */
350 midx(whichmon)
351 char whichmon;
352 {
353 if (isupper(whichmon))
354 return(whichmon - 'A'); /* 0 to 25 for uppercase */
355 else if (islower(whichmon))
356 return(whichmon - 'a' + 26); /* 26 to 51 for lowercase */
357 else
358 return(MAXMONS); /* 52 for Asmodeus */
359 }
360
361 /*
362 * monhurt:
363 * See when monster should run or fight. Return
364 * TRUE if hit points less than acceptable.
365 */
366 monhurt(th)
367 struct thing *th;
368 {
369 reg int ewis, crithp, f1, f2;
370 reg struct stats *st;
371
372 st = &th->t_stats;
373 ewis = st->s_ef.a_wis;
374 if (ewis <= MONWIS) /* stupid monsters dont know */
375 return FALSE;
376 f1 = st->s_maxhp / 4; /* base hpt for being hurt */
377 f2 = (ewis - MONWIS) * 5 / 3; /* bonus for smart monsters */
378 if (th->t_flags & ISWOUND) /* if recovering from being */
379 f1 *= 2; /* wounded, then double the base */
380 crithp = f1 + f2; /* get critical hpt for hurt */
381 if (crithp > st->s_maxhp) /* only up to max hpt */
382 crithp = st->s_maxhp;
383 if (st->s_hpt < crithp) /* if < critical, then still hurt */
384 return TRUE;
385 return FALSE;
386 }