Mercurial > hg > early-roguelike
comparison urogue/monsters.c @ 256:c495a4f288c6
Import UltraRogue from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 31 Jan 2017 19:56:04 -0500 |
parents | |
children | 0250220d8cdd |
comparison
equal
deleted
inserted
replaced
253:d9badb9c0179 | 256:c495a4f288c6 |
---|---|
1 /* | |
2 monsters.c - File with various monster functions in it | |
3 | |
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom | |
5 Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong | |
6 All rights reserved. | |
7 | |
8 Based on "Advanced Rogue" | |
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka | |
10 All rights reserved. | |
11 | |
12 Based on "Rogue: Exploring the Dungeons of Doom" | |
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
14 All rights reserved. | |
15 | |
16 See the file LICENSE.TXT for full copyright and licensing information. | |
17 */ | |
18 | |
19 #include <stdlib.h> | |
20 #include <string.h> | |
21 #include <ctype.h> | |
22 #include "rogue.h" | |
23 | |
24 /* | |
25 summon_monster() | |
26 Summon a monster. | |
27 */ | |
28 | |
29 struct linked_list * | |
30 summon_monster(int type, int familiar, int print_message) | |
31 { | |
32 struct linked_list *mp; | |
33 struct thing *tp; | |
34 int monster; | |
35 | |
36 if (familiar && !is_wearing(R_WIZARD) && off(player, CANSUMMON)) | |
37 { | |
38 msg("Only spellcasters can summon familiars!"); | |
39 return(NULL); | |
40 } | |
41 | |
42 if (type == 0) /* Random monster modified by level */ | |
43 { | |
44 int ndice = min(pstats.s_lvl, (nummonst - NUMSUMMON) / 8); | |
45 | |
46 monster = min(nummonst, roll(ndice, pstats.s_charisma)); | |
47 | |
48 /* | |
49 * if a familiar exists, and it is higher in level, make it | |
50 * again | |
51 */ | |
52 | |
53 if (fam_ptr != NULL) | |
54 { | |
55 struct thing *fp = THINGPTR(fam_ptr); | |
56 | |
57 monster = max(fp->t_index, monster); | |
58 } | |
59 } | |
60 else | |
61 monster = type; | |
62 | |
63 turn_on(player, SUMMONING); | |
64 | |
65 mp = creat_mons(&player, monster, NOMESSAGE); | |
66 | |
67 if (!mp) | |
68 { | |
69 msg("Summon failed."); | |
70 turn_off(player, SUMMONING); | |
71 return(NULL); | |
72 } | |
73 | |
74 if (print_message == MESSAGE) | |
75 { | |
76 msg("A %s appears out of nowhere!", monsters[monster].m_name); | |
77 | |
78 if (familiar) | |
79 msg("I am here to serve %s.", whoami); | |
80 else | |
81 { | |
82 msg("My goodness, are you Yendor?"); | |
83 ++mons_summoned; | |
84 debug("%d monsters now summoned.", mons_summoned); | |
85 } | |
86 } | |
87 | |
88 tp = THINGPTR(mp); | |
89 turn_on(*tp, ISCHARMED); /* Summoned monsters are always charmed */ | |
90 | |
91 if (familiar) | |
92 { | |
93 int i; | |
94 static const unsigned long fam_on[]= {ISREGEN,CANSHOOT,CANWIELD,HASARMOR,ISFAMILIAR,0}; | |
95 static const unsigned long fam_off[]={ISMEAN, ISHUH, ISINVIS, | |
96 CANSURPRISE, NOMOVE, | |
97 ISSLOW, ISSHADOW, ISGREED, ISFAST, | |
98 CANFLY, ISFLEE, 0}; | |
99 | |
100 for (i = 0; fam_on[i]; i++) | |
101 turn_on(*tp, fam_on[i]); | |
102 | |
103 for (i = 0; fam_off[i]; i++) | |
104 turn_off(*tp, fam_off[i]); | |
105 | |
106 if (fam_ptr != NULL) /* Get rid of old familiar */ | |
107 { | |
108 struct thing *fp = THINGPTR(fam_ptr); | |
109 struct linked_list *fpack = fp->t_pack; | |
110 struct linked_list *item; | |
111 | |
112 if (fpack != NULL) /* Transfer pack */ | |
113 { | |
114 if (tp->t_pack == NULL) | |
115 tp->t_pack = fpack; | |
116 else | |
117 { | |
118 for(item=tp->t_pack; item->l_next != NULL; item=next(item)) | |
119 ; /* find last item in list */ | |
120 | |
121 item->l_next = fpack; | |
122 fpack->l_prev = item; | |
123 } | |
124 } | |
125 | |
126 fpack = NULL; | |
127 killed(NULL, fam_ptr, NOMESSAGE, NOPOINTS); | |
128 } | |
129 | |
130 fam_ptr = mp; | |
131 fam_type = monster; | |
132 | |
133 /* improve their abilities a bit */ | |
134 | |
135 tp->t_stats.s_hpt += roll(2, pstats.s_lvl); | |
136 tp->t_stats.s_lvl += roll(2, (pstats.s_lvl / 4) + 1); | |
137 tp->t_stats.s_arm -= roll(2, (pstats.s_lvl / 4) + 1); | |
138 tp->t_stats.s_str += roll(2, (pstats.s_lvl / 4) + 1); | |
139 tp->t_stats.s_intel += roll(2, (pstats.s_lvl / 4) + 1); | |
140 tp->t_stats.s_wisdom += roll(2, (pstats.s_lvl / 4) + 1); | |
141 tp->t_stats.s_dext += roll(2, (pstats.s_lvl / 4) + 1); | |
142 tp->t_stats.s_const += roll(2, (pstats.s_lvl / 4) + 1); | |
143 tp->t_stats.s_charisma += roll(2, (pstats.s_lvl / 4) + 1); | |
144 | |
145 /* some monsters do no damage by default */ | |
146 | |
147 if (strcmp(tp->t_stats.s_dmg, "0d0") == 0) | |
148 tp->t_stats.s_dmg = "1d8"; | |
149 | |
150 tp->maxstats = tp->t_stats; /* structure assignment */ | |
151 } | |
152 | |
153 turn_off(player, SUMMONING); | |
154 | |
155 return(mp); | |
156 } | |
157 | |
158 /* | |
159 randmonster() | |
160 wander - wandering monster allowed | |
161 grab - a throne room monster allowed | |
162 */ | |
163 | |
164 int | |
165 randmonster(int wander, int grab) | |
166 { | |
167 int mons_number, cur_level, range, i; | |
168 | |
169 /* Do we want a merchant? */ | |
170 | |
171 if (wander == WANDER && monsters[nummonst].m_wander && rnd(5000) < 3) | |
172 return(nummonst); | |
173 | |
174 cur_level = level; | |
175 range = 4 * NLEVMONS; | |
176 i = 0; | |
177 | |
178 do | |
179 { | |
180 if (i++ > range * 10) /* just in case all have be genocided */ | |
181 { | |
182 i = 0; | |
183 | |
184 if (--cur_level <= 0) | |
185 fatal("Rogue could not find a monster to make"); | |
186 } | |
187 | |
188 mons_number = NLEVMONS * (cur_level - 1) + | |
189 (rnd(range) - (range - 1 - NLEVMONS)); | |
190 | |
191 if (mons_number < 1) | |
192 mons_number = rnd(NLEVMONS) + 1; | |
193 else if (mons_number > nummonst - NUMSUMMON - 1) | |
194 { | |
195 if (grab == GRAB) | |
196 mons_number = rnd(range + NUMSUMMON) + | |
197 (nummonst - 1) - | |
198 (range + NUMSUMMON - 1); | |
199 else if (mons_number > nummonst - 1) | |
200 mons_number = rnd(range) + | |
201 (nummonst - NUMSUMMON - 1) - | |
202 (range - 1); | |
203 } | |
204 } | |
205 while (wander == WANDER ? !monsters[mons_number].m_wander || | |
206 !monsters[mons_number].m_normal : | |
207 !monsters[mons_number].m_normal); | |
208 | |
209 return((short)mons_number); | |
210 } | |
211 | |
212 /* | |
213 new_monster() | |
214 Pick a new monster and add it to the list | |
215 */ | |
216 | |
217 void | |
218 new_monster(struct linked_list *item, int type, coord *cp, int max_monster) | |
219 { | |
220 struct thing *tp; | |
221 struct monster *mp; | |
222 char *ip, *hitp; | |
223 int i, min_intel, max_intel; | |
224 int num_dice, num_sides = 8, num_extra = 0; | |
225 int eff_charisma = pstats.s_charisma; | |
226 int eff_intel = pstats.s_intel; | |
227 | |
228 attach(mlist, item); | |
229 tp = THINGPTR(item); | |
230 tp->t_index = type; | |
231 tp->t_wasshot = FALSE; | |
232 tp->t_type = monsters[type].m_appear; | |
233 tp->t_ctype = C_MONSTER; | |
234 tp->t_no_move = 0; | |
235 tp->t_doorgoal = -1; | |
236 tp->t_pos = *cp; | |
237 tp->t_oldpos = *cp; | |
238 tp->t_oldch = CCHAR( mvwinch(cw, cp->y, cp->x) ); | |
239 mvwaddch(mw, cp->y, cp->x, tp->t_type); | |
240 mp = &monsters[tp->t_index]; | |
241 | |
242 /* Figure out monster's hit points */ | |
243 | |
244 hitp = mp->m_stats.s_hpt; | |
245 num_dice = atoi(hitp); | |
246 | |
247 if ((hitp = strchr(hitp, 'd')) != NULL) | |
248 { | |
249 num_sides = atoi(++hitp); | |
250 | |
251 if ((hitp = strchr(hitp, '+')) != NULL) | |
252 num_extra = atoi(++hitp); | |
253 } | |
254 | |
255 if (max_monster == MAXSTATS) | |
256 tp->t_stats.s_hpt = num_dice * num_sides + num_extra; | |
257 else | |
258 tp->t_stats.s_hpt = roll(num_dice, num_sides) + num_extra; | |
259 | |
260 tp->t_stats.s_lvl = mp->m_stats.s_lvl; | |
261 tp->t_stats.s_arm = mp->m_stats.s_arm; | |
262 tp->t_stats.s_dmg = mp->m_stats.s_dmg; | |
263 tp->t_stats.s_exp = mp->m_stats.s_exp + mp->m_add_exp * tp->t_stats.s_hpt; | |
264 tp->t_stats.s_str = mp->m_stats.s_str; | |
265 | |
266 if (max_level > 30) | |
267 { | |
268 tp->t_stats.s_hpt += roll(4, (max_level - 60) * 2); | |
269 tp->t_stats.s_lvl += roll(4, (max_level - 60) / 8); | |
270 tp->t_stats.s_arm -= roll(2, (max_level - 60) / 8); | |
271 tp->t_stats.s_str += roll(2, (max_level - 60) / 12); | |
272 tp->t_stats.s_exp += roll(4, (max_level - 60) * 2) * mp->m_add_exp; | |
273 } | |
274 | |
275 /* | |
276 * just initailize others values to something reasonable for now | |
277 * maybe someday will *really* put these in monster table | |
278 */ | |
279 | |
280 tp->t_stats.s_wisdom = 8 + rnd(4); | |
281 tp->t_stats.s_dext = 8 + rnd(4); | |
282 tp->t_stats.s_const = 8 + rnd(4); | |
283 tp->t_stats.s_charisma = 8 + rnd(4); | |
284 | |
285 if (max_level > 45) | |
286 tp->t_stats.s_dext += roll(2, (max_level - 50) / 8); | |
287 | |
288 /* Set the initial flags */ | |
289 | |
290 for (i = 0; i < 16; i++) | |
291 tp->t_flags[i] = 0; | |
292 | |
293 for (i = 0; i < 16; i++) | |
294 turn_on(*tp, mp->m_flags[i]); | |
295 | |
296 /* suprising monsters don't always surprise you */ | |
297 | |
298 if (!max_monster && on(*tp, CANSURPRISE) && rnd(100) < 20) | |
299 turn_off(*tp, CANSURPRISE); | |
300 | |
301 /* If this monster is unique, genocide it */ | |
302 | |
303 if (on(*tp, ISUNIQUE)) | |
304 mp->m_normal = FALSE; | |
305 | |
306 /* gods automatically get special abilities */ | |
307 | |
308 if (on(*tp, ISGOD)) | |
309 { | |
310 turn_on(*tp, CANFRIGHTEN); | |
311 turn_on(*tp, CANCAST); | |
312 turn_on(*tp, CANFLY); | |
313 turn_on(*tp, CANBARGAIN); | |
314 turn_on(*tp, ISLARGE); | |
315 turn_on(*tp, CANTELEPORT); | |
316 turn_on(*tp, CANSPEAK); | |
317 turn_on(*tp, CANDARKEN); | |
318 turn_on(*tp, CANSEE); | |
319 turn_on(*tp, CANLIGHT); | |
320 turn_on(*tp, BMAGICHIT); | |
321 } | |
322 | |
323 tp->t_turn = TRUE; | |
324 tp->t_pack = NULL; | |
325 | |
326 /* Figure intelligence */ | |
327 | |
328 min_intel = atoi(mp->m_intel); | |
329 | |
330 if ((ip = (char *) strchr(mp->m_intel, '-')) == NULL) | |
331 tp->t_stats.s_intel = min_intel; | |
332 else | |
333 { | |
334 max_intel = atoi(++ip); | |
335 | |
336 if (max_monster) | |
337 tp->t_stats.s_intel = max_intel; | |
338 else | |
339 tp->t_stats.s_intel = min_intel + rnd(max_intel - min_intel); | |
340 } | |
341 | |
342 tp->t_stats.s_power = (rnd(tp->t_stats.s_lvl / 5) + 1) * tp->t_stats.s_intel; | |
343 | |
344 tp->maxstats = tp->t_stats; /* structure assignment */ | |
345 | |
346 /* If the monster can shoot, it may have a weapon */ | |
347 | |
348 if (on(*tp, CANSHOOT) && (max_monster || rnd(9) < 6)) | |
349 { | |
350 struct linked_list *thrower_item, *missile_item; | |
351 struct object *thrower, *a_missile; | |
352 | |
353 thrower_item = new_item(sizeof *thrower); | |
354 thrower = OBJPTR(thrower_item); | |
355 carried_weapon(tp, thrower); | |
356 | |
357 missile_item = new_item(sizeof *a_missile); | |
358 a_missile = OBJPTR(missile_item); | |
359 carried_weapon(tp, a_missile); | |
360 | |
361 /* The monster may use a crossbow, sling, footbow, or an arrow */ | |
362 /* Take racial preferences into account */ | |
363 | |
364 if ((strcmp(mp->m_name, "elf") == 0) || | |
365 (strcmp(mp->m_name, "noldor elf") == 0)) | |
366 { | |
367 thrower->o_which = BOW; | |
368 | |
369 if (rnd(5) == 0) | |