summaryrefslogtreecommitdiffstats
path: root/stone_soup/crawl-ref/source/mon-util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'stone_soup/crawl-ref/source/mon-util.cc')
-rw-r--r--stone_soup/crawl-ref/source/mon-util.cc2209
1 files changed, 0 insertions, 2209 deletions
diff --git a/stone_soup/crawl-ref/source/mon-util.cc b/stone_soup/crawl-ref/source/mon-util.cc
deleted file mode 100644
index 7ce15b9660..0000000000
--- a/stone_soup/crawl-ref/source/mon-util.cc
+++ /dev/null
@@ -1,2209 +0,0 @@
-/*
- * File: mon-util.cc
- * Summary: Misc monster related functions.
- * Written by: Linley Henzell
- *
- * Modified for Crawl Reference by $Author$ on $Date$
- *
- * Change History (most recent first):
- *
- * <2> 11/04/99 cdl added a break to spell selection
- * for kobold Summoners
- * print just "[Ii]t" for invisible undead
- * renamed params to monam()
- * <1> -/--/-- LRH Created
- */
-
-// $pellbinder: (c) D.G.S.E 1998
-// some routines snatched from former monsstat.cc
-
-#include "AppHdr.h"
-#include "mon-util.h"
-#include "monstuff.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "externs.h"
-
-#include "debug.h"
-#include "itemname.h"
-#include "itemprop.h"
-#include "mstuff2.h"
-#include "player.h"
-#include "randart.h"
-#include "stuff.h"
-#include "view.h"
-
-//jmf: moved from inside function
-static FixedVector < int, NUM_MONSTERS > mon_entry;
-
-// really important extern -- screen redraws suck w/o it {dlb}
-FixedVector < unsigned short, 1000 > mcolour;
-
-static struct monsterentry mondata[] = {
-#include "mon-data.h"
-};
-
-#define MONDATASIZE (sizeof(mondata)/sizeof(struct monsterentry))
-
-static int mspell_list[][7] = {
-#include "mon-spll.h"
-};
-
-#if DEBUG_DIAGNOSTICS
-static const char *monster_spell_name[] = {
- "Magic Missile",
- "Throw Flame",
- "Throw Frost",
- "Paralysis",
- "Slow",
- "Haste",
- "Confuse",
- "Venom Bolt",
- "Fire Bolt",
- "Cold Bolt",
- "Lightning Bolt",
- "Invisibility",
- "Fireball",
- "Heal",
- "Teleport",
- "Teleport Other",
- "Blink",
- "Crystal Spear",
- "Dig",
- "Negative Bolt",
- "Hellfire Burst",
- "Vampire Summon",
- "Orb Energy",
- "Brain Feed",
- "Level Summon",
- "Fake Rakshasa Summon",
- "Steam Ball",
- "Summon Demon",
- "Animate Dead",
- "Pain",
- "Smite",
- "Sticky Flame",
- "Poison Blast",
- "Summon Demon Lesser",
- "Summon Ufetubus",
- "Purple Blast",
- "Summon Beast",
- "Energy Bolt",
- "Sting",
- "Iron Bolt",
- "Stone Arrow",
- "Poison Splash",
- "Summon Undead",
- "Mutation",
- "Cantrip",
- "Disintegrate",
- "Marsh Gas",
- "Quicksilver Bolt",
- "Torment",
- "Hellfire",
- "Metal Splinters",
- "Summon Demon Greater",
- "Banishment",
-};
-#endif
-
-static int mons_exp_mod(int mclass);
-static monsterentry *seekmonster(int p_monsterid);
-
-// macro that saves some typing, nothing more
-#define smc seekmonster(mc)
-
-/* ******************** BEGIN PUBLIC FUNCTIONS ******************** */
-void init_monsters(FixedVector < unsigned short, 1000 > &colour)
-{
- unsigned int x; // must be unsigned to match size_t {dlb}
-
- for (x = 0; x < MONDATASIZE; x++)
- colour[mondata[x].mc] = mondata[x].colour;
-
- //unsigned int x = 0; // must be unsigned to match size_t {dlb}
-
- // first, fill static array with dummy values {dlb};
- for (x = 0; x < NUM_MONSTERS; x++)
- mon_entry[x] = -1;
-
- // next, fill static array with location of entry in mondata[] {dlb}:
- for (x = 0; x < MONDATASIZE; x++)
- mon_entry[mondata[x].mc] = x;
-
- // finally, monsters yet with dummy entries point to TTTSNB(tm) {dlb}:
- for (x = 0; x < NUM_MONSTERS; x++)
- {
- if (mon_entry[x] == -1)
- mon_entry[x] = mon_entry[MONS_PROGRAM_BUG];
- }
- //return (monsterentry *) 0; // return value should not matter here {dlb}
-} // end mons_init()
-
-unsigned long get_mons_class_resists(int mc)
-{
- return (smc->resists);
-}
-
-unsigned long mons_class_resist(int mc, unsigned long flags)
-{
- return (smc->resists & flags);
-}
-
-bool mons_class_flag(int mc, int bf)
-{
- return ((smc->bitfields & bf) != 0);
-} // end mons_class_flag()
-
-static int scan_mon_inv_randarts( struct monsters *mon, int ra_prop )
-{
- int ret = 0;
-
- if (mons_itemuse( mon->type ) >= MONUSE_STARTING_EQUIPMENT)
- {
- const int weapon = mon->inv[MSLOT_WEAPON];
- const int second = mon->inv[MSLOT_MISSILE]; // ettins/two-head oges
- const int armour = mon->inv[MSLOT_ARMOUR];
-
- if (weapon != NON_ITEM && mitm[weapon].base_type == OBJ_WEAPONS
- && is_random_artefact( mitm[weapon] ))
- {
- ret += randart_wpn_property( mitm[weapon], ra_prop );
- }
-
- if (second != NON_ITEM && mitm[second].base_type == OBJ_WEAPONS
- && is_random_artefact( mitm[second] ))
- {
- ret += randart_wpn_property( mitm[second], ra_prop );
- }
-
- if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR
- && is_random_artefact( mitm[armour] ))
- {
- ret += randart_wpn_property( mitm[armour], ra_prop );
- }
- }
-
- return (ret);
-}
-
-mon_holy_type mons_holiness(const monsters *mon)
-{
- return (mons_class_holiness(mon->type));
-}
-
-mon_holy_type mons_class_holiness(int mc)
-{
- return (smc->holiness);
-} // end mons_holiness()
-
-bool mons_is_stationary(const monsters *mons)
-{
- return (mons->type == MONS_OKLOB_PLANT
- || mons->type == MONS_PLANT
- || mons->type == MONS_FUNGUS
- || mons->type == MONS_CURSE_SKULL
- || (mons->type >= MONS_CURSE_TOE
- && mons->type <= MONS_POTION_MIMIC));
-}
-
-bool invalid_monster(const monsters *mons)
-{
- return (!mons || mons->type == -1);
-}
-
-bool mons_is_mimic( int mc )
-{
- return (mons_species( mc ) == MONS_GOLD_MIMIC);
-}
-
-bool mons_is_demon( int mc )
-{
- const int show_char = mons_char( mc );
-
- // Not every demonic monster is a demon (ie hell hog, hell hound)
- if (mons_class_holiness( mc ) == MH_DEMONIC
- && (isdigit( show_char ) || show_char == '&'))
- {
- return (true);
- }
-
- return (false);
-}
-
-// Used for elven Glamour ability. -- bwr
-bool mons_is_humanoid( int mc )
-{
- switch (mons_char( mc))
- {
- case 'o': // orcs
- case 'e': // elvens (deep)
- case 'c': // centaurs
- case 'C': // giants
- case 'O': // ogres
- case 'K': // kobolds
- case 'N': // nagas
- case '@': // adventuring humans
- case 'T': // trolls
- return (true);
-
- case 'g': // goblines, hobgoblins, gnolls, boggarts -- but not gargoyles
- if (mc != MONS_GARGOYLE
- && mc != MONS_METAL_GARGOYLE
- && mc != MONS_MOLTEN_GARGOYLE)
- {
- return (true);
- }
-
- default:
- break;
- }
-
- return (false);
-}
-
-int mons_zombie_size(int mc)
-{
- return (smc->zombie_size);
-} // end mons_zombie_size()
-
-
-int mons_weight(int mc)
-{
- return (smc->weight);
-} // end mons_weight()
-
-corpse_effect_type mons_corpse_effect(int mc)
-{
- return (smc->corpse_thingy);
-} // end mons_corpse_effect()
-
-
-monster_type mons_species( int mc )
-{
- return (smc->species);
-} // end mons_species()
-
-monster_type mons_genus( int mc )
-{
- return (smc->genus);
-}
-
-monster_type draco_subspecies( const monsters *mon )
-{
- ASSERT( mons_genus( mon->type ) == MONS_DRACONIAN );
-
- monster_type ret = mons_species( mon->type );
-
- if (ret == MONS_DRACONIAN && mon->type != MONS_DRACONIAN)
- ret = static_cast<monster_type>( mon->number );
-
- return (ret);
-}
-
-int mons_shouts(int mc)
-{
- int u = smc->shouts;
-
- if (u == -1)
- u = random2(12);
-
- return (u);
-} // end mons_shouts()
-
-bool mons_is_unique( int mc )
-{
- if (mc <= MONS_PROGRAM_BUG
- || (mc >= MONS_NAGA_MAGE && mc <= MONS_ROYAL_JELLY)
- || (mc >= MONS_DRACONIAN && mc <= MONS_DRACONIAN_SCORCHER)
- || (mc >= MONS_ANCIENT_LICH
- && (mc != MONS_PLAYER_GHOST && mc != MONS_PANDEMONIUM_DEMON)))
- {
- return (false);
- }
-
- return (true);
-}
-
-char mons_see_invis( struct monsters *mon )
-{
- if (mon->type == MONS_PLAYER_GHOST || mon->type == MONS_PANDEMONIUM_DEMON)
- return (ghost.values[ GVAL_SEE_INVIS ]);
- else if (((seekmonster(mon->type))->bitfields & M_SEE_INVIS) != 0)
- return (1);
- else if (scan_mon_inv_randarts( mon, RAP_EYESIGHT ) > 0)
- return (1);
-
- return (0);
-} // end mons_see_invis()
-
-
-// This does NOT do line of sight! It checks the targ's visibility
-// with respect to mon's perception, but doesn't do walls or range.
-bool mons_monster_visible( struct monsters *mon, struct monsters *targ )
-{
- if (mons_has_ench(targ, ENCH_SUBMERGED)
- || (mons_has_ench(targ, ENCH_INVIS) && !mons_see_invis(mon)))
- {
- return (false);
- }
-
- return (true);
-}
-
-// This does NOT do line of sight! It checks the player's visibility
-// with respect to mon's perception, but doesn't do walls or range.
-bool mons_player_visible( struct monsters *mon )
-{
- if (you.invis)
- {
- if (player_in_water())
- return (true);
-
- if (mons_see_invis( mon ))
- return (true);
-
- return (false);
- }
-
- return (true);
-}
-
-unsigned char mons_char(int mc)
-{
- return (unsigned char) smc->showchar;
-} // end mons_char()
-
-
-char mons_itemuse(int mc)
-{
- return (smc->gmon_use);
-} // end mons_itemuse()
-
-unsigned char mons_colour(int mc)
-{
- return (smc->colour);
-} // end mons_colour()
-
-
-int mons_damage(int mc, int rt)
-{
- ASSERT(rt >= 0);
- ASSERT(rt <= 3);
-
- if (rt < 0 || rt > 3) // make it fool-proof
- return (0);
-
- if (rt == 0 && (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON))
- return (ghost.values[ GVAL_DAMAGE ]);
-
- return (smc->damage[rt]);
-} // end mons_damage()
-
-int mons_resist_magic( struct monsters *mon )
-{
- int u = (seekmonster(mon->type))->resist_magic;
-
- // negative values get multiplied with mhd
- if (u < 0)
- u = mon->hit_dice * (-u * 2);
-
- u += scan_mon_inv_randarts( mon, RAP_MAGIC );
-
- // ego armour resistance
- const int armour = mon->inv[MSLOT_ARMOUR];
-
- if (armour != NON_ITEM
- && get_armour_ego_type( mitm[armour] ) == SPARM_MAGIC_RESISTANCE )
- {
- u += 30;
- }
-
- return (u);
-} // end mon_resist_magic()
-
-
-// Returns true if the monster made its save against hostile
-// enchantments/some other magics.
-bool check_mons_resist_magic( struct monsters *monster, int pow )
-{
- int mrs = mons_resist_magic(monster);
-
- if (mrs == 5000)
- return (true);
-
- // Evil, evil hack to make weak one hd monsters easier for first
- // level characters who have resistable 1st level spells. Six is
- // a very special value because mrs = hd * 2 * 3 for most monsters,
- // and the weak, low level monsters have been adjusted so that the
- // "3" is typically a 1. There are some notable one hd monsters
- // that shouldn't fall under this, so we do < 6, instead of <= 6...
- // or checking monster->hit_dice. The goal here is to make the
- // first level easier for these classes and give them a better
- // shot at getting to level two or three and spells that can help
- // them out (or building a level or two of their base skill so they
- // aren't resisted as often). -- bwr
- if (mrs < 6 && coinflip())
- return (false);
-
- pow = stepdown_value( pow, 30, 40, 100, 120 );
-
- const int mrchance = (100 + mrs) - pow;
- const int mrch2 = random2(100) + random2(101);
-
-#if DEBUG_DIAGNOSTICS
- snprintf( info, INFO_SIZE,
- "Power: %d, monster's MR: %d, target: %d, roll: %d",
- pow, mrs, mrchance, mrch2 );
-
- mpr( info, MSGCH_DIAGNOSTICS );
-#endif
-
- return ((mrch2 < mrchance) ? true : false);
-} // end check_mons_resist_magic()
-
-
-int mons_res_elec( struct monsters *mon )
-{
- int mc = mon->type;
-
- if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
- return (ghost.values[ GVAL_RES_ELEC ]);
-
- /* this is a variable, not a player_xx() function, so can be above 1 */
- int u = 0;
-
- if (mons_class_resist( mon->type, MR_RES_ELEC))
- u++;
-
- // don't bother checking equipment if the monster can't use it
- if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
- {
- u += scan_mon_inv_randarts( mon, RAP_ELECTRICITY );
-
- // no ego armour, but storm dragon.
- const int armour = mon->inv[MSLOT_ARMOUR];
- if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR
- && mitm[armour].sub_type == ARM_STORM_DRAGON_ARMOUR)
- {
- u += 1;
- }
- }
-
- return (u);
-} // end mons_res_elec()
-
-bool mons_res_asphyx( const monsters *mon )
-{
- const int holiness = mons_holiness( mon );
- return (holiness == MH_UNDEAD
- || holiness == MH_DEMONIC
- || holiness == MH_NONLIVING);
-}
-
-int mons_res_poison( struct monsters *mon )
-{
- int mc = mon->type;
-
- int u = 0, f = get_mons_class_resists(mc);
-
- if (f & MR_RES_POISON)
- u++;
-
- if (f & MR_VUL_POISON)
- u--;
-
- if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
- {
- u += scan_mon_inv_randarts( mon, RAP_POISON );
-
- const int armour = mon->inv[MSLOT_ARMOUR];
- if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
- {
- // intrinsic armour abilities
- switch (mitm[armour].sub_type)
- {
- case ARM_SWAMP_DRAGON_ARMOUR: u += 1; break;
- case ARM_GOLD_DRAGON_ARMOUR: u += 1; break;
- default: break;
- }
-
- // ego armour resistance
- if (get_armour_ego_type( mitm[armour] ) == SPARM_POISON_RESISTANCE)
- u += 1;
- }
- }
-
- return (u);
-} // end mons_res_poison()
-
-
-int mons_res_fire( struct monsters *mon )
-{
- int mc = mon->type;
-
- if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
- return (ghost.values[ GVAL_RES_FIRE ]);
-
- int u = 0, f = get_mons_class_resists(mc);
-
- // no Big Prize (tm) here either if you set all three flags. It's a pity uh?
- //
- // Note that natural monster resistance is two levels, this is duplicate
- // the fact that having this flag used to be a lot better than armour
- // for monsters (it used to make them immune in a lot of cases) -- bwr
- if (f & MR_RES_HELLFIRE)
- u += 3;
- else if (f & MR_RES_FIRE)
- u += 2;
- else if (f & MR_VUL_FIRE)
- u--;
-
- if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
- {
- u += scan_mon_inv_randarts( mon, RAP_POISON );
-
- const int armour = mon->inv[MSLOT_ARMOUR];
- if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
- {
- // intrinsic armour abilities
- switch (mitm[armour].sub_type)
- {
- case ARM_DRAGON_ARMOUR: u += 2; break;
- case ARM_GOLD_DRAGON_ARMOUR: u += 1; break;
- case ARM_ICE_DRAGON_ARMOUR: u -= 1; break;
- default: break;
- }
-
- // check ego resistance
- const int ego = get_armour_ego_type( mitm[armour] );
- if (ego == SPARM_FIRE_RESISTANCE || ego == SPARM_RESISTANCE)
- u += 1;
- }
- }
-
- return (u);
-} // end mons_res_fire()
-
-
-int mons_res_cold( struct monsters *mon )
-{
- int mc = mon->type;
-
- if (mc == MONS_PLAYER_GHOST || mc == MONS_PANDEMONIUM_DEMON)
- return (ghost.values[ GVAL_RES_COLD ]);
-
- int u = 0, f = get_mons_class_resists(mc);
-
- // Note that natural monster resistance is two levels, this is duplicate
- // the fact that having this flag used to be a lot better than armour
- // for monsters (it used to make them immune in a lot of cases) -- bwr
- if (f & MR_RES_COLD)
- u += 2;
- else if (f & MR_VUL_COLD)
- u--;
-
- if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
- {
- u += scan_mon_inv_randarts( mon, RAP_POISON );
-
- const int armour = mon->inv[MSLOT_ARMOUR];
- if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
- {
- // intrinsic armour abilities
- switch (mitm[armour].sub_type)
- {
- case ARM_ICE_DRAGON_ARMOUR: u += 2; break;
- case ARM_GOLD_DRAGON_ARMOUR: u += 1; break;
- case ARM_DRAGON_ARMOUR: u -= 1; break;
- default: break;
- }
-
- // check ego resistance
- const int ego = get_armour_ego_type( mitm[armour] );
- if (ego == SPARM_COLD_RESISTANCE || ego == SPARM_RESISTANCE)
- u += 1;
- }
- }
-
- return (u);
-} // end mons_res_cold()
-
-int mons_res_negative_energy( struct monsters *mon )
-{
- int mc = mon->type;
-
- if (mons_holiness(mon) == MH_UNDEAD
- || mons_holiness(mon) == MH_DEMONIC
- || mons_holiness(mon) == MH_NONLIVING
- || mons_holiness(mon) == MH_PLANT
- || mon->type == MONS_SHADOW_DRAGON
- || mon->type == MONS_DEATH_DRAKE)
- {
- return (3); // to match the value for players
- }
-
- int u = 0;
-
- if (mons_itemuse(mc) >= MONUSE_STARTING_EQUIPMENT)
- {
- u += scan_mon_inv_randarts( mon, RAP_NEGATIVE_ENERGY );
-
- const int armour = mon->inv[MSLOT_ARMOUR];
- if (armour != NON_ITEM && mitm[armour].base_type == OBJ_ARMOUR)
- {
- // check for ego resistance
- if (get_armour_ego_type( mitm[armour] ) == SPARM_POSITIVE_ENERGY)
- u += 1;
- }
- }
-
- return (u);
-} // end mons_res_negative_energy()
-
-bool mons_is_evil( const monsters *mon )
-{
- return (mons_class_flag( mon->type, M_EVIL ));
-}
-
-bool mons_is_unholy( const monsters *mon )
-{
- const mon_holy_type holy = mons_holiness( mon );
-
- return (holy == MH_UNDEAD || holy == MH_DEMONIC);
-}
-
-bool mons_has_lifeforce( const monsters *mon )
-{
- const int holy = mons_holiness( mon );
-
- return (holy == MH_NATURAL || holy == MH_PLANT);
- // && !mons_has_ench( mon, ENCH_PETRIFY ));
-}
-
-int mons_skeleton(int mc)
-{
- if (mons_zombie_size(mc) == 0
- || mons_weight(mc) == 0 || ((smc->bitfields & M_NO_SKELETON) != 0))
- {
- return (0);
- }
-
- return (1);
-} // end mons_skeleton()
-
-char mons_class_flies(int mc)
-{
- if (mc == MONS_PANDEMONIUM_DEMON)
- return (ghost.values[ GVAL_DEMONLORD_FLY ]);
-
- int f = smc->bitfields;
-
- if (f & M_FLIES)
- return (1);
-
- if (f & M_LEVITATE)
- return (2);
-
- return (0);
-}
-
-char mons_flies( struct monsters *mon )
-{
- char ret = mons_class_flies( mon->type );
-
- return (ret ? ret : (scan_mon_inv_randarts(mon, RAP_LEVITATE) > 0) ? 2 : 0);
-} // end mons_flies()
-
-
-// this nice routine we keep in exactly the way it was
-int hit_points(int hit_dice, int min_hp, int rand_hp)
-{
- int hrolled = 0;
-
- for (int hroll = 0; hroll < hit_dice; hroll++)
- {
- hrolled += random2(1 + rand_hp);
- hrolled += min_hp;
- }
-
- return (hrolled);
-} // end hit_points()
-
-// This function returns the standard number of hit dice for a type
-// of monster, not a pacticular monsters current hit dice. -- bwr
-int mons_type_hit_dice( int type )
-{
- struct monsterentry *mon_class = seekmonster( type );
-
- if (mon_class)
- return (mon_class->hpdice[0]);
-
- return (0);
-}
-
-
-int exper_value( struct monsters *monster )
-{
- long x_val = 0;
-
- // these three are the original arguments:
- const int mclass = monster->type;
- const int mHD = monster->hit_dice;
- const int maxhp = monster->max_hit_points;
-
- // these are some values we care about:
- const int speed = mons_speed(mclass);
- const int modifier = mons_exp_mod(mclass);
- const int item_usage = mons_itemuse(mclass);
-
- // XXX: shapeshifters can qualify here, even though they can't cast:
- const bool spellcaster = mons_class_flag( mclass, M_SPELLCASTER );
-
- // early out for no XP monsters
- if (mons_class_flag(mclass, M_NO_EXP_GAIN))
- return (0);
-
- // These undead take damage to maxhp, so we use only HD. -- bwr
- if (mclass == MONS_ZOMBIE_SMALL
- || mclass == MONS_ZOMBIE_LARGE
- || mclass == MONS_SIMULACRUM_SMALL
- || mclass == MONS_SIMULACRUM_LARGE
- || mclass == MONS_SKELETON_SMALL
- || mclass == MONS_SKELETON_LARGE)
- {
- x_val = (16 + mHD * 4) * (mHD * mHD) / 10;
- }
- else
- {
- x_val = (16 + maxhp) * (mHD * mHD) / 10;
- }
-
-
- // Let's calculate a simple difficulty modifier -- bwr
- int diff = 0;
-
- // Let's look for big spells:
- if (spellcaster)
- {
- const int msecc = ((mclass == MONS_HELLION) ? MST_BURNING_DEVIL :
- (mclass == MONS_PANDEMONIUM_DEMON) ? MST_GHOST
- : monster->number);
-
- int hspell_pass[6] = { MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL,
- MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL };
-
- mons_spell_list( msecc, hspell_pass );
-
- for (int i = 0; i < 6; i++)
- {
- switch (hspell_pass[i])
- {
- case MS_PARALYSIS:
- case MS_SMITE:
- case MS_HELLFIRE_BURST:
- case MS_HELLFIRE:
- case MS_TORMENT:
- case MS_IRON_BOLT:
- diff += 25;
- break;
-
- case MS_LIGHTNING_BOLT:
- case MS_NEGATIVE_BOLT:
- case MS_VENOM_BOLT:
- case MS_STICKY_FLAME:
- case MS_DISINTEGRATE:
- case MS_SUMMON_DEMON_GREATER:
- case MS_BANISHMENT:
- case MS_CRYSTAL_SPEAR:
- case MS_TELEPORT:
- case MS_TELEPORT_OTHER:
- diff += 10;
- break;
-
- default:
- break;
- }
- }
- }
-
- // let's look at regeneration
- if (monster_descriptor( mclass, MDSC_REGENERATES ))
- diff += 15;
-
- // Monsters at normal or fast speed with big melee damage
- if (speed >= 10)
- {
- int max_melee = 0;
- for (int i = 0; i < 4; i++)
- max_melee += mons_damage( mclass, i );
-
- if (max_melee > 30)
- diff += (max_melee / ((speed == 10) ? 2 : 1));
- }
-
- // Monsters who can use equipment (even if only the equipment
- // they are given) can be considerably enhanced because of
- // the way weapons work for monsters. -- bwr
- if (item_usage == MONUSE_STARTING_EQUIPMENT
- || item_usage == MONUSE_WEAPONS_ARMOUR)
- {
- diff += 30;
- }
-
- // Set a reasonable range on the difficulty modifier...
- // Currently 70% - 200% -- bwr
- if (diff > 100)
- diff = 100;
- else if (diff < -30)
- diff = -30;
-
- // Apply difficulty
- x_val *= (100 + diff);
- x_val /= 100;
-
- // Basic speed modification
- if (speed > 0)
- {
- x_val *= speed;
- x_val /= 10;
- }
-
- // Slow monsters without spells and items often have big HD which
- // cause the experience value to be overly large... this tries
- // to reduce the inappropriate amount of XP that results. -- bwr
- if (speed < 10 && !spellcaster && item_usage < MONUSE_STARTING_EQUIPMENT)
- {
- x_val /= 2;
- }
-
- // Apply the modifier in the monster's definition
- if (modifier > 0)
- {
- x_val *= modifier;
- x_val /= 10;
- }
-
- // Reductions for big values. -- bwr
- if (x_val > 100)
- x_val = 100 + ((x_val - 100) * 3) / 4;
- if (x_val > 1000)
- x_val = 1000 + (x_val - 1000) / 2;
-
- // guarantee the value is within limits
- if (x_val <= 0)
- x_val = 1;
- else if (x_val > 15000)
- x_val = 15000;
-
- return (x_val);
-} // end exper_value()
-
-void mons_spell_list(const monsters *monster, int splist[6])
-{
- int msecc = ((monster->type == MONS_HELLION) ? MST_BURNING_DEVIL :
- (monster->type == MONS_PANDEMONIUM_DEMON) ? MST_GHOST
- : monster->number);
- return mons_spell_list(msecc, splist);
-}
-
-// this needs to be rewritten a la the monsterseek rewrite {dlb}:
-void mons_spell_list( int sec, int splist[6] )
-{
- unsigned int x;
-
- for (x = 0; x < NUM_MSTYPES; x++)
- {
- if (mspell_list[x][0] == sec)
- break;
- }
-
- if (x >= NUM_MSTYPES)
- return;
-
- // I *KNOW* this can easily be done in a loop
- splist[0] = mspell_list[x][1]; // bolt spell
- splist[1] = mspell_list[x][2]; // enchantment
- splist[2] = mspell_list[x][3]; // self_ench
- splist[3] = mspell_list[x][4]; // misc
- splist[4] = mspell_list[x][5]; // misc2
- splist[5] = mspell_list[x][6]; // emergency
-
- if (sec == MST_GHOST) /* ghost */
- {
- for (x = 0; x < 6; x++)
- splist[x] = ghost.values[ GVAL_SPELL_1 + x ];
- }
-} // end mons_spell_list()
-
-#if DEBUG_DIAGNOSTICS
-const char *mons_spell_name( int spell )
-{
- if (spell == MS_NO_SPELL || spell >= NUM_MONSTER_SPELLS || spell < 0)
- return ("No spell");
-
- return (monster_spell_name[ spell ]);
-}
-#endif
-
-// generate a shiny new and unscarred monster
-void define_monster(int k)
-{
- int temp_rand = 0; // probability determination {dlb}
- int m2_class = menv[k].type;
- int m2_HD, m2_hp, m2_hp_max, m2_AC, m2_ev, m2_speed;
- int m2_sec = menv[k].number;
- struct monsterentry *m = seekmonster(m2_class);
-
- m2_HD = m->hpdice[0];
-
- // misc
- m2_AC = m->AC;
- m2_ev = m->ev;
-
- // speed
- m2_speed = m->speed;
-
- // some monsters are randomized:
- // did I get them all? // I don't think so {dlb}
- if (mons_is_mimic( m2_class ))
- m2_sec = get_mimic_colour( &menv[k] );
- else
- {
- switch (m2_class)
- {
- case MONS_ABOMINATION_SMALL:
- m2_HD = 4 + random2(4);
- m2_AC = 3 + random2(7);
- m2_ev = 7 + random2(6);
- m2_speed = 7 + random2avg(9, 2);
-
- if (m2_sec == 250)
- m2_sec = random_colour();
- break;
-
- case MONS_ZOMBIE_SMALL:
- m2_HD = (coinflip() ? 1 : 2);
- break;
-
- case MONS_ZOMBIE_LARGE:
- m2_HD = 3 + random2(5);
- break;
-
- case MONS_ABOMINATION_LARGE:
- m2_HD = 8 + random2(4);
- m2_AC = 5 + random2avg(9, 2);
- m2_ev = 3 + random2(5);
- m2_speed = 6 + random2avg(7, 2);
-
- if (m2_sec == 250)
- m2_sec = random_colour();
- break;
-
- case MONS_BEAST:
- m2_HD = 4 + random2(4);
- m2_AC = 2 + random2(5);
- m2_ev = 7 + random2(5);
- m2_speed = 8 + random2(5);
- break;
-
- case MONS_HYDRA:
- m2_sec = 4 + random2(5);
- break;
-
- case MONS_DEEP_ELF_FIGHTER:
- case MONS_DEEP_ELF_KNIGHT:
- case MONS_DEEP_ELF_SOLDIER:
- case MONS_ORC_WIZARD:
- m2_sec = MST_ORC_WIZARD_I + random2(3);
- break;
-
- case MONS_LICH:
- case MONS_ANCIENT_LICH:
- m2_sec = MST_LICH_I + random2(4);
- break;
-
- case MONS_HELL_KNIGHT:
- m2_sec = (coinflip() ? MST_HELL_KNIGHT_I : MST_HELL_KNIGHT_II);
- break;
-
- case MONS_NECROMANCER:
- m2_sec = (coinflip() ? MST_NECROMANCER_I : MST_NECROMANCER_II);
- break;
-
- case MONS_WIZARD:
- case MONS_OGRE_MAGE:
- case MONS_EROLCHA:
- case MONS_DEEP_ELF_MAGE:
- m2_sec = MST_WIZARD_I + random2(5);
- break;
-
- case MONS_DEEP_ELF_CONJURER:
- m2_sec = (coinflip()? MST_DEEP_ELF_CONJURER_I : MST_DEEP_ELF_CONJURER_II);
- break;
-
- case MONS_BUTTERFLY:
- case MONS_SPATIAL_VORTEX:
- case MONS_KILLER_KLOWN:
- m2_sec = random_colour();
- break;
-
- case MONS_GILA_MONSTER:
- temp_rand = random2(7);
-
- m2_sec = (temp_rand >= 5 ? LIGHTRED : // 2/7
- temp_rand >= 3 ? LIGHTMAGENTA : // 2/7
- temp_rand == 2 ? RED : // 1/7
- temp_rand == 1 ? MAGENTA // 1/7
- : YELLOW); // 1/7
- break;
-
- case MONS_HUMAN:
- case MONS_ELF:
- // these are supposed to only be created by polymorph
- m2_HD += random2(10);
- m2_AC += random2(5);
- m2_ev += random2(5);
- break;
-
- default:
- break;
- }
- }
-
- // some calculations
- m2_hp = hit_points(m2_HD, m->hpdice[1], m->hpdice[2]);
- m2_hp += m->hpdice[3];
- m2_hp_max = m2_hp;
-
- if (m2_sec == 250)
- m2_sec = m->sec;
-
- // so let it be written, so let it be done
- menv[k].hit_dice = m2_HD;
- menv[k].hit_points = m2_hp;
- menv[k].max_hit_points = m2_hp_max;
- menv[k].armour_class = m2_AC;
- menv[k].evasion = m2_ev;
- menv[k].speed = m2_speed;
- menv[k].speed_increment = 70;
- menv[k].number = m2_sec;
- menv[k].flags = 0;
-
- // reset monster enchantments
- for (int i = 0; i < NUM_MON_ENCHANTS; i++)
- menv[k].enchantment[i] = ENCH_NONE;
-} // end define_monster()
-
-
-/* ------------------------- monam/moname ------------------------- */
-const char *ptr_monam( struct monsters *mon, char desc )
-{
- // We give an item type description for mimics now, note that
- // since gold mimics only have one description (to match the
- // examine code in direct.cc), we won't bother going through
- // this for them. -- bwr
- if (mons_is_mimic( mon->type ) && mon->type != MONS_GOLD_MIMIC)
- {
- static char mimic_name_buff[ ITEMNAME_SIZE ];
-
- item_def item;
- get_mimic_item( mon, item );
- item_name( item, desc, mimic_name_buff );
-
- return (mimic_name_buff);
- }
-
- return (monam( mon->number, mon->type, player_monster_visible( mon ),
- desc, mon->inv[MSLOT_WEAPON] ));
-}
-
-const char *monam( int mons_num, int mons, bool vis, char desc, int mons_wpn )
-{
- static char gmo_n[ ITEMNAME_SIZE ];
- char gmo_n2[ ITEMNAME_SIZE ] = "";
-
- gmo_n[0] = '\0';
-
- // If you can't see the critter, let moname() print [Ii]t.
- if (!vis)
- {
- moname( mons, vis, desc, gmo_n );
- return (gmo_n);
- }
-
- // These need their description level handled here instead of
- // in monam().
- if (mons == MONS_SPECTRAL_THING)
- {
- switch (desc)
- {
- case DESC_CAP_THE:
- strcpy(gmo_n, "The");
- break;
- case DESC_NOCAP_THE:
- strcpy(gmo_n, "the");
- break;
- case DESC_CAP_A:
- strcpy(gmo_n, "A");
- break;
- case DESC_NOCAP_A:
- strcpy(gmo_n, "a");
- break;
- case DESC_PLAIN: /* do nothing */ ;
- break;
- //default: DEBUGSTR("bad desc flag");
- }
- }
-
- switch (mons)
- {
- case MONS_ZOMBIE_SMALL:
- case MONS_ZOMBIE_LARGE:
- moname(mons_num, vis, desc, gmo_n);
- strcat(gmo_n, " zombie");
- break;
-
- case MONS_SKELETON_SMALL:
- case MONS_SKELETON_LARGE:
- moname(mons_num, vis, desc, gmo_n);
- strcat(gmo_n, " skeleton");
- break;
-
- case MONS_SIMULACRUM_SMALL:
- case MONS_SIMULACRUM_LARGE:
- moname(mons_num, vis, desc, gmo_n);
- strcat(gmo_n, " simulacrum");
- break;
-
- case MONS_SPECTRAL_THING:
- strcat(gmo_n, " spectral ");
- moname(mons_num, vis, DESC_PLAIN, gmo_n2);
- strcat(gmo_n, gmo_n2);
- break;
-
- case MONS_DANCING_WEAPON:
- // safety check -- if we don't have/know the weapon use default name
- if (mons_wpn == NON_ITEM)
- moname( mons, vis, desc, gmo_n );
- else
- {
- item_def item = mitm[mons_wpn];
- unset_ident_flags( item, ISFLAG_KNOW_CURSE | ISFLAG_KNOW_PLUSES );
- item_name( item, desc, gmo_n );
- }
- break;
-
- case MONS_PLAYER_GHOST:
- strcpy(gmo_n, ghost.name);
- strcat(gmo_n, "'s ghost");
- break;
-
- case MONS_PANDEMONIUM_DEMON:
- strcpy(gmo_n, ghost.name);
- break;
-
- default:
- moname(mons, vis, desc, gmo_n);
- break;
- }
-
- return (gmo_n);
-} // end monam()
-
-const char *moname(int mons_num, bool vis, char descrip, char glog[ ITEMNAME_SIZE ])
-{
- glog[0] = '\0';
-
- char gmon_name[ ITEMNAME_SIZE ] = "";
- strcpy( gmon_name, seekmonster( mons_num )->name );
-
- if (!vis)
- {
- switch (descrip)
- {
- case DESC_CAP_THE:
- case DESC_CAP_A:
- strcpy(glog, "It");
- break;
- case DESC_NOCAP_THE:
- case DESC_NOCAP_A:
- case DESC_PLAIN:
- strcpy(glog, "it");
- break;
- }
-
- strcpy(gmon_name, glog);
- return (glog);
- }
-
- if (!mons_is_unique( mons_num ))
- {
- switch (descrip)
- {
- case DESC_CAP_THE:
- strcpy(glog, "The ");
- break;
- case DESC_NOCAP_THE:
- strcpy(glog, "the ");
- break;
- case DESC_CAP_A:
- strcpy(glog, "A");
- break;
- case DESC_NOCAP_A:
- strcpy(glog, "a");
- break;
- case DESC_PLAIN:
- break;
- // default: DEBUGSTR("bad monster descrip flag");
- }
-
- if (descrip == DESC_CAP_A || descrip == DESC_NOCAP_A)
- {
- switch (toupper(gmon_name[0]))
- {
- case 'A':
- case 'E':
- case 'I':
- case 'O':
- case 'U':
- strcat(glog, "n ");
- break;
-
- default:
- strcat(glog, " ");
- break;
- }
- }
- }
-
- strcat(glog, gmon_name);
-
- return (glog);
-} // end moname()
-
-/* ********************* END PUBLIC FUNCTIONS ********************* */
-
-// see mons_init for initialization of mon_entry array.
-static monsterentry *seekmonster(int p_monsterid)
-{
- int me = mon_entry[p_monsterid];
-
- if (me >= 0) // PARANOIA
- return (&mondata[me]);
- else
- return (NULL);
-} // end seekmonster()
-
-static int mons_exp_mod(int mc)
-{
- return (smc->exp_mod);
-} // end mons_exp_mod()
-
-
-int mons_speed(int mc)
-{
- return (smc->speed);
-} // end mons_speed()
-
-
-int mons_intel(int mc) //jmf: "fixed" to work with new I_ types
-{
- switch (smc->intel)
- {
- case I_PLANT:
- return (I_PLANT);
- case I_INSECT:
- case I_REPTILE:
- return (I_INSECT);
- case I_ANIMAL:
- case I_ANIMAL_LIKE:
- return (I_ANIMAL);
- case I_NORMAL:
- return (I_NORMAL);
- case I_HIGH:
- return (I_HIGH);
- default:
- return (I_NORMAL);
- }
-} // ens mons_intel()
-
-
-int mons_intel_type(int mc) //jmf: new, used by my spells
-{
- return (smc->intel);
-} // end mons_intel_type()
-
-int mons_power(int mc)
-{
- // for now, just return monster hit dice.
- return (smc->hpdice[0]);
-}
-
-bool mons_aligned(int m1, int m2)
-{
- bool fr1, fr2;
- struct monsters *mon1, *mon2;
-
- if (m1 == MHITNOT || m2 == MHITNOT)
- return (true);
-
- if (m1 == MHITYOU)
- fr1 = true;
- else
- {
- mon1 = &menv[m1];
- fr1 = (mon1->attitude == ATT_FRIENDLY) || mons_has_ench(mon1, ENCH_CHARM);
- }
-
- if (m2 == MHITYOU)
- fr2 = true;
- else
- {
- mon2 = &menv[m2];
- fr2 = (mon2->attitude == ATT_FRIENDLY) || mons_has_ench(mon2, ENCH_CHARM);
- }
-
- return (fr1 == fr2);
-}
-
-bool mons_friendly(const monsters *m)
-{
- return (m->attitude == ATT_FRIENDLY || mons_has_ench(m, ENCH_CHARM));
-}
-
-bool mons_is_paralysed(const monsters *m)
-{
- return (m->speed_increment == 0);
-}
-
-bool mons_is_confused(const monsters *m)
-{
- return (mons_has_ench(m, ENCH_CONFUSION) &&
- !mons_class_flag(m->type, M_CONFUSED));
-}
-
-bool mons_is_fleeing(const monsters *m)
-{
- return (m->behaviour == BEH_FLEE);
-}
-
-bool mons_is_sleeping(const monsters *m)
-{
- return (m->behaviour == BEH_SLEEP);
-}
-
-bool mons_is_batty(const monsters *m)
-{
- return testbits(m->flags, MF_BATTY);
-}
-
-bool mons_looks_stabbable(const monsters *m)
-{
- // Make sure oklob plants are never highlighted. That'll defeat the
- // point of making them look like normal plants.
- return (!mons_class_flag(m->type, M_NO_EXP_GAIN)
- && m->type != MONS_OKLOB_PLANT
- && !mons_is_mimic(m->type)
- && !mons_friendly(m)
- && mons_is_sleeping(m));
-}
-
-bool mons_looks_distracted(const monsters *m)
-{
- return (!mons_class_flag(m->type, M_NO_EXP_GAIN)
- && m->type != MONS_OKLOB_PLANT
- && !mons_is_mimic(m->type)
- && !mons_friendly(m)
- && ((m->foe != MHITYOU && !mons_is_batty(m))
- || mons_is_confused(m)
- || mons_is_fleeing(m)));
-}
-
-/* ******************************************************************
-
-// In the name of England, I declare this function wasteful! {dlb}
-
-static monsterentry *seekmonster( int mc )
-{
-
- ASSERT(mc >= 0);
-
- int x = 0;
-
- while (x < mondatasize)
- {
- if (mondata[x].mc == mc)
- return &mondata[x];
-
- x++;
- }
-
- ASSERT(false);
-
- return seekmonster(MONS_PROGRAM_BUG); // see the disasters coming if there is no 250?
-
-} // end seekmonster()
-****************************************************************** */
-
-
-/* ******************************************************************
-
-// only used once, and internal to this file, to boot {dlb}:
-
-// These are easy to implement here. The difficult (dull!) work of converting
-// the data structures is finally finished now!
-inline char *mons_name( int mc )
-{
-
- return smc->name;
-
-} // end mons_name()
-****************************************************************** */
-
-/*****************************************************************
-
- Used to determine whether or not a monster should fire a beam (MUST be
- called _after_ fire_tracer() for meaningful result.
-
-*/
-
-bool mons_should_fire(struct bolt &beam)
-{
- // use of foeRatio:
- // the higher this number, the more monsters
- // will _avoid_ collateral damage to their friends.
- // setting this to zero will in fact have all
- // monsters ignore their friends when considering
- // collateral damage.
-
- // quick check - did we in fact get any foes?
- if (beam.foe_count == 0)
- return (false);
-
- // if we either hit no friends, or monster too dumb to care
- if (beam.fr_count == 0 || !beam.smart_monster)
- return (true);
-
- // only fire if they do acceptably low collateral damage
- // the default for this is 50%; in other words, don't
- // hit a foe unless you hit 2 or fewer friends.
- if (beam.foe_power >= (beam.foe_ratio * beam.fr_power) / 100)
- return (true);
-
- return (false);
-}
-
-int mons_has_ench(const monsters *mon, unsigned int ench, unsigned int ench2)
-{
- // silliness
- if (ench == ENCH_NONE)
- return (ench);
-
- if (ench2 == ENCH_NONE)
- ench2 = ench;
-
- for (int p = 0; p < NUM_MON_ENCHANTS; p++)
- {
- if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2)
- return (mon->enchantment[p]);
- }
-
- return (ENCH_NONE);
-}
-
-// Returning the deleted enchantment is important! See abjuration. -- bwr
-int mons_del_ench( struct monsters *mon, unsigned int ench, unsigned int ench2,
- bool quiet )
-{
- unsigned int p;
- int ret_val = ENCH_NONE;
-
- // silliness
- if (ench == ENCH_NONE)
- return (ENCH_NONE);
-
- if (ench2 == ENCH_NONE)
- ench2 = ench;
-
- for (p = 0; p < NUM_MON_ENCHANTS; p++)
- {
- if (mon->enchantment[p] >= ench && mon->enchantment[p] <= ench2)
- break;
- }
-
- if (p == NUM_MON_ENCHANTS)
- return (ENCH_NONE);
-
- ret_val = mon->enchantment[p];
- mon->enchantment[p] = ENCH_NONE;
-
- // check for slow/haste
- if (ench == ENCH_HASTE)
- {
- if (mon->speed >= 100)
- mon->speed = 100 + ((mon->speed - 100) / 2);
- else
- mon->speed /= 2;
- }
-
- if (ench == ENCH_SLOW)
- {
- if (mon->speed >= 100)
- mon->speed = 100 + ((mon->speed - 100) * 2);
- else
- mon->speed *= 2;
- }
-
- if (ench == ENCH_FEAR)
- {
- if (!quiet)
- simple_monster_message(mon, " seems to regain its courage.");
-
- // reevaluate behaviour
- behaviour_event(mon, ME_EVAL);
- }
-
- if (ench == ENCH_CONFUSION)
- {
- if (!quiet)
- simple_monster_message(mon, " seems less confused.");
-
- // reevaluate behaviour
- behaviour_event(mon, ME_EVAL);
- }
-
- if (ench == ENCH_INVIS)
- {
- // invisible monsters stay invisible
- if (mons_class_flag(mon->type, M_INVIS))
- {
- mon->enchantment[p] = ENCH_INVIS;
- }
- else if (mons_near(mon) && !player_see_invis()
- && !mons_has_ench( mon, ENCH_SUBMERGED ))
- {
- if (!quiet)
- {
- strcpy( info, ptr_monam( mon, DESC_CAP_A ) );
- strcat( info, " appears!" );
- mpr( info );
- }
- }
- }
-
- if (ench == ENCH_CHARM)
- {
- if (!quiet)
- simple_monster_message(mon, " is no longer charmed.");
-
- // reevaluate behaviour
- behaviour_event(mon, ME_EVAL);
- }
-
- if (ench == ENCH_BACKLIGHT_I)
- {
- if (!quiet)
- simple_monster_message(mon, " stops glowing.");
- }
-
- if (ench == ENCH_STICKY_FLAME_I || ench == ENCH_YOUR_STICKY_FLAME_I)
- {
- if (!quiet)
- simple_monster_message(mon, " stops burning.");
- }
-
- if (ench == ENCH_POISON_I || ench == ENCH_YOUR_POISON_I)
- {
- if (!quiet)
- simple_monster_message(mon, " looks more healthy.");
- }
-
- if (ench == ENCH_YOUR_ROT_I)
- {
- if (!quiet)
- simple_monster_message(mon, " is no longer rotting.");
- }
-
- return (ret_val);
-}
-
-bool mons_add_ench(struct monsters *mon, unsigned int ench)
-{
- // silliness
- if (ench == ENCH_NONE)
- return (false);
-
- int newspot = -1;
-
- // don't double-add
- for (int p = 0; p < NUM_MON_ENCHANTS; p++)
- {
- if (mon->enchantment[p] == ench)
- return (true);
-
- if (mon->enchantment[p] == ENCH_NONE && newspot < 0)
- newspot = p;
- }
-
- if (newspot < 0)
- return (false);
-
- mon->enchantment[newspot] = ench;
-// if ench == ENCH_FEAR //mv: withou this fear & repel undead spell doesn't work
-
-
- // check for slow/haste
- if (ench == ENCH_HASTE)
- {
- if (mon->speed >= 100)
- mon->speed = 100 + ((mon->speed - 100) * 2);
- else
- mon->speed *= 2;
- }
-
- if (ench == ENCH_SLOW)
- {
- if (mon->speed >= 100)
- mon->speed = 100 + ((mon->speed - 100) / 2);
- else
- mon->speed /= 2;
- }
-
- return (true);
-}
-
-// used to determine whether or not a monster should always
-// fire this spell if selected. If not, we should use a
-// tracer.
-
-// note - this function assumes that the monster is "nearby"
-// its target!
-
-bool ms_requires_tracer(int monspell)
-{
- bool requires = false;
-
- switch(monspell)
- {
- case MS_BANISHMENT:
- case MS_COLD_BOLT:
- case MS_CONFUSE:
- case MS_CRYSTAL_SPEAR:
- case MS_DISINTEGRATE:
- case MS_ENERGY_BOLT:
- case MS_FIRE_BOLT:
- case MS_FIREBALL:
- case MS_FLAME:
- case MS_FROST:
- case MS_HELLFIRE:
- case MS_IRON_BOLT:
- case MS_LIGHTNING_BOLT:
- case MS_MARSH_GAS:
- case MS_MIASMA:
- case MS_METAL_SPLINTERS:
- case MS_MMISSILE:
- case MS_NEGATIVE_BOLT:
- case MS_ORB_ENERGY:
- case MS_PAIN:
- case MS_PARALYSIS:
- case MS_POISON_BLAST:
- case MS_POISON_ARROW:
- case MS_POISON_SPLASH:
- case MS_QUICKSILVER_BOLT:
- case MS_SLOW:
- case MS_STEAM_BALL:
- case MS_STICKY_FLAME:
- case MS_STING:
- case MS_STONE_ARROW:
- case MS_TELEPORT_OTHER:
- case MS_VENOM_BOLT:
- requires = true;
- break;
-
- // self-niceties and direct effects
- case MS_ANIMATE_DEAD:
- case MS_BLINK:
- case MS_BRAIN_FEED:
- case MS_DIG:
- case MS_FAKE_RAKSHASA_SUMMON:
- case MS_HASTE:
- case MS_HEAL:
- case MS_HELLFIRE_BURST:
- case MS_INVIS:
- case MS_LEVEL_SUMMON:
- case MS_MUTATION:
- case MS_SMITE:
- case MS_SUMMON_BEAST:
- case MS_SUMMON_DEMON_LESSER:
- case MS_SUMMON_DEMON:
- case MS_SUMMON_DEMON_GREATER:
- case MS_SUMMON_UFETUBUS:
- case MS_TELEPORT:
- case MS_TORMENT:
- case MS_VAMPIRE_SUMMON:
- case MS_CANTRIP:
-
- // meaningless, but sure, why not?
- case MS_NO_SPELL:
- break;
-
- default:
- break;
-
- }
-
- return (requires);
-}
-
-// returns true if the spell is something you wouldn't want done if
-// you had a friendly target.. only returns a meaningful value for
-// non-beam spells
-
-bool ms_direct_nasty(int monspell)
-{
- bool nasty = true;
-
- switch(monspell)
- {
- // self-niceties/summonings
- case MS_ANIMATE_DEAD:
- case MS_BLINK:
- case MS_DIG:
- case MS_FAKE_RAKSHASA_SUMMON:
- case MS_HASTE:
- case MS_HEAL:
- case MS_INVIS:
- case MS_LEVEL_SUMMON:
- case MS_SUMMON_BEAST:
- case MS_SUMMON_DEMON_LESSER:
- case MS_SUMMON_DEMON:
- case MS_SUMMON_DEMON_GREATER:
- case MS_SUMMON_UFETUBUS:
- case MS_TELEPORT:
- case MS_VAMPIRE_SUMMON:
- nasty = false;
- break;
-
- case MS_BRAIN_FEED:
- case MS_HELLFIRE_BURST:
- case MS_MUTATION:
- case MS_SMITE:
- case MS_TORMENT:
-
- // meaningless, but sure, why not?
- case MS_NO_SPELL:
- break;
-
- default:
- break;
-
- }
-
- return (nasty);
-}
-
-// Spells a monster may want to cast if fleeing from the player, and
-// the player is not in sight.
-bool ms_useful_fleeing_out_of_sight( struct monsters *mon, int monspell )
-{
- if (ms_waste_of_time( mon, monspell ))
- return (false);
-
- switch (monspell)
- {
- case MS_HASTE:
- case MS_INVIS:
- case MS_HEAL:
- case MS_ANIMATE_DEAD:
- return (true);
-
- case MS_VAMPIRE_SUMMON:
- case MS_SUMMON_UFETUBUS:
- case MS_FAKE_RAKSHASA_SUMMON:
- case MS_LEVEL_SUMMON:
- case MS_SUMMON_DEMON:
- case MS_SUMMON_DEMON_LESSER:
- case MS_SUMMON_BEAST:
- case MS_SUMMON_UNDEAD:
- case MS_SUMMON_DEMON_GREATER:
- if (one_chance_in(10)) // only summon friends some of the time
- return (true);
- break;
-
- default:
- break;
- }
-
- return (false);
-}
-
-bool ms_low_hitpoint_cast( struct monsters *mon, int monspell )
-{
- bool ret = false;
-
- bool targ_adj = false;
-
- if (mon->foe == MHITYOU || mon->foe == MHITNOT)
- {
- if (adjacent(you.x_pos, you.y_pos, mon->x, mon->y))
- targ_adj = true;
- }
- else if (adjacent( menv[mon->foe].x, menv[mon->foe].y, mon->x, mon->y ))
- {
- targ_adj = true;
- }
-
- switch (monspell)
- {
- case MS_TELEPORT:
- case MS_TELEPORT_OTHER:
- case MS_HEAL:
- ret = true;
- break;
-
- case MS_BLINK:
- if (targ_adj)
- ret = true;
- break;
-
- case MS_VAMPIRE_SUMMON:
- case MS_SUMMON_UFETUBUS:
- case MS_FAKE_RAKSHASA_SUMMON:
- if (!targ_adj)
- ret = true;
- break;
- }
-
- return (ret);
-}
-
-// Checks to see if a particular spell is worth casting in the first place.
-bool ms_waste_of_time( struct monsters *mon, int monspell )
-{
- bool ret = false;
- int intel, est_magic_resist, power, diff;
- struct monsters *targ;
-
-
- // Eventually, we'll probably want to be able to have monsters
- // learn which of their elemental bolts were resisted and have those
- // handled here as well. -- bwr
- switch (monspell)
- {
- case MS_HASTE:
- if (mons_has_ench( mon, ENCH_HASTE ))
- ret = true;
- break;
-
- case MS_INVIS:
- if (mons_has_ench( mon, ENCH_INVIS ))
- ret = true;
- break;
-
- case MS_HEAL:
- if (mon->hit_points > mon->max_hit_points / 2)
- ret = true;
- break;
-
- case MS_TELEPORT:
- // Monsters aren't smart enough to know when to cancel teleport.
- if (mons_has_ench( mon, ENCH_TP_I, ENCH_TP_IV ))
- ret = true;
- break;
-
- case MS_TELEPORT_OTHER:
- // Monsters aren't smart enough to know when to cancel teleport.
- if (mon->foe == MHITYOU)
- {
- if (you.duration[DUR_TELEPORT])
- return (true);
- }
- else if (mon->foe != MHITNOT)
- {
- if (mons_has_ench( &menv[mon->foe], ENCH_TP_I, ENCH_TP_IV))
- return (true);
- }
- // intentional fall-through
-
- case MS_SLOW:
- case MS_CONFUSE:
- case MS_PAIN:
- case MS_BANISHMENT:
- case MS_DISINTEGRATE:
- case MS_PARALYSIS:
- // occasionally we don't estimate... just fire and see:
- if (one_chance_in(5))
- return (false);
-
- // Only intelligent monsters estimate.
- intel = mons_intel( mon->type );
- if (intel != I_NORMAL && intel != I_HIGH)
- return (false);
-
- // We'll estimate the target's resistance to magic, by first getting
- // the actual value and then randomizing it.
- est_magic_resist = (mon->foe == MHITNOT) ? 10000 : 0;
-
- if (mon->foe != MHITNOT)
- {
- if (mon->foe == MHITYOU)
- est_magic_resist = player_res_magic();
- else
- {
- targ = &menv[ mon->foe ];
- est_magic_resist = mons_resist_magic( targ );
- }
-
- // now randomize (normal intels less accurate than high):
- if (intel == I_NORMAL)
- est_magic_resist += random2(80) - 40;
- else
- est_magic_resist += random2(30) - 15;
- }
-
- power = 12 * mon->hit_dice * (monspell == MS_PAIN ? 2 : 1);
- power = stepdown_value( power, 30, 40, 100, 120 );
-
- // Determine the amount of chance allowed by the benefit from
- // the spell. The estimated difficulty is the probability
- // of rolling over 100 + diff on 2d100. -- bwr
- diff = (monspell == MS_PAIN
- || monspell == MS_SLOW
- || monspell == MS_CONFUSE) ? 0 : 50;
-
- if (est_magic_resist - power > diff)
- ret = true;
-
- break;
-
- default:
- break;
- }
-
- return (ret);
-}
-
-static bool ms_ranged_spell( int monspell )
-{
- switch (monspell)
- {
- case MS_HASTE:
- case MS_HEAL:
- case MS_TELEPORT:
- case MS_INVIS:
- case MS_BLINK:
- return (false);
-
- default:
- break;
- }
-
- return (true);
-}
-
-bool mons_has_ranged_spell( struct monsters *mon )
-{
- const int mclass = mon->type;
-
- if (mons_class_flag( mclass, M_SPELLCASTER ))
- {
- const int msecc = ((mclass == MONS_HELLION) ? MST_BURNING_DEVIL :
- (mclass == MONS_PANDEMONIUM_DEMON) ? MST_GHOST
- : mon->number);
-
- int hspell_pass[6] = { MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL,
- MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL };
-
- mons_spell_list( msecc, hspell_pass );
-
- for (int i = 0; i < 6; i++)
- {
- if (ms_ranged_spell( hspell_pass[i] ))
- return (true);
- }
- }
-
- return (false);
-}
-
-bool mons_has_ranged_attack( struct monsters *mon )
-{
- const int weapon = mon->inv[MSLOT_WEAPON];
- const int ammo = mon->inv[MSLOT_MISSILE];
-
- const int lnchClass = (weapon != NON_ITEM) ? mitm[weapon].base_type : -1;
- const int lnchType = (weapon != NON_ITEM) ? mitm[weapon].sub_type : 0;
-
- const int ammoClass = (ammo != NON_ITEM) ? mitm[ammo].base_type : -1;
- const int ammoType = (ammo != NON_ITEM) ? mitm[ammo].sub_type : 0;
-
- bool launched = false;
- bool thrown = false;
-
- throw_type( lnchClass, lnchType, ammoClass, ammoType, launched, thrown );
-
- if (launched || thrown)
- return (true);
-
- return (false);
-}
-
-
-// use of variant:
-// 0 : She is tap dancing.
-// 1 : It seems she is tap dancing. (lower case pronoun)
-// 2 : Her sword explodes! (upper case possessive)
-// 3 : It sticks to her sword! (lower case possessive)
-// ... as needed
-
-const char *mons_pronoun(int mon_type, int variant)
-{
- int gender = GENDER_NEUTER;
-
- if (mons_is_unique( mon_type ))
- {
- switch(mon_type)
- {
- case MONS_JESSICA:
- case MONS_PSYCHE:
- case MONS_JOSEPHINE:
- case MONS_AGNES:
- case MONS_MAUD:
- case MONS_LOUISE:
- case MONS_FRANCES:
- case MONS_MARGERY:
- case MONS_EROLCHA:
- case MONS_ERICA:
- gender = GENDER_FEMALE;
- break;
- default:
- gender = GENDER_MALE;
- break;
- }
- }
-
- switch(variant)
- {
- case PRONOUN_CAP:
- return ((gender == 0) ? "It" :
- (gender == 1) ? "He" : "She");
-
- case PRONOUN_NOCAP:
- return ((gender == 0) ? "it" :
- (gender == 1) ? "he" : "she");
-
- case PRONOUN_CAP_POSSESSIVE:
- return ((gender == 0) ? "Its" :
- (gender == 1) ? "His" : "Her");
-
- case PRONOUN_NOCAP_POSSESSIVE:
- return ((gender == 0) ? "its" :
- (gender == 1) ? "his" : "her");
-
- case PRONOUN_REFLEXIVE: // awkward at start of sentence, always lower
- return ((gender == 0) ? "itself" :
- (gender == 1) ? "himself" : "herself");
- }
-
- return ("");
-}
-
-/*
- * Checks if the monster can use smiting/torment to attack without unimpeded
- * LOS to the player.
- */
-static bool mons_can_smite(const monsters *monster)
-{
- if (monster->type == MONS_FIEND)
- return (true);
-
- int hspell_pass[6] = { MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL,
- MS_NO_SPELL, MS_NO_SPELL, MS_NO_SPELL };
- mons_spell_list(monster, hspell_pass);
- for (unsigned i = 0; i < sizeof(hspell_pass) / sizeof(hspell_pass[0]); ++i)
- if (hspell_pass[i] == MS_TORMENT || hspell_pass[i] == MS_SMITE)
- return (true);
-
- return (false);
-}
-
-/*
- * Determines if a monster is smart and pushy enough to displace other monsters.
- * A shover should not cause damage to the shovee by displacing it, so monsters
- * that trail clouds of badness are ineligible. The shover should also benefit
- * from shoving, so monsters that can smite/torment are ineligible.
- *
- * (Smiters would be eligible for shoving when fleeing if the AI allowed for
- * smart monsters to flee.)
- */
-bool monster_shover(const monsters *m)
-{
- const monsterentry *me = seekmonster(m->type);
- if (!me)
- return (false);
-
- // Efreet and fire elementals are disqualified because they leave behind
- // clouds of flame.
- if (m->type == MONS_EFREET || m->type == MONS_FIRE_ELEMENTAL
- || m->type == MONS_ROTTING_DEVIL)
- return (false);
-
- if (mons_can_smite(m))
- return (false);
-
- int mchar = me->showchar;
- // Somewhat arbitrary: giants and dragons are too big to get past anything,
- // beetles are too dumb (arguable), dancing weapons can't communicate, eyes
- // aren't pushers and shovers, zombies are zombies. Worms and elementals
- // are on the list because all 'w' are currently unrelated.
- return (mchar != 'C' && mchar != 'B' && mchar != '(' && mchar != 'D'
- && mchar != 'G' && mchar != 'Z' && mchar != 'z'
- && mchar != 'w' && mchar != '#');
-}
-
-// Returns true if m1 and m2 are related, and m1 is higher up the totem pole
-// than m2. The criteria for being related are somewhat loose, as you can see
-// below.
-bool monster_senior(const monsters *m1, const monsters *m2)
-{
- const monsterentry *me1 = seekmonster(m1->type),
- *me2 = seekmonster(m2->type);
-
- if (!me1 || !me2)
- return (false);
-
- int mchar1 = me1->showchar,
- mchar2 = me2->showchar;
-
- // If both are demons, the smaller number is the nastier demon.
- if (isdigit(mchar1) && isdigit(mchar2))
- return (mchar1 < mchar2);
-
- // &s are the evillest demons of all, well apart from Geryon, who really
- // profits from *not* pushing past beasts.
- if (mchar1 == '&' && isdigit(mchar2) && m1->type != MONS_GERYON)
- return (m1->hit_dice > m2->hit_dice);
-
- // Skeletal warriors can push past zombies large and small.
- if (m1->type == MONS_SKELETAL_WARRIOR && (mchar2 == 'z' || mchar2 == 'Z'))
- return (m1->hit_dice > m2->hit_dice);
-
- if (m1->type == MONS_QUEEN_BEE
- && (m2->type == MONS_KILLER_BEE
- || m2->type == MONS_KILLER_BEE_LARVA))
- return (true);
-
- if (m1->type == MONS_KILLER_BEE && m2->type == MONS_KILLER_BEE_LARVA)
- return (true);
-
- // Special-case gnolls so they can't get past (hob)goblins
- if (m1->type == MONS_GNOLL && m2->type != MONS_GNOLL)
- return (false);
-
- return (mchar1 == mchar2 && m1->hit_dice > m2->hit_dice);
-}