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)