Mercurial > hg > early-roguelike
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 } |