1 /*
2 * File: mon-util.cc
3 * Summary: Misc monster related functions.
4 * Written by: Linley Henzell
5 *
6 * Change History (most recent first):
7 *
8 * <2> 11/04/99 cdl added a break to spell selection
9 * for kobold Summoners
10 * print just "[Ii]t" for invisible undead
11 * renamed params to monam()
12 * <1> -/--/-- LRH Created
13 */
14
15 // $pellbinder: (c) D.G.S.E 1998
16 // some routines snatched from former monsstat.cc
17
18 #include "AppHdr.h"
19 #include "mon-util.h"
20 #include "monstuff.h"
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #include "externs.h"
28
29 #include "debug.h"
30 #include "itemname.h"
31 #include "mstuff2.h"
32 #include "player.h"
33 #include "randart.h"
34 #include "stuff.h"
35 #include "view.h"
36
37 //jmf: moved from inside function
38 static FixedVector < int, NUM_MONSTERS > mon_entry;
39
40 // really important extern -- screen redraws suck w/o it {dlb}
41 FixedVector < unsigned short, 1000 > mcolour;
42
43 static struct monsterentry mondata[] = {
44 #include "mon-data.h"
45 };
46
47 #define MONDATASIZE (sizeof(mondata)/sizeof(struct monsterentry))
48
49 static int mspell_list[][7] = {
50 #include "mon-spll.h"
51 };
52
53 #if DEBUG_DIAGNOSTICS
54 static const char *monster_spell_name[] = {
55 "Magic Missile",
56 "Throw Flame",
57 "Throw Frost",
58 "Paralysis",
59 "Slow",
60 "Haste",
61 "Confuse",
62 "Venom Bolt",
63 "Fire Bolt",
64 "Cold Bolt",
65 "Lightning Bolt",
66 "Invisibility",
67 "Fireball",
68 "Heal",
69 "Teleport",
70 "Teleport Other",
71 "Blink",
72 "Crystal Spear",
73 "Dig",
74 "Negative Bolt",
75 "Hellfire Burst",
76 "Vampire Summon",
77 "Orb Energy",
78 "Brain Feed",
79 "Level Summon",
80 "Fake Rakshasa Summon",
81 "Steam Ball",
82 "Summon Demon",
83 "Animate Dead",
84 "Pain",
85 "Smite",
86 "Sticky Flame",
87 "Poison Blast",
88 "Summon Demon Lesser",
89 "Summon Ufetubus",
90 "Purple Blast",
91 "Summon Beast",
92 "Energy Bolt",
93 "Sting",
94 "Iron Bolt",
95 "Stone Arrow",
96 "Poison Splash",
97 "Summon Undead",
98 "Mutation",
99 "Cantrip",
100 "Disintegrate",
101 "Marsh Gas",
102 "Quicksilver Bolt",
103 "Torment",
104 "Hellfire",
105 "Metal Splinters",
106 "Summon Demon Greater",
107 "Banishment",
108 };
109 #endif
110
111 static int mons_exp_mod(int mclass);
112 static monsterentry *seekmonster(int *p_monsterid);
113
114 // macro that saves some typing, nothing more
115 #define smc seekmonster(&mc)
116
117 /* ******************** BEGIN PUBLIC FUNCTIONS ******************** */
mons_init(FixedVector<unsigned short,1000> & colour)118 void mons_init(FixedVector < unsigned short, 1000 > &colour)
119 {
120 unsigned int x; // must be unsigned to match size_t {dlb}
121
122 for (x = 0; x < MONDATASIZE; x++)
123 colour[mondata[x].mc] = mondata[x].colour;
124
125 //unsigned int x = 0; // must be unsigned to match size_t {dlb}
126
127 // first, fill static array with dummy values {dlb};
128 for (x = 0; x < NUM_MONSTERS; x++)
129 mon_entry[x] = -1;
130
131 // next, fill static array with location of entry in mondata[] {dlb}:
132 for (x = 0; x < MONDATASIZE; x++)
133 mon_entry[mondata[x].mc] = x;
134
135 // finally, monsters yet with dummy entries point to TTTSNB(tm) {dlb}:
136 for (x = 0; x < NUM_MONSTERS; x++)
137 {
138 if (mon_entry[x] == -1)
139 mon_entry[x] = mon_entry[MONS_PROGRAM_BUG];
140 }
141 //return (monsterentry *) 0; // return value should not matter here {dlb}
142 } // end mons_init()
143
144
mons_flag(int mc,int bf)145 int mons_flag(int mc, int bf)
146 {
147 return ((smc->bitfields & bf) != 0);
148 } // end mons_flag()
149
scan_mon_inv_randarts(struct monsters * mon,int ra_prop)150 static int scan_mon_inv_randarts( struct monsters *mon, int ra_prop )
151 {
152 int ret = 0;
153
154 if (mons_itemuse( mon->type ) >= MONUSE_STARTING_EQUIPMENT)
155 {
156 const int weapon = mon->inv[MSLOT_WEAPON];
157 const int second = mon->inv[MSLOT_MISSILE]; // ettins/two-head oges
158 const int armour = mon->inv[MSLOT_ARMOUR];
159
160 if (weapon != NON_ITEM && mitm[weapon].base_type == OBJ_WEAPONS
161 && is_random_artefact( mitm[weapon] ))
162 {
163 ret += randart_wpn_property( mitm[weapon], ra_prop );
164 }
165
166 if (second != NON_ITEM && mitm[second].base_type == OBJ_WEAPONS
167 && is_random_artefact( mitm[second] ))
168 {
169 ret += randart_wpn_property( mitm[second], ra_prop );
170 }
171
172 if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR
173 && is_random_artefact( mitm[armour] ))
174 {
175 ret += randart_wpn_property( mitm[armour], ra_prop );
176 }
177 }
178
179 return (ret);
180 }
181
182
mons_holiness(int mc)183 int mons_holiness(int mc)
184 {
185 return (smc->holiness);
186 } // end mons_holiness()
187
mons_is_mimic(int mc)188 bool mons_is_mimic( int mc )
189 {
190 return (mons_charclass( mc ) == MONS_GOLD_MIMIC);
191 }
192
mons_is_demon(int mc)193 bool mons_is_demon( int mc )
194 {
195 const int show_char = mons_char( mc );
196
197 // Not every demonic monster is a demon (ie hell hog, hell hound)
198 if (mons_holiness( mc ) == MH_DEMONIC
199 && (isdigit( show_char ) || show_char == '&'))
200 {
201 return (true);
202 }
203
204 return (false);
205 }
206
207 // Used for elven Glamour ability. -- bwr
mons_is_humanoid(int mc)208 bool mons_is_humanoid( int mc )
209 {
210 switch (mons_char( mc))
211 {
212 case 'o': // orcs
213 case 'e': // elvens (deep)
214 case 'c': // centaurs
215 case 'C': // giants
216 case 'O': // ogres
217 case 'K': // kobolds
218 case 'N': // nagas
219 case '@': // adventuring humans
220 case 'T': // trolls
221 return (true);
222
223 case 'g': // goblines, hobgoblins, gnolls, boggarts -- but not gargoyles
224 if (mc != MONS_GARGOYLE
225 && mc != MONS_METAL_GARGOYLE
226 && mc != MONS_MOLTEN_GARGOYLE)
227 {
228 return (true);
229 }
230
231 default:
232 break;
233 }
234
235 return (false);
236 }
237
mons_zombie_size(int mc)238 int mons_zombie_size(int mc)
239 {
240 return (smc->zombie_size);
241 } // end mons_zombie_size()
242
243
mons_weight(int mc)244 int mons_weight(int mc)
245 {
246 return (smc->weight);
247 } // end mons_weight()
248
249
mons_corpse_thingy(int mc)250 int mons_corpse_thingy(int mc)
251 {
252 return (smc->corpse_thingy);
253 } // end mons_corpse_thingy()
254
255
mons_charclass(int mc)256 int mons_charclass(int mc)
257 {
258 return (smc->charclass);
259 } // end mons_charclass()
260
261
mons_shouts(int mc)262 char mons_shouts(int mc)
263 {
264 int u = smc->shouts;
265
266 if (u == -1)
267 u = random2(12);
268
269 return (u);
270 } // end mons_shouts()
271
mons_is_unique(int mc)272 bool mons_is_unique( int mc )
273 {
274 if (mc <= MONS_PROGRAM_BUG
275 || (mc >= MONS_NAGA_MAGE && mc <= MONS_ROYAL_JELLY)
276 || (mc >= MONS_ANCIENT_LICH
277 && (mc != MONS_PLAYER_GHOST && mc != MONS_PANDEMONIUM_DEMON)))
278 {
279 return (false);
280 }
281
282 return (true);
283 }
284
mons_see_invis(struct monsters * mon)285 char mons_see_invis( struct monsters *mon )
286 {
287 if (mon->type == MONS_PLAYER_GHOST || mon->type == MONS_PANDEMONIUM_DEMON)
288 return (ghost.values[ GVAL_SEE_INVIS ]);
289 else if (((seekmonster(&mon->type))->bitfields & M_SEE_INVIS) != 0)
290 return (1);
291 else if (scan_mon_inv_randarts( mon, RAP_EYESIGHT ) > 0)
292 return (1);
293
294 return (0);
295 } // end mons_see_invis()
296
297
298 // This does NOT do line of sight! It checks the targ's visibility
299 // with respect to mon's perception, but doesn't do walls or range.
mons_monster_visible(struct monsters * mon,struct monsters * targ)300 bool mons_monster_visible( struct monsters *mon, struct monsters *targ )
301 {
302 if (mons_has_ench(targ, ENCH_SUBMERGED)
303 || (mons_has_ench(targ, ENCH_INVIS) && !mons_see_invis(mon)))
304 {
305 return (false);
306 }
307
308 return (true);
309 }
310
311 // This does NOT do line of sight! It checks the player's visibility
312 // with respect to mon's perception, but doesn't do walls or range.
mons_player_visible(struct monsters * mon)313 bool mons_player_visible( struct monsters *mon )
314 {
315 if (you.invis)
316 {
317 if (player_in_water())
318 return (true);
319
320 if (mons_see_invis( mon ))
321 return (true);
322
323 return (false);
324 }
325
326 return (true);
327 }
328
mons_char(int mc)329 unsigned char mons_char(int mc)
330 {
331 return (unsigned char) smc->showchar;
332 } // end mons_char()
333
334
mons_itemuse(int mc)335 char mons_itemuse(int mc)
336 {
337 return (smc->gmon_use);
338 } // end mons_itemuse()
339
mons_colour(int mc)340 unsigned char mons_colour(int mc)
341 {
342 return (smc->colour);
343 } // end mons_colour()
344
345
mons_damage(int mc,int rt)346 int mons_damage(int mc, int rt)
347 {
348 ASSERT(rt >= 0);
349 ASSERT(rt <= 3);
350
351 if (rt < 0 || rt > 3) // make it fool-proof
352 return (0);
353
354 if (rt == 0 && (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON))
355 return (ghost.values[ GVAL_DAMAGE ]);
356
357 return (smc->damage[rt]);
358 } // end mons_damage()
359
mons_resist_magic(struct monsters * mon)360 int mons_resist_magic( struct monsters *mon )
361 {
362 int u = (seekmonster(&mon->type))->resist_magic;
363
364 // negative values get multiplied with mhd
365 if (u < 0)
366 u = mon->hit_dice * (-u * 2);
367
368 u += scan_mon_inv_randarts( mon, RAP_MAGIC );
369
370 // ego armour resistance
371 const int armour = mon->inv[MSLOT_ARMOUR];
372
373 if (armour != NON_ITEM
374 && get_armour_ego_type( mitm[armour] ) == SPARM_MAGIC_RESISTANCE )
375 {
376 u += 30;
377 }
378
379 return (u);
380 } // end mon_resist_magic()
381
382
383 // Returns true if the monster made its save against hostile
384 // enchantments/some other magics.
check_mons_resist_magic(struct monsters * monster,int pow)385 bool check_mons_resist_magic( struct monsters *monster, int pow )
386 {
387 int mrs = mons_resist_magic(monster);
388
389 if (mrs == 5000)
390 return (true);
391
392 // Evil, evil hack to make weak one hd monsters easier for first
393 // level characters who have resistable 1st level spells. Six is
394 // a very special value because mrs = hd * 2 * 3 for most monsters,
395 // and the weak, low level monsters have been adjusted so that the
396 // "3" is typically a 1. There are some notable one hd monsters
397 // that shouldn't fall under this, so we do < 6, instead of <= 6...
398 // or checking monster->hit_dice. The goal here is to make the
399 // first level easier for these classes and give them a better
400 // shot at getting to level two or three and spells that can help
401 // them out (or building a level or two of their base skill so they
402 // aren't resisted as often). -- bwr
403 if (mrs < 6 && coinflip())
404 return (false);
405
406 pow = stepdown_value( pow, 30, 40, 100, 120 );
407
408 const int mrchance = (100 + mrs) - pow;
409 const int mrch2 = random2(100) + random2(101);
410
411 #if DEBUG_DIAGNOSTICS
412 snprintf( info, INFO_SIZE,
413 "Power: %d, monster's MR: %d, target: %d, roll: %d",
414 pow, mrs, mrchance, mrch2 );
415
416 mpr( info, MSGCH_DIAGNOSTICS );
417 #endif
418
419 return ((mrch2 < mrchance) ? true : false);
420 } // end check_mons_resist_magic()
421
422
mons_res_elec(struct monsters * mon)423 int mons_res_elec( struct monsters *mon )
424 {
425 int mc = mon->type;
426
427 if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
428 return (ghost.values[ GVAL_RES_ELEC ]);
429
430 /* this is a variable, not a player_xx() function, so can be above 1 */
431 int u = 0, f = (seekmonster(&mc))->bitfields;
432
433 // of course it makes no sense setting them both :)
434 if (f & M_RES_ELEC)
435 u++; //if(f&M_ED_ELEC) u--;
436
437 // don't bother checking equipment if the monster can't use it
438 if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
439 {
440 u += scan_mon_inv_randarts( mon, RAP_ELECTRICITY );
441
442 // no ego armour, but storm dragon.
443 const int armour = mon->inv[MSLOT_ARMOUR];
444 if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR
445 && mitm[armour].sub_type == ARM_STORM_DRAGON_ARMOUR)
446 {
447 u += 1;
448 }
449 }
450
451 return (u);
452 } // end mons_res_elec()
453
454
mons_res_poison(struct monsters * mon)455 int mons_res_poison( struct monsters *mon )
456 {
457 int mc = mon->type;
458
459 int u = 0, f = (seekmonster(&mc))->bitfields;
460
461 if (f & M_RES_POISON)
462 u++;
463
464 if (f & M_ED_POISON)
465 u--;
466
467 if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
468 {
469 u += scan_mon_inv_randarts( mon, RAP_POISON );
470
471 const int armour = mon->inv[MSLOT_ARMOUR];
472 if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
473 {
474 // intrinsic armour abilities
475 switch (mitm[armour].sub_type)
476 {
477 case ARM_SWAMP_DRAGON_ARMOUR: u += 1; break;
478 case ARM_GOLD_DRAGON_ARMOUR: u += 1; break;
479 default: break;
480 }
481
482 // ego armour resistance
483 if (get_armour_ego_type( mitm[armour] ) == SPARM_POISON_RESISTANCE)
484 u += 1;
485 }
486 }
487
488 return (u);
489 } // end mons_res_poison()
490
491
mons_res_fire(struct monsters * mon)492 int mons_res_fire( struct monsters *mon )
493 {
494 int mc = mon->type;
495
496 if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
497 return (ghost.values[ GVAL_RES_FIRE ]);
498
499 int u = 0, f = (seekmonster(&mc))->bitfields;
500
501 // no Big Prize (tm) here either if you set all three flags. It's a pity uh?
502 //
503 // Note that natural monster resistance is two levels, this is duplicate
504 // the fact that having this flag used to be a lot better than armour
505 // for monsters (it used to make them immune in a lot of cases) -- bwr
506 if (f & M_RES_HELLFIRE)
507 u += 3;
508 else if (f & M_RES_FIRE)
509 u += 2;
510 else if (f & M_ED_FIRE)
511 u--;
512
513 if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
514 {
515 u += scan_mon_inv_randarts( mon, RAP_POISON );
516
517 const int armour = mon->inv[MSLOT_ARMOUR];
518 if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
519 {
520 // intrinsic armour abilities
521 switch (mitm[armour].sub_type)
522 {
523 case ARM_DRAGON_ARMOUR: u += 2; break;
524 case ARM_GOLD_DRAGON_ARMOUR: u += 1; break;
525 case ARM_ICE_DRAGON_ARMOUR: u -= 1; break;
526 default: break;
527 }
528
529 // check ego resistance
530 const int ego = get_armour_ego_type( mitm[armour] );
531 if (ego == SPARM_FIRE_RESISTANCE || ego == SPARM_RESISTANCE)
532 u += 1;
533 }
534 }
535
536 return (u);
537 } // end mons_res_fire()
538
539
mons_res_cold(struct monsters * mon)540 int mons_res_cold( struct monsters *mon )
541 {
542 int mc = mon->type;
543
544 if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
545 return (ghost.values[ GVAL_RES_COLD ]);
546
547 int u = 0, f = (seekmonster(&mc))->bitfields;
548
549 // Note that natural monster resistance is two levels, this is duplicate
550 // the fact that having this flag used to be a lot better than armour
551 // for monsters (it used to make them immune in a lot of cases) -- bwr
552 if (f & M_RES_COLD)
553 u += 2;
554 else if (f & M_ED_COLD)
555 u--;
556
557 if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
558 {
559 u += scan_mon_inv_randarts( mon, RAP_POISON );
560
561 const int armour = mon->inv[MSLOT_ARMOUR];
562 if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
563 {
564 // intrinsic armour abilities
565 switch (mitm[armour].sub_type)
566 {
567 case ARM_ICE_DRAGON_ARMOUR: u += 2; break;
568 case ARM_GOLD_DRAGON_ARMOUR: u += 1; break;
569 case ARM_DRAGON_ARMOUR: u -= 1; break;
570 default: break;
571 }
572
573 // check ego resistance
574 const int ego = get_armour_ego_type( mitm[armour] );
575 if (ego == SPARM_COLD_RESISTANCE || ego == SPARM_RESISTANCE)
576 u += 1;
577 }
578 }
579
580 return (u);
581 } // end mons_res_cold()
582
mons_res_negative_energy(struct monsters * mon)583 int mons_res_negative_energy( struct monsters *mon )
584 {
585 int mc = mon->type;
586
587 if (mons_holiness( mon->type ) == MH_UNDEAD
588 || mons_holiness( mon->type ) == MH_DEMONIC
589 || mons_holiness( mon->type ) == MH_NONLIVING
590 || mons_holiness( mon->type ) == MH_PLANT
591 || mon->type == MONS_SHADOW_DRAGON)
592 {
593 return (3); // to match the value for players
594 }
595
596 int u = 0;
597
598 if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
599 {
600 u += scan_mon_inv_randarts( mon, RAP_NEGATIVE_ENERGY );
601
602 const int armour = mon->inv[MSLOT_ARMOUR];
603 if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
604 {
605 // check for ego resistance
606 if (get_armour_ego_type( mitm[armour] ) == SPARM_POSITIVE_ENERGY)
607 u += 1;
608 }
609 }
610
611 return (u);
612 } // end mons_res_negative_energy()
613
mons_skeleton(int mc)614 int mons_skeleton(int mc)
615 {
616 if (mons_zombie_size(mc) == 0
617 || mons_weight(mc) == 0 || ((smc->bitfields & M_NO_SKELETON) != 0))
618 {
619 return (0);
620 }
621
622 return (1);
623 } // end mons_skeleton()
624
mons_class_flies(int mc)625 char mons_class_flies(int mc)
626 {
627 if (mc == MONS_PANDEMONIUM_DEMON)
628 return (ghost.values[ GVAL_DEMONLORD_FLY ]);
629
630 int f = smc->bitfields;
631
632 if (f & M_FLIES)
633 return (1);
634
635 if (f & M_LEVITATE)
636 return (2);
637
638 return (0);
639 }
640
mons_flies(struct monsters * mon)641 char mons_flies( struct monsters *mon )
642 {
643 char ret = mons_class_flies( mon->type );
644
645 return (ret ? ret : (scan_mon_inv_randarts(mon, RAP_LEVITATE) > 0) ? 2 : 0);
646 } // end mons_flies()
647
648
649 // this nice routine we keep in exactly the way it was
hit_points(int hit_dice,int min_hp,int rand_hp)650 int hit_points(int hit_dice, int min_hp, int rand_hp)
651 {
652 int hrolled = 0;
653
654 for (int hroll = 0; hroll < hit_dice; hroll++)
655 {
656 hrolled += random2(1 + rand_hp);
657 hrolled += min_hp;
658 }
659
660 return (hrolled);
661 } // end hit_points()
662
663 // This function returns the standard number of hit dice for a type
664 // of monster, not a pacticular monsters current hit dice. -- bwr
mons_type_hit_dice(int type)665 int mons_type_hit_dice( int type )
666 {
667 struct monsterentry *mon_class = seekmonster( &type );
668
669 if (mon_class)
670 return (mon_class->hpdice[0]);
671
672 return (0);
673 }
674
675
exper_value(struct monsters * monster)676 int exper_value( struct monsters *monster )
677 {
678 long x_val = 0;
679
680 // these three are the original arguments:
681 const int mclass = monster->type;
682 const int mHD = monster->hit_dice;
683 const int maxhp = monster->max_hit_points;
684
685 // these are some values we care about:
686 const int speed = mons_speed(mclass);
687 const int modifier = mons_exp_mod(mclass);
688 const int item_usage = mons_itemuse(mclass);
689
690 // XXX: shapeshifters can qualify here, even though they can't cast:
691 const bool spellcaster = mons_flag( mclass, M_SPELLCASTER );
692
693 // early out for no XP monsters
694 if (mons_flag(mclass, M_NO_EXP_GAIN))
695 return (0);
696
697 // These undead take damage to maxhp, so we use only HD. -- bwr
698 if (mclass == MONS_ZOMBIE_SMALL
699 || mclass == MONS_ZOMBIE_LARGE
700 || mclass == MONS_SIMULACRUM_SMALL
701 || mclass == MONS_SIMULACRUM_LARGE
702 || mclass == MONS_SKELETON_SMALL
703 || mclass == MONS_SKELETON_LARGE)
704 {
705 x_val = (16 + mHD * 4) * (mHD * mHD) / 10;
706 }
707 else
708 {
709 x_val = (16 + maxhp) * (mHD * mHD) / 10;
710 }
711
712
713 // Let's calculate a simple difficulty modifier -- bwr
714 int diff = 0;
715
716 // Let's look for big spells:
717 if (spellcaster)
718 {
719 const int msecc = ((mclass == MONS_HELLION) ? MST_BURNING_DEVIL :
720 (mclass == MONS_PANDEMONIUM_DEMON) ? MST_GHOST
721 : monster->number);
722
723 int hspell_pass[6] = { MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL,
724 MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL };
725
726 mons_spell_list( msecc, hspell_pass );
727
728 for (int i = 0; i < 6; i++)
729 {
730 switch (hspell_pass[i])
731 {
732 case MS_PARALYSIS:
733 case MS_SMITE:
734 case MS_HELLFIRE_BURST:
735 case MS_HELLFIRE:
736 case MS_TORMENT:
737 case MS_IRON_BOLT:
738 diff += 25;
739 break;
740
741 case MS_LIGHTNING_BOLT:
742 case MS_NEGATIVE_BOLT:
743 case MS_VENOM_BOLT:
744 case MS_STICKY_FLAME:
745 case MS_DISINTEGRATE:
746 case MS_SUMMON_DEMON_GREATER:
747 case MS_BANISHMENT:
748 case MS_CRYSTAL_SPEAR:
749 case MS_TELEPORT:
750 case MS_TELEPORT_OTHER:
751 diff += 10;
752 break;
753
754 default:
755 break;
756 }
757 }
758 }
759
760 // let's look at regeneration
761 if (monster_descriptor( mclass, MDSC_REGENERATES ))
762 diff += 15;
763
764 // Monsters at normal or fast speed with big melee damage
765 if (speed >= 10)
766 {
767 int max_melee = 0;
768 for (int i = 0; i < 4; i++)
769 max_melee += mons_damage( mclass, i );
770
771 if (max_melee > 30)
772 diff += (max_melee / ((speed == 10) ? 2 : 1));
773 }
774
775 // Monsters who can use equipment (even if only the equipment
776 // they are given) can be considerably enhanced because of
777 // the way weapons work for monsters. -- bwr
778 if (item_usage == MONUSE_STARTING_EQUIPMENT
779 || item_usage == MONUSE_WEAPONS_ARMOUR)
780 {
781 diff += 30;
782 }
783
784 // Set a reasonable range on the difficulty modifier...
785 // Currently 70% - 200% -- bwr
786 if (diff > 100)
787 diff = 100;
788 else if (diff < -30)
789 diff = -30;
790
791 // Apply difficulty
792 x_val *= (100 + diff);
793 x_val /= 100;
794
795 // Basic speed modification
796 if (speed > 0)
797 {
798 x_val *= speed;
799 x_val /= 10;
800 }
801
802 // Slow monsters without spells and items often have big HD which
803 // cause the experience value to be overly large... this tries
804 // to reduce the inappropriate amount of XP that results. -- bwr
805 if (speed < 10 && !spellcaster && item_usage < MONUSE_STARTING_EQUIPMENT)
806 {
807 x_val /= 2;
808 }
809
810 // Apply the modifier in the monster's definition
811 if (modifier > 0)
812 {
813 x_val *= modifier;
814 x_val /= 10;
815 }
816
817 // Reductions for big values. -- bwr
818 if (x_val > 100)
819 x_val = 100 + ((x_val - 100) * 3) / 4;
820 if (x_val > 1000)
821 x_val = 1000 + (x_val - 1000) / 2;
822
823 // guarantee the value is within limits
824 if (x_val <= 0)
825 x_val = 1;
826 else if (x_val > 15000)
827 x_val = 15000;
828
829 return (x_val);
830 } // end exper_value()
831
832
833 // this needs to be rewritten a la the monsterseek rewrite {dlb}:
mons_spell_list(unsigned char sec,int splist[6])834 void mons_spell_list( unsigned char sec, int splist[6] )
835 {
836 unsigned int x;
837
838 for (x = 0; x < NUM_MSTYPES; x++)
839 {
840 if (mspell_list[x][0] == sec)
841 break;
842 }
843
844 if (x >= NUM_MSTYPES)
845 return;
846
847 // I *KNOW* this can easily be done in a loop
848 splist[0] = mspell_list[x][1]; // bolt spell
849 splist[1] = mspell_list[x][2]; // enchantment
850 splist[2] = mspell_list[x][3]; // self_ench
851 splist[3] = mspell_list[x][4]; // misc
852 splist[4] = mspell_list[x][5]; // misc2
853 splist[5] = mspell_list[x][6]; // emergency
854
855 if (sec == MST_GHOST) /* ghost */
856 {
857 for (x = 0; x < 6; x++)
858 splist[x] = ghost.values[ GVAL_SPELL_1 + x ];
859 }
860 } // end mons_spell_list()
861
862 #if DEBUG_DIAGNOSTICS
mons_spell_name(int spell)863 const char *mons_spell_name( int spell )
864 {
865 if (spell == MS_NO_SPELL || spell >= NUM_MONSTER_SPELLS || spell < 0)
866 return ("No spell");
867
868 return (monster_spell_name[ spell ]);
869 }
870 #endif
871
872 // generate a shiny new and unscarred monster
define_monster(int k)873 void define_monster(int k)
874 {
875 int temp_rand = 0; // probability determination {dlb}
876 int m2_class = menv[k].type;
877 int m2_HD, m2_hp, m2_hp_max, m2_AC, m2_ev, m2_speed;
878 int m2_sec = menv[k].number;
879 struct monsterentry *m = seekmonster(&m2_class);
880
881 m2_HD = m->hpdice[0];
882
883 // misc
884 m2_AC = m->AC;
885 m2_ev = m->ev;
886
887 // speed
888 m2_speed = m->speed;
889
890 // some monsters are randomized:
891 // did I get them all? // I don't think so {dlb}
892 if (mons_is_mimic( m2_class ))
893 m2_sec = get_mimic_colour( &menv[k] );
894 else
895 {
896 switch (m2_class)
897 {
898 case MONS_ABOMINATION_SMALL:
899 m2_HD = 4 + random2(4);
900 m2_AC = 3 + random2(7);
901 m2_ev = 7 + random2(6);
902 m2_speed = 7 + random2avg(9, 2);
903
904 if (m2_sec == 250)
905 m2_sec = random_colour();
906 break;
907
908 case MONS_ZOMBIE_SMALL:
909 m2_HD = (coinflip() ? 1 : 2);
910 break;
911
912 case MONS_ZOMBIE_LARGE:
913 m2_HD = 3 + random2(5);
914 break;
915
916 case MONS_ABOMINATION_LARGE:
917 m2_HD = 8 + random2(4);
918 m2_AC = 5 + random2avg(9, 2);
919 m2_ev = 3 + random2(5);
920 m2_speed = 6 + random2avg(7, 2);
921
922 if (m2_sec == 250)
923 m2_sec = random_colour();
924 break;
925
926 case MONS_BEAST:
927 m2_HD = 4 + random2(4);
928 m2_AC = 2 + random2(5);
929 m2_ev = 7 + random2(5);
930 m2_speed = 8 + random2(5);
931 break;
932
933 case MONS_HYDRA:
934 m2_sec = 4 + random2(5);
935 break;
936
937 case MONS_DEEP_ELF_FIGHTER:
938 case MONS_DEEP_ELF_KNIGHT:
939 case MONS_DEEP_ELF_SOLDIER:
940 case MONS_ORC_WIZARD:
941 m2_sec = MST_ORC_WIZARD_I + random2(3);
942 break;
943
944 case MONS_LICH:
945 case MONS_ANCIENT_LICH:
946 m2_sec = MST_LICH_I + random2(4);
947 break;
948
949 case MONS_HELL_KNIGHT:
950 m2_sec = (coinflip() ? MST_HELL_KNIGHT_I : MST_HELL_KNIGHT_II);
951 break;
952
953 case MONS_NECROMANCER:
954 m2_sec = (coinflip() ? MST_NECROMANCER_I : MST_NECROMANCER_II);
955 break;
956
957 case MONS_WIZARD:
958 case MONS_OGRE_MAGE:
959 case MONS_EROLCHA:
960 case MONS_DEEP_ELF_MAGE:
961 m2_sec = MST_WIZARD_I + random2(5);
962 break;
963
964 case MONS_DEEP_ELF_CONJURER:
965 m2_sec = (coinflip()? MST_DEEP_ELF_CONJURER_I : MST_DEEP_ELF_CONJURER_II);
966 break;
967
968 case MONS_BUTTERFLY:
969 case MONS_SPATIAL_VORTEX:
970 case MONS_KILLER_KLOWN:
971 m2_sec = random_colour();
972 break;
973
974 case MONS_GILA_MONSTER:
975 temp_rand = random2(7);
976
977 m2_sec = (temp_rand >= 5 ? LIGHTRED : // 2/7
978 temp_rand >= 3 ? LIGHTMAGENTA : // 2/7
979 temp_rand == 2 ? RED : // 1/7
980 temp_rand == 1 ? MAGENTA // 1/7
981 : YELLOW); // 1/7
982 break;
983
984 case MONS_HUMAN:
985 case MONS_ELF:
986 // these are supposed to only be created by polymorph
987 m2_HD += random2(10);
988 m2_AC += random2(5);
989 m2_ev += random2(5);
990 break;
991
992 default:
993 break;
994 }
995 }
996
997 // some calculations
998 m2_hp = hit_points(m2_HD, m->hpdice[1], m->hpdice[2]);
999 m2_hp += m->hpdice[3];
1000 m2_hp_max = m2_hp;
1001
1002 if (m2_sec == 250)
1003 m2_sec = m->sec;
1004
1005 // so let it be written, so let it be done
1006 menv[k].hit_dice = m2_HD;
1007 menv[k].hit_points = m2_hp;
1008 menv[k].max_hit_points = m2_hp_max;
1009 menv[k].armour_class = m2_AC;
1010 menv[k].evasion = m2_ev;
1011 menv[k].speed = m2_speed;
1012 menv[k].speed_increment = 70;
1013 menv[k].number = m2_sec;
1014 menv[k].flags = 0;
1015
1016 // reset monster enchantments
1017 for (int i = 0; i < NUM_MON_ENCHANTS; i++)
1018 menv[k].enchantment[i] = ENCH_NONE;
1019 } // end define_monster()
1020
1021
1022 /* ------------------------- monam/moname ------------------------- */
ptr_monam(struct monsters * mon,char desc)1023 const char *ptr_monam( struct monsters *mon, char desc )
1024 {
1025 // We give an item type description for mimics now, note that
1026 // since gold mimics only have one description (to match the
1027 // examine code in direct.cc), we won't bother going through
1028 // this for them. -- bwr
1029 if (mons_is_mimic( mon->type ) && mon->type != MONS_GOLD_MIMIC)
1030 {
1031 static char mimic_name_buff[ ITEMNAME_SIZE ];
1032
1033 item_def item;
1034 get_mimic_item( mon, item );
1035 item_name( item, desc, mimic_name_buff );
1036
1037 return (mimic_name_buff);
1038 }
1039
1040 return (monam( mon->number, mon->type, player_monster_visible( mon ),
1041 desc, mon->inv[MSLOT_WEAPON] ));
1042 }
1043
monam(int mons_num,int mons,bool vis,char desc,int mons_wpn)1044 const char *monam( int mons_num, int mons, bool vis, char desc, int mons_wpn )
1045 {
1046 static char gmo_n[ ITEMNAME_SIZE ];
1047 char gmo_n2[ ITEMNAME_SIZE ] = "";
1048
1049 gmo_n[0] = '\0';
1050
1051 // If you can't see the critter, let moname() print [Ii]t.
1052 if (!vis)
1053 {
1054 moname( mons, vis, desc, gmo_n );
1055 return (gmo_n);
1056 }
1057
1058 // These need their description level handled here instead of
1059 // in monam().
1060 if (mons == MONS_SPECTRAL_THING)
1061 {
1062 switch (desc)
1063 {
1064 case DESC_CAP_THE:
1065 strcpy(gmo_n, "The");
1066 break;
1067 case DESC_NOCAP_THE:
1068 strcpy(gmo_n, "the");
1069 break;
1070 case DESC_CAP_A:
1071 strcpy(gmo_n, "A");
1072 break;
1073 case DESC_NOCAP_A:
1074 strcpy(gmo_n, "a");
1075 break;
1076 case DESC_PLAIN: /* do nothing */ ;
1077 break;
1078 //default: DEBUGSTR("bad desc flag");
1079 }
1080 }
1081
1082 switch (mons)
1083 {
1084 case MONS_ZOMBIE_SMALL:
1085 case MONS_ZOMBIE_LARGE:
1086 moname(mons_num, vis, desc, gmo_n);
1087 strcat(gmo_n, " zombie");
1088 break;
1089
1090 case MONS_SKELETON_SMALL:
1091 case MONS_SKELETON_LARGE:
1092 moname(mons_num, vis, desc, gmo_n);
1093 strcat(gmo_n, " skeleton");
1094 break;
1095
1096 case MONS_SIMULACRUM_SMALL:
1097 case MONS_SIMULACRUM_LARGE:
1098 moname(mons_num, vis, desc, gmo_n);
1099 strcat(gmo_n, " simulacrum");
1100 break;
1101
1102 case MONS_SPECTRAL_THING:
1103 strcat(gmo_n, " spectral ");
1104 moname(mons_num, vis, DESC_PLAIN, gmo_n2);
1105 strcat(gmo_n, gmo_n2);
1106 break;
1107
1108 case MONS_DANCING_WEAPON:
1109 // safety check -- if we don't have/know the weapon use default name
1110 if (mons_wpn == NON_ITEM)
1111 moname( mons, vis, desc, gmo_n );
1112 else
1113 {
1114 item_def item = mitm[mons_wpn];
1115 unset_ident_flags( item, ISFLAG_KNOW_CURSE | ISFLAG_KNOW_PLUSES );
1116 item_name( item, desc, gmo_n );
1117 }
1118 break;
1119
1120 case MONS_PLAYER_GHOST:
1121 strcpy(gmo_n, ghost.name);
1122 strcat(gmo_n, "'s ghost");
1123 break;
1124
1125 case MONS_PANDEMONIUM_DEMON:
1126 strcpy(gmo_n, ghost.name);
1127 break;
1128
1129 default:
1130 moname(mons, vis, desc, gmo_n);
1131 break;
1132 }
1133
1134 return (gmo_n);
1135 } // end monam()
1136
moname(int mons_num,bool vis,char descrip,char glog[ITEMNAME_SIZE])1137 void moname(int mons_num, bool vis, char descrip, char glog[ ITEMNAME_SIZE ])
1138 {
1139 glog[0] = '\0';
1140
1141 char gmon_name[ ITEMNAME_SIZE ] = "";
1142 strcpy( gmon_name, seekmonster( &mons_num )->name );
1143
1144 if (!vis)
1145 {
1146 switch (descrip)
1147 {
1148 case DESC_CAP_THE:
1149 case DESC_CAP_A:
1150 strcpy(glog, "It");
1151 break;
1152 case DESC_NOCAP_THE:
1153 case DESC_NOCAP_A:
1154 case DESC_PLAIN:
1155 strcpy(glog, "it");
1156 break;
1157 }
1158
1159 strcpy(gmon_name, glog);
1160 return;
1161 }
1162
1163 if (!mons_is_unique( mons_num ))
1164 {
1165 switch (descrip)
1166 {
1167 case DESC_CAP_THE:
1168 strcpy(glog, "The ");
1169 break;
1170 case DESC_NOCAP_THE:
1171 strcpy(glog, "the ");
1172 break;
1173 case DESC_CAP_A:
1174 strcpy(glog, "A");
1175 break;
1176 case DESC_NOCAP_A:
1177 strcpy(glog, "a");
1178 break;
1179 case DESC_PLAIN:
1180 break;
1181 // default: DEBUGSTR("bad monster descrip flag");
1182 }
1183
1184 if (descrip == DESC_CAP_A || descrip == DESC_NOCAP_A)
1185 {
1186 switch (toupper(gmon_name[0]))
1187 {
1188 case 'A':
1189 case 'E':
1190 case 'I':
1191 case 'O':
1192 case 'U':
1193 strcat(glog, "n ");
1194 break;
1195
1196 default:
1197 strcat(glog, " ");
1198 break;
1199 }
1200 }
1201 }
1202
1203 strcat(glog, gmon_name);
1204 } // end moname()
1205
1206 /* ********************* END PUBLIC FUNCTIONS ********************* */
1207
1208 // see mons_init for initialization of mon_entry array.
seekmonster(int * p_monsterid)1209 static struct monsterentry *seekmonster(int *p_monsterid)
1210 {
1211 ASSERT(p_monsterid != 0);
1212
1213 int me = mon_entry[(*p_monsterid)];
1214
1215 if (me >= 0) // PARANOIA
1216 return (&mondata[mon_entry[(*p_monsterid)]]);
1217 else
1218 return (NULL);
1219 } // end seekmonster()
1220
mons_exp_mod(int mc)1221 static int mons_exp_mod(int mc)
1222 {
1223 return (smc->exp_mod);
1224 } // end mons_exp_mod()
1225
1226
mons_speed(int mc)1227 int mons_speed(int mc)
1228 {
1229 return (smc->speed);
1230 } // end mons_speed()
1231
1232
mons_intel(int mc)1233 int mons_intel(int mc) //jmf: "fixed" to work with new I_ types
1234 {
1235 switch (smc->intel)
1236 {
1237 case I_PLANT:
1238 return (I_PLANT);
1239 case I_INSECT:
1240 case I_REPTILE:
1241 return (I_INSECT);
1242 case I_ANIMAL:
1243 case I_ANIMAL_LIKE:
1244 return (I_ANIMAL);
1245 case I_NORMAL:
1246 return (I_NORMAL);
1247 case I_HIGH:
1248 return (I_HIGH);
1249 default:
1250 return (I_NORMAL);
1251 }
1252 } // ens mons_intel()
1253
1254
mons_intel_type(int mc)1255 int mons_intel_type(int mc) //jmf: new, used by my spells
1256 {
1257 return (smc->intel);
1258 } // end mons_intel_type()
1259
mons_power(int mc)1260 int mons_power(int mc)
1261 {
1262 // for now, just return monster hit dice.
1263 return (smc->hpdice[0]);
1264 }
1265
mons_aligned(int m1,int m2)1266 bool mons_aligned(int m1, int m2)
1267 {
1268 bool fr1, fr2;
1269 struct monsters *mon1, *mon2;
1270
1271 if (m1 == MHITNOT || m2 == MHITNOT)
1272 return (true);
1273
1274 if (m1 == MHITYOU)
1275 fr1 = true;
1276 else
1277 {
1278 mon1 = &menv[m1];
1279 fr1 = (mon1->attitude == ATT_FRIENDLY) || mons_has_ench(mon1, ENCH_CHARM);
1280 }
1281
1282 if (m2 == MHITYOU)
1283 fr2 = true;
1284 else
1285 {
1286 mon2 = &menv[m2];
1287 fr2 = (mon2->attitude == ATT_FRIENDLY) || mons_has_ench(mon2, ENCH_CHARM);
1288 }
1289
1290 return (fr1 == fr2);
1291 }
1292
mons_friendly(struct monsters * m)1293 bool mons_friendly(struct monsters *m)
1294 {
1295 return (m->attitude == ATT_FRIENDLY || mons_has_ench(m, ENCH_CHARM));
1296 }
1297
1298 /* ******************************************************************
1299
1300 // In the name of England, I declare this function wasteful! {dlb}
1301
1302 static monsterentry *seekmonster( int mc )
1303 {
1304
1305 ASSERT(mc >= 0);
1306
1307 int x = 0;
1308
1309 while (x < mondatasize)
1310 {
1311 if (mondata[x].mc == mc)
1312 return &mondata[x];
1313
1314 x++;
1315 }
1316
1317 ASSERT(false);
1318
1319 return seekmonster(MONS_PROGRAM_BUG); // see the disasters coming if there is no 250?
1320
1321 } // end seekmonster()
1322 ****************************************************************** */
1323
1324
1325 /* ******************************************************************
1326
1327 // only used once, and internal to this file, to boot {dlb}:
1328
1329 // These are easy to implement here. The difficult (dull!) work of converting
1330 // the data structures is finally finished now!
1331 inline char *mons_name( int mc )
1332 {
1333
1334 return smc->name;
1335
1336 } // end mons_name()
1337 ****************************************************************** */
1338
1339 /*****************************************************************
1340
1341 Used to determine whether or not a monster should fire a beam (MUST be
1342 called _after_ fire_tracer() for meaningful result.
1343
1344 */
1345
mons_should_fire(struct bolt & beam)1346 bool mons_should_fire(struct bolt &beam)
1347 {
1348 // use of foeRatio:
1349 // the higher this number, the more monsters
1350 // will _avoid_ collateral damage to their friends.
1351 // setting this to zero will in fact have all
1352 // monsters ignore their friends when considering
1353 // collateral damage.
1354
1355 // quick check - did we in fact get any foes?
1356 if (beam.foe_count == 0)
1357 return (false);
1358
1359 // if we either hit no friends, or monster too dumb to care
1360 if (beam.fr_count == 0 || !beam.smartMonster)
1361 return (true);
1362
1363 // only fire if they do acceptably low collateral damage
1364 // the default for this is 50%; in other words, don't
1365 // hit a foe unless you hit 2 or fewer friends.
1366 if (beam.foe_power >= (beam.foeRatio * beam.fr_power) / 100)
1367 return (true);
1368
1369 return (false);
1370 }
1371
mons_has_ench(struct monsters * mon,unsigned int ench,unsigned int ench2)1372 int mons_has_ench(struct monsters *mon, unsigned int ench, unsigned int ench2)
1373 {
1374 // silliness
1375 if (ench == ENCH_NONE)
1376 return (ench);
1377
1378 if (ench2 == ENCH_NONE)
1379 ench2 = ench;
1380
1381 for (int p = 0; p < NUM_MON_ENCHANTS; p++)
1382 {
1383 if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2)
1384 return (mon->enchantment[p]);
1385 }
1386
1387 return (ENCH_NONE);
1388 }
1389
1390 // Returning the deleted enchantment is important! See abjuration. -- bwr
mons_del_ench(struct monsters * mon,unsigned int ench,unsigned int ench2,bool quiet)1391 int mons_del_ench( struct monsters *mon, unsigned int ench, unsigned int ench2,
1392 bool quiet )
1393 {
1394 unsigned int p;
1395 int ret_val = ENCH_NONE;
1396
1397 // silliness
1398 if (ench == ENCH_NONE)
1399 return (ENCH_NONE);
1400
1401 if (ench2 == ENCH_NONE)
1402 ench2 = ench;
1403
1404 for (p = 0; p < NUM_MON_ENCHANTS; p++)
1405 {
1406 if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2)
1407 break;
1408 }
1409
1410 if (p == NUM_MON_ENCHANTS)
1411 return (ENCH_NONE);
1412
1413 ret_val = mon->enchantment[p];
1414 mon->enchantment[p] = ENCH_NONE;
1415
1416 // check for slow/haste
1417 if (ench == ENCH_HASTE)
1418 {
1419 if (mon->speed >= 100)
1420 mon->speed = 100 + ((mon->speed - 100) / 2);
1421 else
1422 mon->speed /= 2;
1423 }
1424
1425 if (ench == ENCH_SLOW)
1426 {
1427 if (mon->speed >= 100)
1428 mon->speed = 100 + ((mon->speed - 100) * 2);
1429 else
1430 mon->speed *= 2;
1431 }
1432
1433 if (ench == ENCH_FEAR)
1434 {
1435 if (!quiet)
1436 simple_monster_message(mon, " seems to regain its courage.");
1437
1438 // reevaluate behaviour
1439 behaviour_event(mon, ME_EVAL);
1440 }
1441
1442 if (ench == ENCH_CONFUSION)
1443 {
1444 if (!quiet)
1445 simple_monster_message(mon, " seems less confused.");
1446
1447 // reevaluate behaviour
1448 behaviour_event(mon, ME_EVAL);
1449 }
1450
1451 if (ench == ENCH_INVIS)
1452 {
1453 // invisible monsters stay invisible
1454 if (mons_flag(mon->type, M_INVIS))
1455 {
1456 mon->enchantment[p] = ENCH_INVIS;
1457 }
1458 else if (mons_near(mon) && !player_see_invis()
1459 && !mons_has_ench( mon, ENCH_SUBMERGED ))
1460 {
1461 if (!quiet)
1462 {
1463 strcpy( info, ptr_monam( mon, DESC_CAP_A ) );
1464 strcat( info, " appears!" );
1465 mpr( info );
1466 }
1467 }
1468 }
1469
1470 if (ench == ENCH_CHARM)
1471 {
1472 if (!quiet)
1473 simple_monster_message(mon, " is no longer charmed.");
1474
1475 // reevaluate behaviour
1476 behaviour_event(mon, ME_EVAL);
1477 }
1478
1479 if (ench == ENCH_BACKLIGHT_I)
1480 {
1481 if (!quiet)
1482 simple_monster_message(mon, " stops glowing.");
1483 }
1484
1485 if (ench == ENCH_STICKY_FLAME_I || ench == ENCH_YOUR_STICKY_FLAME_I)
1486 {
1487 if (!quiet)
1488 simple_monster_message(mon, " stops burning.");
1489 }
1490
1491 if (ench == ENCH_POISON_I || ench == ENCH_YOUR_POISON_I)
1492 {
1493 if (!quiet)
1494 simple_monster_message(mon, " looks more healthy.");
1495 }
1496
1497 if (ench == ENCH_YOUR_ROT_I)
1498 {
1499 if (!quiet)
1500 simple_monster_message(mon, " is no longer rotting.");
1501 }
1502
1503 return (ret_val);
1504 }
1505
mons_add_ench(struct monsters * mon,unsigned int ench)1506 bool mons_add_ench(struct monsters *mon, unsigned int ench)
1507 {
1508 // silliness
1509 if (ench == ENCH_NONE)
1510 return (false);
1511
1512 int newspot = -1;
1513
1514 // don't double-add
1515 for (int p = 0; p < NUM_MON_ENCHANTS; p++)
1516 {
1517 if (mon->enchantment[p] == ench)
1518 return (true);
1519
1520 if (mon->enchantment[p] == ENCH_NONE && newspot < 0)
1521 newspot = p;
1522 }
1523
1524 if (newspot < 0)
1525 return (false);
1526
1527 mon->enchantment[newspot] = ench;
1528 // if ench == ENCH_FEAR //mv: withou this fear & repel undead spell doesn't work
1529
1530
1531 // check for slow/haste
1532 if (ench == ENCH_HASTE)
1533 {
1534 if (mon->speed >= 100)
1535 mon->speed = 100 + ((mon->speed - 100) * 2);
1536 else
1537 mon->speed *= 2;
1538 }
1539
1540 if (ench == ENCH_SLOW)
1541 {
1542 if (mon->speed >= 100)
1543 mon->speed = 100 + ((mon->speed - 100) / 2);
1544 else
1545 mon->speed /= 2;
1546 }
1547
1548 return (true);
1549 }
1550
1551 // used to determine whether or not a monster should always
1552 // fire this spell if selected. If not, we should use a
1553 // tracer.
1554
1555 // note - this function assumes that the monster is "nearby"
1556 // its target!
1557
ms_requires_tracer(int monspell)1558 bool ms_requires_tracer(int monspell)
1559 {
1560 bool requires = false;
1561
1562 switch(monspell)
1563 {
1564 case MS_BANISHMENT:
1565 case MS_COLD_BOLT:
1566 case MS_CONFUSE:
1567 case MS_CRYSTAL_SPEAR:
1568 case MS_DISINTEGRATE:
1569 case MS_ENERGY_BOLT:
1570 case MS_FIRE_BOLT:
1571 case MS_FIREBALL:
1572 case MS_FLAME:
1573 case MS_FROST:
1574 case MS_HELLFIRE:
1575 case MS_IRON_BOLT:
1576 case MS_LIGHTNING_BOLT:
1577 case MS_MARSH_GAS:
1578 case MS_METAL_SPLINTERS:
1579 case MS_MMISSILE:
1580 case MS_NEGATIVE_BOLT:
1581 case MS_ORB_ENERGY:
1582 case MS_PAIN:
1583 case MS_PARALYSIS:
1584 case MS_POISON_BLAST:
1585 case MS_POISON_SPLASH:
1586 case MS_QUICKSILVER_BOLT:
1587 case MS_SLOW:
1588 case MS_STEAM_BALL:
1589 case MS_STICKY_FLAME:
1590 case MS_STING:
1591 case MS_STONE_ARROW:
1592 case MS_TELEPORT_OTHER:
1593 case MS_VENOM_BOLT:
1594 requires = true;
1595 break;
1596
1597 // self-niceties and direct effects
1598 case MS_ANIMATE_DEAD:
1599 case MS_BLINK:
1600 case MS_BRAIN_FEED:
1601 case MS_DIG:
1602 case MS_FAKE_RAKSHASA_SUMMON:
1603 case MS_HASTE:
1604 case MS_HEAL:
1605 case MS_HELLFIRE_BURST:
1606 case MS_INVIS:
1607 case MS_LEVEL_SUMMON:
1608 case MS_MUTATION:
1609 case MS_SMITE:
1610 case MS_SUMMON_BEAST:
1611 case MS_SUMMON_DEMON_LESSER:
1612 case MS_SUMMON_DEMON:
1613 case MS_SUMMON_DEMON_GREATER:
1614 case MS_SUMMON_UFETUBUS:
1615 case MS_TELEPORT:
1616 case MS_TORMENT:
1617 case MS_VAMPIRE_SUMMON:
1618 case MS_CANTRIP:
1619
1620 // meaningless, but sure, why not?
1621 case MS_NO_SPELL:
1622 break;
1623
1624 default:
1625 break;
1626
1627 }
1628
1629 return (requires);
1630 }
1631
1632 // returns true if the spell is something you wouldn't want done if
1633 // you had a friendly target.. only returns a meaningful value for
1634 // non-beam spells
1635
ms_direct_nasty(int monspell)1636 bool ms_direct_nasty(int monspell)
1637 {
1638 bool nasty = true;
1639
1640 switch(monspell)
1641 {
1642 // self-niceties/summonings
1643 case MS_ANIMATE_DEAD:
1644 case MS_BLINK:
1645 case MS_DIG:
1646 case MS_FAKE_RAKSHASA_SUMMON:
1647 case MS_HASTE:
1648 case MS_HEAL:
1649 case MS_INVIS:
1650 case MS_LEVEL_SUMMON:
1651 case MS_SUMMON_BEAST:
1652 case MS_SUMMON_DEMON_LESSER:
1653 case MS_SUMMON_DEMON:
1654 case MS_SUMMON_DEMON_GREATER:
1655 case MS_SUMMON_UFETUBUS:
1656 case MS_TELEPORT:
1657 case MS_VAMPIRE_SUMMON:
1658 nasty = false;
1659 break;
1660
1661 case MS_BRAIN_FEED:
1662 case MS_HELLFIRE_BURST:
1663 case MS_MUTATION:
1664 case MS_SMITE:
1665 case MS_TORMENT:
1666
1667 // meaningless, but sure, why not?
1668 case MS_NO_SPELL:
1669 break;
1670
1671 default:
1672 break;
1673
1674 }
1675
1676 return (nasty);
1677 }
1678
1679 // Spells a monster may want to cast if fleeing from the player, and
1680 // the player is not in sight.
ms_useful_fleeing_out_of_sight(struct monsters * mon,int monspell)1681 bool ms_useful_fleeing_out_of_sight( struct monsters *mon, int monspell )
1682 {
1683 if (ms_waste_of_time( mon, monspell ))
1684 return (false);
1685
1686 switch (monspell)
1687 {
1688 case MS_HASTE:
1689 case MS_INVIS:
1690 case MS_HEAL:
1691 case MS_ANIMATE_DEAD:
1692 return (true);
1693
1694 case MS_VAMPIRE_SUMMON:
1695 case MS_SUMMON_UFETUBUS:
1696 case MS_FAKE_RAKSHASA_SUMMON:
1697 case MS_LEVEL_SUMMON:
1698 case MS_SUMMON_DEMON:
1699 case MS_SUMMON_DEMON_LESSER:
1700 case MS_SUMMON_BEAST:
1701 case MS_SUMMON_UNDEAD:
1702 case MS_SUMMON_DEMON_GREATER:
1703 if (one_chance_in(10)) // only summon friends some of the time
1704 return (true);
1705 break;
1706
1707 default:
1708 break;
1709 }
1710
1711 return (false);
1712 }
1713
ms_low_hitpoint_cast(struct monsters * mon,int monspell)1714 bool ms_low_hitpoint_cast( struct monsters *mon, int monspell )
1715 {
1716 bool ret = false;
1717
1718 bool targ_adj = false;
1719
1720 if (mon->foe == MHITYOU || mon->foe == MHITNOT)
1721 {
1722 if (adjacent(you.x_pos, you.y_pos, mon->x, mon->y))
1723 targ_adj = true;
1724 }
1725 else if (adjacent( menv[mon->foe].x, menv[mon->foe].y, mon->x, mon->y ))
1726 {
1727 targ_adj = true;
1728 }
1729
1730 switch (monspell)
1731 {
1732 case MS_TELEPORT:
1733 case MS_TELEPORT_OTHER:
1734 case MS_HEAL:
1735 ret = true;
1736 break;
1737
1738 case MS_BLINK:
1739 if (targ_adj)
1740 ret = true;
1741 break;
1742
1743 case MS_VAMPIRE_SUMMON:
1744 case MS_SUMMON_UFETUBUS:
1745 case MS_FAKE_RAKSHASA_SUMMON:
1746 if (!targ_adj)
1747 ret = true;
1748 break;
1749 }
1750
1751 return (ret);
1752 }
1753
1754 // Checks to see if a particular spell is worth casting in the first place.
ms_waste_of_time(struct monsters * mon,int monspell)1755 bool ms_waste_of_time( struct monsters *mon, int monspell )
1756 {
1757 bool ret = false;
1758 int intel, est_magic_resist, power, diff;
1759 struct monsters *targ;
1760
1761
1762 // Eventually, we'll probably want to be able to have monsters
1763 // learn which of their elemental bolts were resisted and have those
1764 // handled here as well. -- bwr
1765 switch (monspell)
1766 {
1767 case MS_HASTE:
1768 if (mons_has_ench( mon, ENCH_HASTE ))
1769 ret = true;
1770 break;
1771
1772 case MS_INVIS:
1773 if (mons_has_ench( mon, ENCH_INVIS ))
1774 ret = true;
1775 break;
1776
1777 case MS_HEAL:
1778 if (mon->hit_points > mon->max_hit_points / 2)
1779 ret = true;
1780 break;
1781
1782 case MS_TELEPORT:
1783 // Monsters aren't smart enough to know when to cancel teleport.
1784 if (mons_has_ench( mon, ENCH_TP_I, ENCH_TP_IV ))
1785 ret = true;
1786 break;
1787
1788 case MS_TELEPORT_OTHER:
1789 // Monsters aren't smart enough to know when to cancel teleport.
1790 if (mon->foe == MHITYOU)
1791 {
1792 if (you.duration[DUR_TELEPORT])
1793 return (true);
1794 }
1795 else if (mon->foe != MHITNOT)
1796 {
1797 if (mons_has_ench( &menv[mon->foe], ENCH_TP_I, ENCH_TP_IV))
1798 return (true);
1799 }
1800 // intentional fall-through
1801
1802 case MS_SLOW:
1803 case MS_CONFUSE:
1804 case MS_PAIN:
1805 case MS_BANISHMENT:
1806 case MS_DISINTEGRATE:
1807 case MS_PARALYSIS:
1808 // occasionally we don't estimate... just fire and see:
1809 if (one_chance_in(5))
1810 return (false);
1811
1812 // Only intelligent monsters estimate.
1813 intel = mons_intel( mon->type );
1814 if (intel != I_NORMAL && intel != I_HIGH)
1815 return (false);
1816
1817 // We'll estimate the target's resistance to magic, by first getting
1818 // the actual value and then randomizing it.
1819 est_magic_resist = (mon->foe == MHITNOT) ? 10000 : 0;
1820
1821 if (mon->foe != MHITNOT)
1822 {
1823 if (mon->foe == MHITYOU)
1824 est_magic_resist = player_res_magic();
1825 else
1826 {
1827 targ = &menv[ mon->foe ];
1828 est_magic_resist = mons_resist_magic( targ );
1829 }
1830
1831 // now randomize (normal intels less accurate than high):
1832 if (intel == I_NORMAL)
1833 est_magic_resist += random2(80) - 40;
1834 else
1835 est_magic_resist += random2(30) - 15;
1836 }
1837
1838 power = 12 * mon->hit_dice * (monspell == MS_PAIN ? 2 : 1);
1839 power = stepdown_value( power, 30, 40, 100, 120 );
1840
1841 // Determine the amount of chance allowed by the benefit from
1842 // the spell. The estimated difficulty is the probability
1843 // of rolling over 100 + diff on 2d100. -- bwr
1844 diff = (monspell == MS_PAIN
1845 || monspell == MS_SLOW
1846 || monspell == MS_CONFUSE) ? 0 : 50;
1847
1848 if (est_magic_resist - power > diff)
1849 ret = true;
1850
1851 break;
1852
1853 default:
1854 break;
1855 }
1856
1857 return (ret);
1858 }
1859
ms_ranged_spell(int monspell)1860 static bool ms_ranged_spell( int monspell )
1861 {
1862 switch (monspell)
1863 {
1864 case MS_HASTE:
1865 case MS_HEAL:
1866 case MS_TELEPORT:
1867 case MS_INVIS:
1868 case MS_BLINK:
1869 return (false);
1870
1871 default:
1872 break;
1873 }
1874
1875 return (true);
1876 }
1877
mons_has_ranged_spell(struct monsters * mon)1878 bool mons_has_ranged_spell( struct monsters *mon )
1879 {
1880 const int mclass = mon->type;
1881
1882 if (mons_flag( mclass, M_SPELLCASTER ))
1883 {
1884 const int msecc = ((mclass == MONS_HELLION) ? MST_BURNING_DEVIL :
1885 (mclass == MONS_PANDEMONIUM_DEMON) ? MST_GHOST
1886 : mon->number);
1887
1888 int hspell_pass[6] = { MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL,
1889 MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL };
1890
1891 mons_spell_list( msecc, hspell_pass );
1892
1893 for (int i = 0; i < 6; i++)
1894 {
1895 if (ms_ranged_spell( hspell_pass[i] ))
1896 return (true);
1897 }
1898 }
1899
1900 return (false);
1901 }
1902
mons_has_ranged_attack(struct monsters * mon)1903 bool mons_has_ranged_attack( struct monsters *mon )
1904 {
1905 const int weapon = mon->inv[MSLOT_WEAPON];
1906 const int ammo = mon->inv[MSLOT_MISSILE];
1907
1908 const int lnchClass = (weapon != NON_ITEM) ? mitm[weapon].base_type : -1;
1909 const int lnchType = (weapon != NON_ITEM) ? mitm[weapon].sub_type : 0;
1910
1911 const int ammoClass = (ammo != NON_ITEM) ? mitm[ammo].base_type : -1;
1912 const int ammoType = (ammo != NON_ITEM) ? mitm[ammo].sub_type : 0;
1913
1914 bool launched = false;
1915 bool thrown = false;
1916
1917 throw_type( lnchClass, lnchType, ammoClass, ammoType, launched, thrown );
1918
1919 if (launched || thrown)
1920 return (true);
1921
1922 return (false);
1923 }
1924
1925
1926 // use of variant:
1927 // 0 : She is tap dancing.
1928 // 1 : It seems she is tap dancing. (lower case pronoun)
1929 // 2 : Her sword explodes! (upper case possessive)
1930 // 3 : It sticks to her sword! (lower case possessive)
1931 // ... as needed
1932
mons_pronoun(int mon_type,int variant)1933 const char *mons_pronoun(int mon_type, int variant)
1934 {
1935 int gender = GENDER_NEUTER;
1936
1937 if (mons_is_unique( mon_type ))
1938 {
1939 switch(mon_type)
1940 {
1941 case MONS_JESSICA:
1942 case MONS_PSYCHE:
1943 case MONS_JOSEPHINE:
1944 case MONS_AGNES:
1945 case MONS_MAUD:
1946 case MONS_LOUISE:
1947 case MONS_FRANCES:
1948 case MONS_MARGERY:
1949 case MONS_EROLCHA:
1950 case MONS_ERICA:
1951 gender = GENDER_FEMALE;
1952 break;
1953 default:
1954 gender = GENDER_MALE;
1955 break;
1956 }
1957 }
1958
1959 switch(variant)
1960 {
1961 case PRONOUN_CAP:
1962 return ((gender == 0) ? "It" :
1963 (gender == 1) ? "He" : "She");
1964
1965 case PRONOUN_NOCAP:
1966 return ((gender == 0) ? "it" :
1967 (gender == 1) ? "he" : "she");
1968
1969 case PRONOUN_CAP_POSSESSIVE:
1970 return ((gender == 0) ? "Its" :
1971 (gender == 1) ? "His" : "Her");
1972
1973 case PRONOUN_NOCAP_POSSESSIVE:
1974 return ((gender == 0) ? "its" :
1975 (gender == 1) ? "his" : "her");
1976
1977 case PRONOUN_REFLEXIVE: // awkward at start of sentence, always lower
1978 return ((gender == 0) ? "itself" :
1979 (gender == 1) ? "himself" : "herself");
1980 }
1981
1982 return ("");
1983 }
1984