Annotation of early-roguelike/srogue/monsters.c, Revision 1.1.1.1
1.1 rubenllo 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 <string.h>
18: #include "rogue.h"
19: #include <ctype.h>
20: #include "rogue.ext"
21:
22: /*
23: * rnd_mon:
24: * Pick a monster to show up. The lower the level,
25: * the meaner the monster.
26: */
27: char
28: rnd_mon(bool wander, bool baddie)
29: {
30: /* baddie; TRUE when from a polymorph stick */
31: reg int i, ok, cnt;
32:
33: cnt = 0;
34: if (levcount == 0) /* if only asmodeus possible */
35: return(MAXMONS);
36: if (baddie) {
37: while (1) {
38: i = rnd(MAXMONS); /* pick ANY monster */
39: if (monsters[i].m_lev.l_lev < 0) /* skip genocided ones */
40: continue;
41: return i;
42: }
43: }
44: ok = FALSE;
45: do {
46: /*
47: * get a random monster from this range
48: */
49: i = rnd(levcount);
50: /*
51: * Only create a wandering monster if we want one
52: * (or the count is exceeded)
53: */
54: if (!wander || mtlev[i]->m_lev.d_wand || ++cnt > 500)
55: ok = TRUE;
56: } while(!ok);
57: return (midx(mtlev[i]->m_show));
58: }
59:
60: /*
61: * lev_mon:
62: * This gets all monsters possible on this level
63: */
64: void
65: lev_mon(void)
66: {
67: reg int i;
68: reg struct monster *mm;
69:
70: levcount = 0;
71: for (i = 0; i < MAXMONS; i++) {
72: mm = &monsters[i];
73: if (mm->m_lev.h_lev >= level && mm->m_lev.l_lev <= level) {
74: mtlev[levcount] = mm;
75: if (++levcount >= MONRANGE)
76: break;
77: }
78: }
79: if (levcount == 0) /* if no monsters are possible */
80: mtlev[0] = &monsters[MAXMONS]; /* then asmodeus 'A' */
81: }
82:
83: /*
84: * new_monster:
85: * Pick a new monster and add it to the list
86: */
87: struct linked_list *
88: new_monster(char type, struct coord *cp, bool treas)
89: {
90: reg struct linked_list *item;
91: reg struct thing *tp;
92: reg struct monster *mp;
93: reg struct stats *st;
94: float killexp; /* experience gotten for killing him */
95:
96: item = new_item(sizeof(struct thing));
97: attach(mlist, item);
98: tp = THINGPTR(item);
99: st = &tp->t_stats;
100: mp = &monsters[type]; /* point to this monsters structure */
101: tp->t_type = mp->m_show;
102: tp->t_indx = type;
103: tp->t_pos = *cp;
104: tp->t_room = roomin(cp);
105: tp->t_oldch = mvwinch(cw, cp->y, cp->x);
106: tp->t_nomove = 0;
107: tp->t_nocmd = 0;
108: mvwaddch(mw, cp->y, cp->x, tp->t_type);
109:
110: /*
111: * copy monster data
112: */
113: tp->t_stats = mp->m_stats;
114:
115: /*
116: * If below amulet level, make the monsters meaner the
117: * deeper the hero goes.
118: */
119: if (level > AMLEVEL)
120: st->s_lvl += ((level - AMLEVEL) / 4);
121:
122: /*
123: * If monster in treasure room, then tougher.
124: */
125: if (treas)
126: st->s_lvl += 1;
127: if (levtype == MAZELEV)
128: st->s_lvl += 1;
129: /*
130: * If the hero is going back up, then the monsters are more
131: * prepared for him, so tougher.
132: */
133: if (goingup())
134: st->s_lvl += 1;
135:
136: /*
137: * Get hit points for monster depending on his experience
138: */
139: st->s_hpt = roll(st->s_lvl, 8);
140: st->s_maxhp = st->s_hpt;
141: /*
142: * Adjust experience point we get for killing it by the
143: * strength of this particular monster by ~~ +- 50%
144: */
145: killexp = mp->m_stats.s_exp * (0.47 + (float)st->s_hpt /
146: (8 * (float)st->s_lvl));
147:
148: st->s_exp = killexp; /* use float for accuracy */
149: if(st->s_exp < 1)
150: st->s_exp = 1; /* minimum 1 experience point */
151: tp->t_flags = mp->m_flags;
152: /*
153: * If monster in treasure room, then MEAN
154: */
155: if (treas || levtype == MAZELEV)
156: tp->t_flags |= ISMEAN;
157: tp->t_turn = TRUE;
158: tp->t_pack = NULL;
159: /*
160: * Dont wander if treas room
161: */
162: if (iswearing(R_AGGR) && !treas)
163: runto(cp, &hero);
164: if (tp->t_type == 'M') {
165: char mch;
166:
167: if (tp->t_pack != NULL)
168: mch = (OBJPTR(tp->t_pack))->o_type;
169: else {
170: switch (rnd(level >= AMLEVEL ? 9 : 8)) {
171: case 0: mch = GOLD;
172: when 1: mch = POTION;
173: when 2: mch = SCROLL;
174: when 3: mch = STAIRS;
175: when 4: mch = WEAPON;
176: when 5: mch = ARMOR;
177: when 6: mch = RING;
178: when 7: mch = STICK;
179: when 8: mch = AMULET;
180: }
181: }
182: if (treas)
183: mch = 'M'; /* no disguise in treasure room */
184: tp->t_disguise = mch;
185: }
186: return item;
187: }
188:
189: /*
190: * wanderer:
191: * A wandering monster has awakened and is headed for the player
192: */
193: void
194: wanderer(void)
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(int y, int x)
221: {
222: reg struct thing *tp;
223: reg struct linked_list *it;
224: reg struct room *rp;
225: reg char ch;
226: bool treas = FALSE;
227:
228: if ((it = find_mons(y, x)) == NULL)
229: return NULL;
230: tp = THINGPTR(it);
231: ch = tp->t_type;
232: /*
233: * Every time he sees mean monster, it might start chasing him
234: */
235: rp = player.t_room;
236: if (rp != NULL && rf_on(rp,ISTREAS)) {
237: tp->t_flags &= ~ISHELD;
238: treas = TRUE;
239: }
240: if (treas || (rnd(100) > 33 && on(*tp,ISMEAN) && off(*tp,ISHELD) &&
241: !iswearing(R_STEALTH))) {
242: tp->t_dest = &hero;
243: tp->t_flags |= ISRUN;
244: }
245: if (ch == 'U' && pl_off(ISBLIND)) {
246: if ((rp != NULL && !rf_on(rp,ISDARK) && levtype != MAZELEV)
247: || DISTANCE(y, x, hero.y, hero.x) < 3) {
248: if (off(*tp,ISFOUND) && !save(VS_PETRIFICATION)
249: && !iswearing(R_SUSAB) && pl_off(ISINVINC)) {
250: msg("The umber hulk's gaze has confused you.");
251: if (pl_on(ISHUH))
252: lengthen(unconfuse,rnd(20)+HUHDURATION);
253: else
254: fuse(unconfuse,TRUE,rnd(20)+HUHDURATION);
255: player.t_flags |= ISHUH;
256: }
257: tp->t_flags |= ISFOUND;
258: }
259: }
260: /*
261: * Hide invisible monsters
262: */
263: if ((tp->t_flags & ISINVIS) && pl_off(CANSEE))
264: ch = mvinch(y, x);
265: /*
266: * Let greedy ones guard gold
267: */
268: if (on(*tp, ISGREED) && off(*tp, ISRUN)) {
269: if (rp != NULL && rp->r_goldval) {
270: tp->t_dest = &rp->r_gold;
271: tp->t_flags |= ISRUN;
272: }
273: }
274: return it;
275: }
276:
277: /*
278: * genocide:
279: * Eradicate a monster forevermore
280: */
281: void
282: genocide(void)
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: void
335: unhold(char whichmon)
336: {
337: struct linked_list *item;
338: struct thing *mon;
339:
340: switch (whichmon) {
341: case 'F':
342: fung_hit = 0;
343: for (item = mlist; item != NULL; item = next(item)) {
344: mon = THINGPTR(item);
345: if (mon->t_type == 'F')
346: strcpy(mon->t_stats.s_dmg, "000d0");
347: }
348: case 'd':
349: player.t_flags &= ~ISHELD;
350: }
351: }
352:
353: /*
354: * midx:
355: * This returns an index to 'whichmon'
356: */
357: int
358: midx(char whichmon)
359: {
360: if (isupper(whichmon))
361: return(whichmon - 'A'); /* 0 to 25 for uppercase */
362: else if (islower(whichmon))
363: return(whichmon - 'a' + 26); /* 26 to 51 for lowercase */
364: else
365: return(MAXMONS); /* 52 for Asmodeus */
366: }
367:
368: /*
369: * monhurt:
370: * See when monster should run or fight. Return
371: * TRUE if hit points less than acceptable.
372: */
373: bool
374: monhurt(struct thing *th)
375: {
376: reg int ewis, crithp, f1, f2;
377: reg struct stats *st;
378:
379: st = &th->t_stats;
380: ewis = st->s_ef.a_wis;
381: if (ewis <= MONWIS) /* stupid monsters dont know */
382: return FALSE;
383: f1 = st->s_maxhp / 4; /* base hpt for being hurt */
384: f2 = (ewis - MONWIS) * 5 / 3; /* bonus for smart monsters */
385: if (th->t_flags & ISWOUND) /* if recovering from being */
386: f1 *= 2; /* wounded, then double the base */
387: crithp = f1 + f2; /* get critical hpt for hurt */
388: if (crithp > st->s_maxhp) /* only up to max hpt */
389: crithp = st->s_maxhp;
390: if (st->s_hpt < crithp) /* if < critical, then still hurt */
391: return TRUE;
392: return FALSE;
393: }
CVSweb