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) | |
370 a_missile->o_which = SILVERARROW; | |
371 else | |
372 a_missile->o_which = ARROW; | |
373 } | |
374 else if ((strcmp(mp->m_name, "dwarf") == 0) || | |
375 (strcmp(mp->m_name, "kazad dwarf") == 0)) | |
376 { | |
377 thrower->o_which = CROSSBOW; | |
378 a_missile->o_which = BOLT; | |
379 } | |
380 else if (on(*tp, ISSMALL)) | |
381 { | |
382 switch (rnd(3)) | |
383 { | |
384 case 0: | |
385 thrower->o_which = SLING; | |
386 a_missile->o_which = BULLET; | |
387 break; | |
388 default: | |
389 thrower->o_which = SLING; | |
390 a_missile->o_which = ROCK; | |
391 } | |
392 } | |
393 else if (on(*tp, ISLARGE)) | |
394 { | |
395 switch (rnd(4)) | |
396 { | |
397 case 0: | |
398 thrower->o_which = CROSSBOW; | |
399 a_missile->o_which = BOLT; | |
400 break; | |
401 | |
402 case 1: | |
403 thrower->o_which = FOOTBOW; | |
404 a_missile->o_which = FBBOLT; | |
405 break; | |
406 | |
407 default: | |
408 thrower->o_which = BOW; | |
409 | |
410 if (rnd(5) == 0) | |
411 a_missile->o_which = FLAMEARROW; | |
412 else | |
413 a_missile->o_which = ARROW; | |
414 | |
415 break; | |
416 } | |
417 } | |
418 else | |
419 { | |
420 switch (rnd(6)) | |
421 { | |
422 case 1: | |
423 thrower->o_which = SLING; | |
424 a_missile->o_which = ROCK; | |
425 break; | |
426 | |
427 case 2: | |
428 thrower->o_which = CROSSBOW; | |
429 a_missile->o_which = BOLT; | |
430 break; | |
431 | |
432 case 3: | |
433 thrower->o_which = FOOTBOW; | |
434 a_missile->o_which = FBBOLT; | |
435 break; | |
436 | |
437 case 4: | |
438 thrower->o_which = BOW; | |
439 a_missile->o_which = ARROW; | |
440 break; | |
441 | |
442 default: | |
443 thrower->o_which = SLING; | |
444 a_missile->o_which = BULLET; | |
445 break; | |
446 } | |
447 } | |
448 | |
449 init_weapon(thrower, thrower->o_which); | |
450 init_weapon(a_missile, a_missile->o_which); | |
451 | |
452 attach(tp->t_pack, thrower_item); | |
453 attach(tp->t_pack, missile_item); | |
454 } | |
455 | |
456 /* monsters that wield weapons */ | |
457 | |
458 if (on(*tp, CANWIELD)) | |
459 { | |
460 if (max_monster || rnd(3)) | |
461 { | |
462 struct linked_list *wield_item; | |
463 struct object *wielded; | |
464 | |
465 wield_item = new_item(sizeof *wielded); | |
466 wielded = OBJPTR(wield_item); | |
467 carried_weapon(tp, wielded); | |
468 | |
469 i = rnd(CLAYMORE - CLUB) + rnd(2 * tp->t_stats.s_lvl); | |
470 i = min(i, CLAYMORE); | |
471 wielded->o_which = i; | |
472 init_weapon(wielded, wielded->o_which); | |
473 | |
474 /* Is it too heavy? */ | |
475 | |
476 if (itemweight(wielded) > 8 * tp->t_stats.s_str) | |
477 discard(wield_item); | |
478 else | |
479 attach(tp->t_pack, wield_item); | |
480 } | |
481 } | |
482 | |
483 if (is_wearing(R_AGGR)) | |
484 chase_it(cp, &player); | |
485 else | |
486 { | |
487 turn_off(*tp, ISRUN); | |
488 | |
489 if (on(*tp, ISFLEE) && (rnd(4) == 0)) | |
490 turn_off(*tp, ISFLEE); | |
491 | |
492 if (rnd(luck) == 0) | |
493 switch (player.t_ctype) | |
494 { | |
495 case C_MAGICIAN: | |
496 case C_ILLUSION: | |
497 eff_intel = 2 * pstats.s_intel; | |
498 break; | |
499 case C_DRUID: | |
500 eff_intel = 2 * pstats.s_intel; | |
501 case C_RANGER: | |
502 eff_charisma = 2 * pstats.s_charisma; | |
503 break; | |
504 case C_ASSASIN: | |
505 case C_THIEF: | |
506 case C_NINJA: | |
507 eff_charisma = pstats.s_charisma / 2; | |
508 break; | |
509 } | |
510 | |
511 /* LOWFRIENDLY monsters might be friendly */ | |
512 | |
513 i = roll(1,100); | |
514 | |
515 if (i == 0 || (on(*tp, LOWFRIENDLY) && i < eff_charisma) || | |
516 (on(*tp, MEDFRIENDLY) && i < 3 * eff_charisma) || | |
517 (on(*tp, HIGHFRIENDLY) && i < 5 * eff_charisma)) | |
518 { | |
519 turn_on(*tp, ISFRIENDLY); | |
520 turn_off(*tp, ISMEAN); | |
521 } | |
522 | |
523 i = roll(1,100); | |
524 | |
525 if (i == 0 || (on(*tp, LOWCAST) && i < eff_intel) || | |
526 (on(*tp, MEDCAST) && i < 3 * eff_intel) || | |
527 (on(*tp, HIGHCAST) && i < 5 * eff_intel)) | |
528 { | |
529 turn_on(*tp, CANCAST); | |
530 } | |
531 | |
532 if (on(*tp, ISDISGUISE)) | |
533 { | |
534 char mch = 0; | |
535 | |
536 if (tp->t_pack != NULL) | |
537 mch = (OBJPTR(tp->t_pack))->o_type; | |
538 else | |
539 switch (rnd(level > arts[0].ar_level ? 10 : 9)) | |
540 { | |
541 case 0: mch = GOLD; break; | |
542 case 1: mch = POTION; break; | |
543 case 2: mch = SCROLL; break; | |
544 case 3: mch = FOOD; break; | |
545 case 4: mch = WEAPON; break; | |
546 case 5: mch = ARMOR; break; | |
547 case 6: mch = RING; break; | |
548 case 7: mch = STICK; break; | |
549 case 8: mch = monsters[randmonster(NOWANDER, NOGRAB)].m_appear; | |
550 break; | |
551 case 9: mch = ARTIFACT; break; | |
552 } | |
553 | |
554 tp->t_disguise = mch; | |
555 } | |
556 } | |
557 } | |
558 | |
559 /* | |
560 wanderer() | |
561 A wandering monster has awakened and is headed for the player | |
562 */ | |
563 | |
564 void | |
565 wanderer(void) | |
566 { | |
567 int i, cnt = 0; | |
568 struct room *hr = roomin(hero); | |
569 struct linked_list *item; | |
570 struct thing *tp; | |
571 coord cp; | |
572 char *loc; | |
573 int which; | |
574 | |
575 /* Find a place for it -- avoid the player's room */ | |
576 | |
577 do | |
578 { | |
579 do | |
580 { | |
581 cnt++; | |
582 i = rnd_room(); | |
583 } | |
584 while (!(hr != &rooms[i] || levtype == MAZELEV | |
585 || levtype == THRONE || cnt > 5000)); | |
586 | |
587 rnd_pos(&rooms[i], &cp); | |
588 } | |
589 while(!step_ok(cp.y, cp.x, NOMONST, NULL)); | |
590 | |
591 /* Create a new wandering monster */ | |
592 | |
593 item = new_item(sizeof *tp); | |
594 which = randmonster(TRUE, FALSE); | |
595 new_monster(item, which, &cp, FALSE); | |
596 | |
597 tp = THINGPTR(item); | |
598 tp->t_pos = cp; /* Assign the position to the monster */ | |
599 | |
600 chase_it(&tp->t_pos, &player); | |
601 | |
602 i = rnd(7); | |
603 | |
604 if (on(*tp, ISSWARM) && i < 5) | |
605 cnt = roll(2, 4); | |
606 else if (on(*tp, ISFLOCK) && i < 5) | |
607 cnt = roll(1, 4); | |
608 else | |
609 cnt = 0; | |
610 | |
611 for (i = 1; i <= cnt; i++) | |
612 { | |
613 struct linked_list *ip = creat_mons(tp, which, NOMESSAGE); | |
614 | |
615 if (ip != NULL) | |
616 { | |
617 struct thing *mp = THINGPTR(ip); | |
618 | |
619 if (on(*tp, ISFRIENDLY)) | |
620 turn_on(*mp, ISFRIENDLY); | |
621 else | |
622 turn_off(*mp, ISFRIENDLY); | |
623 } | |
624 } | |
625 | |
626 if (cnt > 0) | |
627 { | |
628 if (on(*tp, LOWCAST) || on(*tp, MEDCAST) || on(*tp, HIGHCAST)) | |
629 turn_on(*tp, CANCAST); | |
630 | |
631 tp->t_stats.s_hpt += roll(2, 8); | |
632 tp->t_stats.s_lvl += roll(2, 3); | |
633 tp->t_stats.s_arm -= roll(1, 6); | |
634 tp->t_stats.s_str += roll(2, 3); | |
635 tp->t_stats.s_intel += roll(2, 3); | |
636 tp->t_stats.s_exp += roll(2, 8) * monsters[which].m_add_exp; | |
637 } | |
638 | |
639 i = DISTANCE(cp, hero); | |
640 | |
641 if (i < 20) | |
642 loc = "very close to you"; | |
643 else if (i < 400) | |
644 loc = "nearby"; | |
645 else | |
646 loc = "in the distance"; | |
647 | |
648 if (wizard) | |
649 msg("Started a wandering %s.", monsters[tp->t_index].m_name); | |
650 else if (on(*tp, ISUNDEAD) && (player.t_ctype == C_CLERIC || | |
651 player.t_ctype == C_PALADIN || is_wearing(R_PIETY))) | |
652 msg("You sense a new ungodly monster %s.", loc); | |
653 else if (on(player, CANHEAR) || (player.t_ctype == C_THIEF && | |
654 rnd(20) == 0)) | |
655 msg("You hear a new %s moving %s.", | |
656 monsters[tp->t_index].m_name, loc); | |
657 else if (on(player, CANSCENT) || (player.t_ctype == C_THIEF && | |
658 rnd(20) == 0)) | |
659 msg("You smell a new %s %s.", monsters[tp->t_index].m_name, | |
660 loc); | |
661 } | |
662 | |
663 /* | |
664 wake_monster | |
665 | |
666 what to do when the hero steps next to a monster | |
667 */ | |
668 | |
669 struct linked_list * | |
670 wake_monster(int y, int x) | |
671 { | |
672 struct thing *tp; | |
673 struct linked_list *it; | |
674 struct room *trp; | |
675 char *mname; | |
676 | |
677 if ((it = find_mons(y, x)) == NULL) | |
678 { | |
679 debug("Can't find monster in show."); | |
680 return(NULL); | |
681 } | |
682 | |
683 tp = THINGPTR(it); | |
684 | |
685 if ((good_monster(*tp)) || on(player, SUMMONING)) | |
686 { | |
687 chase_it(&tp->t_pos, &player); | |
688 turn_off(*tp, ISINVIS); | |
689 turn_off(*tp, CANSURPRISE); | |
690 return(it); | |
691 } | |
692 | |
693 trp = roomin(tp->t_pos); /* Current room for monster */ | |
694 mname = monsters[tp->t_index].m_name; | |
695 | |
696 /* Let greedy ones guard gold */ | |
697 | |
698 if (on(*tp, ISGREED) && off(*tp, ISRUN)) | |
699 if ((trp != NULL) && (lvl_obj != NULL)) | |
700 { | |
701 struct linked_list *item; | |
702 struct object *cur; | |
703 | |
704 for (item = lvl_obj; item != NULL; item = next(item)) | |
705 { | |
706 cur = OBJPTR(item); | |
707 | |
708 if ((cur->o_type == GOLD) && | |
709 (roomin(cur->o_pos) == trp)) | |
710 { | |
711 /* Run to the gold */ | |
712 tp->t_horde = cur; | |
713 turn_on(*tp, ISRUN); | |
714 turn_off(*tp, ISDISGUISE); | |
715 tp->t_ischasing = FALSE; | |
716 /* Make it worth protecting */ | |
717 cur->o_count += roll(2, 3) * GOLDCALC; | |
718 break; | |
719 } | |
720 } | |
721 } | |
722 | |
723 /* | |
724 * Every time he sees mean monster, it might start chasing him unique | |
725 * monsters always do | |
726 */ | |
727 | |
728 if ( (on(*tp, ISUNIQUE)) || | |
729 ( (rnd(100) > 33) && | |
730 on(*tp, ISMEAN) && | |
731 off(*tp, ISHELD) && | |
732 off(*tp, ISRUN) && | |
733 !is_stealth(&player) && | |
734 (off(player, ISINVIS) || on(*tp, CANSEE)) | |
735 ) | |
736 ) | |
737 { | |
738 chase_it(&tp->t_pos, &player); | |
739 } | |
740 | |
741 /* Handle gaze attacks */ | |
742 | |
743 if (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x) && | |
744 off(player, ISINVIS)) | |
745 { | |
746 if (on(*tp, CANHUH)) /* Confusion */ | |
747 { | |
748 if (on(player, CANREFLECT)) | |
749 { | |
750 msg("You reflect the bewildering stare of the %s.", mname); | |
751 | |
752 if (save_throw(VS_MAGIC, tp)) | |
753 { | |
754 msg("The %s is confused!", mname); | |
755 turn_on(*tp, ISHUH); | |
756 } | |
757 else | |
758 msg("The %s staggers for a moment.", mname); | |
759 } | |
760 else if (save(VS_MAGIC)) | |
761 { | |
762 msg("You feel dizzy for a moment, but it quickly passes."); | |
763 | |
764 if (rnd(100) < 67) | |
765 turn_off(*tp, CANHUH); | |
766 } | |
767 else if (off(player, ISCLEAR)) | |
768 { | |
769 if (off(player, ISHUH)) | |
770 { | |
771 light_fuse(FUSE_UNCONFUSE, 0, rnd(20) + HUHDURATION, AFTER); | |
772 msg("The %s's gaze has confused you.", mname); | |
773 turn_on(player, ISHUH); | |
774 } | |
775 else | |
776 lengthen_fuse(FUSE_UNCONFUSE, rnd(20) + HUHDURATION); | |
777 } | |
778 } | |
779 | |
780 if (on(*tp, CANSNORE)) /* Sleep */ | |
781 { | |
782 if (on(player, CANREFLECT)) | |
783 { | |
784 msg("You reflect the lethargic glance of the %s", mname); | |
785 | |
786 if (save_throw(VS_PARALYZATION, tp)) | |
787 { | |
788 msg("The %s falls asleep!", mname); | |
789 tp->t_no_move += SLEEPTIME; | |
790 } | |
791 } | |
792 else if (no_command == 0 && !save(VS_PARALYZATION)) | |
793 { | |
794 if (is_wearing(R_ALERT)) | |
795 msg("You feel slightly drowsy for a moment."); | |
796 else | |
797 { | |
798 msg("The %s's gaze puts you to sleep.", mname); | |
799 no_command = SLEEPTIME; | |
800 | |
801 if (rnd(100) < 50) | |
802 turn_off(*tp, CANSNORE); | |
803 } | |
804 } | |
805 } | |
806 | |
807 if (on(*tp, CANFRIGHTEN)) /* Fear */ | |
808 { | |
809 turn_off(*tp, CANFRIGHTEN); | |
810 | |
811 if (on(player, CANREFLECT)) | |
812 { | |
813 msg("The %s sees its reflection. ", mname); | |
814 | |
815 if (save_throw(VS_MAGIC,tp)) | |
816 { | |
817 msg("The %s is terrified by its reflection!", mname); | |
818 turn_on(*tp, ISFLEE); | |
819 } | |
820 } | |
821 else | |
822 { | |
823 if (!save(VS_WAND) && !(on(player, ISFLEE) && | |
824 (player.t_chasee==tp))) | |
825 { | |
826 if ((player.t_ctype != C_PALADIN) && | |
827 off(player, SUPERHERO)) | |
828 { | |
829 turn_on(player, ISFLEE); | |
830 player.t_ischasing = FALSE; | |
831 player.t_chasee = tp; | |
832 msg("The sight of the %s terrifies you.", mname); | |
833 } | |
834 else | |
835 msg("My, the %s looks ugly.", mname); | |
836 } | |
837 } | |
838 } | |
839 | |
840 if (on(*tp, LOOKSLOW)) /* Slow */ | |
841 { | |
842 turn_off(*tp, LOOKSLOW); | |
843 | |
844 if (on(player, CANREFLECT)) | |
845 { | |
846 msg("You reflect the mournful glare of the %s.", mname); | |
847 | |
848 if (save_throw(VS_MAGIC,tp)) | |
849 { | |
850 msg("The %s is slowing down!", mname); | |
851 turn_on(*tp, ISSLOW); | |
852 } | |
853 } | |
854 else if (is_wearing(R_FREEDOM) || save(VS_MAGIC)) | |
855 msg("You feel run-down for a moment."); | |
856 else | |
857 { | |
858 if (on(player, ISHASTE)) /* Already sped up */ | |
859 { | |
860 extinguish_fuse(FUSE_NOHASTE); | |
861 nohaste(NULL); | |
862 } | |
863 else | |
864 { | |
865 msg("You feel yourself moving %sslower.", | |
866 on(player, ISSLOW) ? "even " : ""); | |
867 | |
868 if (on(player, ISSLOW)) | |
869 lengthen_fuse(FUSE_NOSLOW, rnd(4) + 4); | |
870 else | |
871 { | |
872 turn_on(player, ISSLOW); | |
873 player.t_turn = TRUE; | |
874 light_fuse(FUSE_NOSLOW, 0, rnd(4) + 4, AFTER); | |
875 } | |
876 } | |
877 } | |
878 } | |
879 | |
880 if (on(*tp, CANBLIND)) /* Blinding */ | |
881 { | |
882 turn_off(*tp, CANBLIND); | |
883 | |
884 if (on(player, CANREFLECT)) | |
885 { | |
886 msg("You reflect the blinding stare of the %s.", mname); | |
887 | |
888 if (save_throw(VS_WAND, tp)) | |
889 { | |
890 msg("The %s is blinded!", mname); | |
891 turn_on(*tp, ISHUH); | |
892 } | |
893 } | |
894 else if (off(player, ISBLIND)) | |
895 if (save(VS_WAND) || is_wearing(R_TRUESEE) || is_wearing(R_SEEINVIS)) | |
896 msg("Your eyes film over for a moment."); | |
897 else | |
898 { | |
899 msg("The gaze of the %s blinds you.", mname); | |
900 turn_on(player, ISBLIND); | |
901 light_fuse(FUSE_SIGHT, 0, rnd(30) + 20, AFTER); | |
902 look(FALSE); | |
903 } | |
904 } | |
905 | |
906 if (on(*tp, LOOKSTONE)) /* Stoning */ | |
907 { | |
908 turn_off(*tp, LOOKSTONE); | |
909 | |
910 if (on(player, CANREFLECT)) | |
911 { | |
912 msg("You reflect the flinty look of the %s.", mname); | |
913 | |
914 if (save_throw(VS_PETRIFICATION,tp)) | |
915 { | |
916 msg("The %s suddenly stiffens", mname); | |
917 tp->t_no_move += STONETIME; | |
918 } | |
919 else | |
920 { | |
921 msg("The %s is turned to stone!", mname); | |
922 killed(&player, it, NOMESSAGE, POINTS); | |
923 } | |
924 } | |
925 else | |
926 { | |
927 if (on(player, CANINWALL)) | |
928 msg("The %s cannot focus on you.", mname); | |
929 else | |
930 { | |
931 msg("The gaze of the %s stiffens your limbs.", mname); | |
932 | |
933 if (save(VS_PETRIFICATION)) | |
934 no_command = STONETIME; | |
935 else if (rnd(100)) | |
936 no_command = STONETIME * 3; | |
937 else | |
938 { | |
939 msg("The gaze of the %s petrifies you.", mname); | |
940 msg("You are turned to stone!!! --More--"); | |
941 wait_for(' '); | |
942 death(D_PETRIFY); | |
943 return(it); | |
944 } | |
945 } | |
946 } | |
947 } | |
948 } | |
949 | |
950 /* | |
951 * True Sight sees all Never see ISINWALL or CANSURPRISE See ISSHADOW | |
952 * 80% See ISINVIS with See Invisibilty | |
953 */ | |
954 | |
955 if (off(player, CANTRUESEE) && | |
956 on(*tp, ISINWALL) || on(*tp, CANSURPRISE) || | |
957 (on(*tp, ISSHADOW) && rnd(100) < 80) || | |
958 (on(*tp, ISINVIS) && off(player, CANSEE))) | |
959 { | |
960 /* | |
961 TODO: incomplete - need to finish logic | |
962 int ch = mvwinch(stdscr, y, x); | |
963 */ | |
964 } | |
965 | |
966 | |
967 /* hero might be able to hear or smell monster if he can't see it */ | |
968 | |
969 if ((rnd(player.t_ctype == C_THIEF ? 40 : 200) == 0 || | |
970 on(player, CANHEAR)) && !cansee(tp->t_pos.y, tp->t_pos.x)) | |
971 msg("You hear a %s nearby.", mname); | |
972 else if ((rnd(player.t_ctype == C_THIEF ? 40 : 200) == 0 || | |
973 on(player, CANSCENT)) && !cansee(tp->t_pos.y, tp->t_pos.x)) | |
974 msg("You smell a %s nearby.", mname); | |
975 | |
976 return(it); | |
977 } | |
978 | |
979 /* | |
980 genocide() | |
981 wipe out hated monsters flags: ISBLESSED, ISCURSED | |
982 */ | |
983 | |
984 void | |
985 genocide(int flags) | |
986 { | |
987 struct linked_list *ip; | |
988 struct thing *mp; | |
989 struct linked_list *nip; | |
990 int which_monst; | |
991 int blessed = flags & ISBLESSED; | |
992 int cursed = flags & ISCURSED; | |
993 | |
994 while ((which_monst = get_monster_number("genocide")) == 0) | |
995 ; | |
996 | |
997 if (cursed) /* oops... */ | |
998 { | |
999 new_level(THRONE, which_monst); | |
1000 msg("What's this I hear about you trying to wipe me out?"); | |
1001 fighting = running = after = FALSE; | |
1002 return; | |
1003 } | |
1004 | |
1005 /* Remove this monster from the present level */ | |
1006 | |
1007 for (ip = mlist; ip; ip = nip) | |
1008 { | |
1009 mp = THINGPTR(ip); | |
1010 nip = next(ip); | |
1011 | |
1012 if (mp->t_index == which_monst) | |
1013 { | |
1014 check_residue(mp); /* Check for special features before removing */ | |
1015 remove_monster(&mp->t_pos, ip); | |
1016 } | |
1017 } | |
1018 | |
1019 /* Remove from available monsters */ | |
1020 | |
1021 monsters[which_monst].m_normal = FALSE; | |
1022 monsters[which_monst].m_wander = FALSE; | |
1023 mpos = 0; | |
1024 msg("You have wiped out the %s.", monsters[which_monst].m_name); | |
1025 | |
1026 if (blessed) | |
1027 genocide(ISNORMAL); | |
1028 } | |
1029 | |
1030 | |
1031 /* | |
1032 id_monst() | |
1033 lists the monsters with the displayed by the character unless | |
1034 there is only one in which case it is returned as the string | |
1035 */ | |
1036 | |
1037 void | |
1038 id_monst(int monster) | |
1039 { | |
1040 int i; | |
1041 | |
1042 for (i = 1; i <= nummonst + 2; i++) | |
1043 if (monsters[i].m_appear == monster) | |
1044 add_line("A %s ", monsters[i].m_name); | |
1045 | |
1046 end_line(); | |
1047 } | |
1048 | |
1049 | |
1050 /* | |
1051 check_residue() | |
1052 takes care of any effect of the monster | |
1053 */ | |
1054 | |
1055 void | |
1056 check_residue(struct thing *tp) | |
1057 { | |
1058 /* Take care of special abilities */ | |
1059 | |
1060 if (on(*tp, DIDHOLD) && (--hold_count == 0)) | |
1061 turn_off(player, ISHELD); | |
1062 | |
1063 /* If it has lowered player, give him back a level, maybe */ | |
1064 | |
1065 if (on(*tp, DIDDRAIN) && rnd(3) == 0) | |
1066 raise_level(); | |
1067 | |
1068 /* If frightened of this monster, stop */ | |
1069 | |
1070 if (on(player, ISFLEE) && (player.t_chasee==tp)) | |
1071 turn_off(player, ISFLEE); | |
1072 | |
1073 /* If monster was suffocating player, stop it */ | |
1074 if (on(*tp, DIDSUFFOCATE)) | |
1075 extinguish_fuse(FUSE_SUFFOCATE); | |
1076 | |
1077 /* If something with fire, may darken */ | |
1078 if (on(*tp, HASFIRE)) | |
1079 { | |
1080 struct room *rp = roomin(tp->t_pos); | |
1081 | |
1082 if (rp && (--(rp->r_fires) <= 0)) | |
1083 { | |
1084 rp->r_flags &= ~HASFIRE; | |
1085 light(&tp->t_pos); | |
1086 } | |
1087 } | |
1088 } | |
1089 | |
1090 /* | |
1091 sell() | |
1092 displays a menu of goods from which the player may choose to | |
1093 purchase something. | |
1094 */ | |
1095 | |
1096 #define SELL_ITEMS 10 /* How many things 'q' might carry */ | |
1097 | |
1098 void | |
1099 sell(struct thing *tp) | |
1100 { | |
1101 struct linked_list *item; | |
1102 int i, j, min_worth, nitems, chance, which_item, w; | |
1103 char goods; | |
1104 struct object *obj; | |
1105 char buffer[2 * LINELEN]; | |
1106 char dbuf[2 * LINELEN]; | |
1107 | |
1108 struct | |
1109 { | |
1110 int which; | |
1111 int plus1, plus2; | |
1112 int count; | |
1113 int worth; | |
1114 int flags; | |
1115 char *name; | |
1116 } | |
1117 selection[SELL_ITEMS]; | |
1118 | |
1119 int effective_purse = ((player.t_ctype == C_PALADIN) ? | |
1120 (9 * purse / 10) : purse); | |
1121 | |
1122 min_worth = -1; /* hope item is never worth less than this */ | |
1123 item = find_mons(tp->t_pos.y, tp->t_pos.x); /* Get pointer to monster */ | |
1124 | |
1125 /* Select the items */ | |
1126 | |
1127 nitems = rnd(6) + 5; | |
1128 | |
1129 switch (rnd(6)) | |
1130 { | |
1131 /* Armor */ | |
1132 case 0: | |
1133 case 1: | |
1134 goods = ARMOR; | |
1135 for (i = 0; i < nitems; i++) | |
1136 { | |
1137 chance = rnd(100); | |
1138 | |
1139 for (j = 0; j < maxarmors; j++) | |
1140 if (chance < armors[j].a_prob) | |
1141 break; | |
1142 | |
1143 if (j == maxarmors) | |
1144 { | |
1145 debug("Picked a bad armor %d", chance); | |
1146 j = 0; | |
1147 } | |
1148 | |
1149 selection[i].which = j; | |
1150 selection[i].count = 1; | |
1151 | |
1152 if (rnd(100) < 40) | |
1153 selection[i].plus1 = rnd(5) + 1; | |
1154 else | |
1155 selection[i].plus1 = 0; | |
1156 | |
1157 selection[i].name = armors[j].a_name; | |
1158 | |
1159 switch (luck) | |
1160 { | |
1161 case 0: break; | |
1162 case 1: | |
1163 if (rnd(3) == 0) | |
1164 { | |
1165 selection[i].flags |= ISCURSED; | |
1166 selection[i].plus1 = -1 - rnd(5); | |
1167 } | |
1168 break; | |
1169 | |
1170 default: | |
1171 if (rnd(luck)) | |
1172 { | |
1173 selection[i].flags |= ISCURSED; | |
1174 selection[i].plus1 = -1 - rnd(5); | |
1175 } | |
1176 break; | |
1177 } | |
1178 | |
1179 /* Calculate price */ | |
1180 | |
1181 w = armors[j].a_worth; | |
1182 w *= (1 + luck + (10 * selection[i].plus1)); | |
1183 w = (w / 2) + (roll(6, w) / 6); | |
1184 selection[i].worth = max(w, 25); | |
1185 | |
1186 if (min_worth > selection[i].worth || i == 1) | |
1187 min_worth = selection[i].worth; | |
1188 } | |
1189 break; | |
1190 | |
1191 /* Weapon */ | |
1192 case 2: | |
1193 case 3: | |
1194 goods = WEAPON; | |
1195 for (i = 0; i < nitems; i++) | |
1196 { | |
1197 selection[i].which = rnd(maxweapons); | |
1198 selection[i].count = 1; | |
1199 | |
1200 if (rnd(100) < 35) | |
1201 { | |
1202 selection[i].plus1 = rnd(3); | |
1203 selection[i].plus2 = rnd(3); | |
1204 } | |
1205 else | |
1206 { | |
1207 selection[i].plus1 = 0; | |
1208 selection[i].plus2 = 0; | |
1209 } | |
1210 | |
1211 if (weaps[selection[i].which].w_flags & ISMANY) | |
1212 selection[i].count = rnd(15) + 8; | |
1213 | |
1214 selection[i].name = weaps[selection[i].which].w_name; | |
1215 | |
1216 switch (luck) | |
1217 { | |
1218 case 0: break; | |
1219 case 1: | |
1220 if (rnd(3) == 0) | |
1221 { | |
1222 selection[i].flags |= ISCURSED; | |
1223 selection[i].plus1 = -rnd(3); | |
1224 selection[i].plus2 = -rnd(3); | |
1225 } | |
1226 break; | |
1227 | |
1228 default: | |
1229 if (rnd(luck)) | |
1230 { | |
1231 selection[i].flags |= ISCURSED; | |
1232 selection[i].plus1 = -rnd(3); | |
1233 selection[i].plus2 = -rnd(3); | |
1234 } | |
1235 break; | |
1236 } | |
1237 | |
1238 w = weaps[selection[i].which].w_worth * selection[i].count; | |
1239 w *= (1 + luck + (10 * selection[i].plus1 + | |
1240 10 * selection[i].plus2)); | |
1241 w = (w / 2) + (roll(6, w) / 6); | |
1242 selection[i].worth = max(w, 25); | |
1243 | |
1244 if (min_worth > selection[i].worth || i == 1) | |
1245 min_worth = selection[i].worth; | |
1246 } | |
1247 break; | |
1248 | |
1249 /* Staff or wand */ | |
1250 case 4: | |
1251 goods = STICK; | |
1252 | |
1253 for (i = 0; i < nitems; i++) | |
1254 { | |
1255 selection[i].which = pick_one(ws_magic, maxsticks); | |
1256 selection[i].plus1 = rnd(11) + 5; | |
1257 selection[i].count = 1; | |
1258 selection[i].name = ws_magic[selection[i].which].mi_name; | |
1259 | |
1260 switch (luck) | |
1261 { | |
1262 case 0: break; | |
1263 case 1: | |
1264 if (rnd(3) == 0) | |
1265 { | |
1266 selection[i].flags |= ISCURSED; | |
1267 selection[i].plus1 = 1; | |
1268 } | |
1269 break; | |
1270 | |
1271 default: | |
1272 if (rnd(luck)) | |
1273 { | |
1274 selection[i].flags |= ISCURSED; | |
1275 selection[i].plus1 = 1; | |
1276 } | |
1277 } | |
1278 | |
1279 w = ws_magic[selection[i].which].mi_worth; | |
1280 w += (luck + 1) * 20 * selection[i].plus1; | |
1281 w = (w / 2) + (roll(6, w) / 6); | |
1282 selection[i].worth = max(w, 25); | |
1283 | |
1284 if (min_worth > selection[i].worth || i == 1) | |
1285 min_worth = selection[i].worth; | |
1286 } | |
1287 break; | |
1288 | |
1289 /* Ring */ | |
1290 | |
1291 case 5: | |
1292 goods = RING; | |
1293 for (i = 0; i < nitems; i++) | |
1294 { | |
1295 selection[i].which = pick_one(r_magic, maxrings); | |
1296 selection[i].plus1 = rnd(2) + 1; | |
1297 selection[i].count = 1; | |
1298 | |
1299 if (rnd(100) < r_magic[selection[i].which].mi_bless + 10) | |
1300 selection[i].plus1 += rnd(2) + 1; | |
1301 | |
1302 selection[i].name = r_magic[selection[i].which].mi_name; | |
1303 | |
1304 switch (luck) | |
1305 { | |
1306 case 0: break; | |
1307 case 1: | |
1308 if (rnd(3) == 0) | |
1309 { | |
1310 selection[i].flags |= ISCURSED; | |
1311 selection[i].plus1 = -1 - rnd(2); | |
1312 } | |
1313 break; | |
1314 | |
1315 default: | |
1316 if (rnd(luck)) | |
1317 { | |
1318 selection[i].flags |= ISCURSED; | |
1319 selection[i].plus1 = -1 - rnd(2); | |
1320 } | |
1321 } | |
1322 | |
1323 w = r_magic[selection[i].which].mi_worth; | |
1324 | |
1325 switch(selection[i].which) | |
1326 { | |
1327 case R_DIGEST: | |
1328 if (selection[i].plus1 > 2) | |
1329 selection[i].plus1 = 2; | |
1330 else if (selection[i].plus1 < 1) | |
1331 selection[i].plus1 = 1; | |
1332 /* fall thru here to other cases */ | |
1333 case R_ADDSTR: | |
1334 case R_ADDDAM: | |
1335 case R_PROTECT: | |
1336 case R_ADDHIT: | |
1337 case R_ADDINTEL: | |
1338 case R_ADDWISDOM: | |
1339 if (selection[i].plus1 > 0) | |
1340 w += selection[i].plus1 * 50; | |
1341 } | |
1342 | |
1343 w *= (1 + luck); | |
1344 w = (w / 2) + (roll(6, w) / 6); | |
1345 selection[i].worth = max(w, 25); | |
1346 | |
1347 if (min_worth > selection[i].worth * selection[i].count) | |
1348 min_worth = selection[i].worth; | |
1349 } | |
1350 } | |
1351 | |
1352 /* See if player can afford an item */ | |
1353 | |
1354 if (min_worth > effective_purse) | |
1355 { | |
1356 msg("The %s eyes your small purse and departs.", | |
1357 monsters[nummonst].m_name); | |
1358 | |
1359 /* Get rid of the monster */ | |
1360 | |
1361 killed(NULL, item, NOMESSAGE, NOPOINTS); | |
1362 | |
1363 return; | |
1364 } | |
1365 | |
1366 /* Display the goods */ | |
1367 | |
1368 msg("The %s shows you his wares.", monsters[nummonst].m_name); | |
1369 wstandout(cw); | |
1370 mvwaddstr(cw, 0, mpos, morestr); | |
1371 wstandend(cw); | |
1372 wrefresh(cw); | |
1373 wait_for(' '); | |
1374 msg(""); | |
1375 clearok(cw, TRUE); | |
1376 touchwin(cw); | |
1377 | |
1378 wclear(hw); | |
1379 touchwin(hw); | |
1380 | |
1381 for (i = 0; i < nitems; i++) | |
1382 { | |
1383 if (selection[i].worth > effective_purse) | |
1384 continue; | |
1385 | |
1386 wmove(hw, i + 2, 0); | |
1387 sprintf(dbuf, "[%c] ", ('a' + i)); | |
1388 | |
1389 switch(goods) | |
1390 { | |
1391 case ARMOR: | |
1392 strcat(dbuf, "Some "); | |
1393 break; | |
1394 case WEAPON: | |
1395 if (selection[i].count == 1) | |
1396 strcat(dbuf, "A "); | |
1397 else | |
1398 { | |
1399 sprintf(buffer, "%2d ", selection[i].count); | |
1400 strcat(dbuf, buffer); | |
1401 } | |
1402 break; | |
1403 | |
1404 case STICK: | |
1405 strcat(dbuf, "A "); | |
1406 strcat(dbuf, ws_type[selection[i].which]); | |
1407 strcat(dbuf, " of "); | |
1408 break; | |
1409 | |
1410 case RING: | |
1411 strcat(dbuf, "A ring of "); | |
1412 break; | |
1413 } | |
1414 | |
1415 strcat(dbuf, selection[i].name); | |
1416 | |
1417 if (selection[i].count > 1) | |
1418 strcat(dbuf, "s"); | |
1419 | |
1420 sprintf(buffer, "%-50s Price: %d", dbuf, selection[i].worth); | |
1421 waddstr(hw, buffer); | |
1422 } | |
1423 | |
1424 sprintf(buffer, "Purse: %d", purse); | |
1425 mvwaddstr(hw, nitems + 3, 0, buffer); | |
1426 mvwaddstr(hw, 0, 0, "How about one of the following goods? "); | |
1427 wrefresh(hw); | |
1428 | |
1429 /* Get rid of the monster */ | |
1430 | |
1431 killed(NULL, item, NOMESSAGE, NOPOINTS); | |
1432 | |
1433 which_item = (short) ((readchar() & 0177) - 'a'); | |
1434 | |
1435 while (which_item < 0 || which_item >= nitems || | |
1436 selection[which_item].worth > effective_purse) | |
1437 { | |
1438 if (which_item == (short) ESCAPE - (short) 'a') | |
1439 return; | |
1440 | |
1441 mvwaddstr(hw, 0, 0, "Please enter one of the listed items: "); | |
1442 wrefresh(hw); | |
1443 which_item = (short) ((readchar() & 0177) - 'a'); | |
1444 } | |
1445 | |
1446 if (purse > selection[which_item].worth) | |
1447 purse -= selection[which_item].worth; | |
1448 else | |
1449 purse = 0L; | |
1450 | |
1451 item = spec_item(goods, selection[which_item].which, | |
1452 selection[which_item].plus1, selection[which_item].plus2); | |
1453 | |
1454 obj = OBJPTR(item); | |
1455 | |
1456 if (selection[which_item].count > 1) | |
1457 { | |
1458 obj->o_count = selection[which_item].count; | |
1459 obj->o_group = ++group; | |
1460 } | |
1461 | |
1462 /* If a stick or ring, let player know the type */ | |
1463 | |
1464 switch (goods) | |
1465 { | |
1466 case STICK: know_items[TYP_STICK][selection[which_item].which] = TRUE; | |
1467 break; | |
1468 case RING: know_items[TYP_RING][selection[which_item].which] = TRUE; | |
1469 break; | |
1470 } | |
1471 | |
1472 if (add_pack(item, MESSAGE) == FALSE) | |
1473 { | |
1474 obj->o_pos = hero; | |
1475 fall(&player, item, TRUE, FALSE); | |
1476 } | |
1477 } | |
1478 | |
1479 void | |
1480 carried_weapon(struct thing *owner, struct object *weapon) | |
1481 { | |
1482 weapon->o_hplus = (rnd(4) < 3) ? 0 : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); | |
1483 weapon->o_dplus = (rnd(4) < 3) ? 0 : (rnd(3) + 1) * ((rnd(3) < 2) ? 1 : -1); | |
1484 weapon->o_hplus += rnd(owner->t_stats.s_lvl / 3 + 1); | |
1485 weapon->o_hplus += rnd(owner->t_stats.s_lvl / 3 + 1); | |
1486 weapon->o_damage = weapon->o_hurldmg = "0d0"; | |
1487 weapon->o_ac = 11; | |
1488 weapon->o_count = 1; | |
1489 weapon->o_group = 0; | |
1490 | |
1491 if ((weapon->o_hplus <= 0) && (weapon->o_dplus <= 0)) | |
1492 weapon->o_flags = ISCURSED; | |
1493 | |
1494 weapon->o_flags = 0; | |
1495 weapon->o_type = WEAPON; | |
1496 weapon->o_mark[0] = '\0'; | |
1497 } |