diff options
Diffstat (limited to 'src/monster2.c')
-rw-r--r-- | src/monster2.c | 4054 |
1 files changed, 0 insertions, 4054 deletions
diff --git a/src/monster2.c b/src/monster2.c deleted file mode 100644 index b0753244..00000000 --- a/src/monster2.c +++ /dev/null @@ -1,4054 +0,0 @@ -/* File: monster2.c */ - -/* Purpose: misc code for monsters */ - -/* - * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke - * - * This software may be copied and distributed for educational, research, and - * not for profit purposes provided that this copyright and statement are - * included in all such copies. - */ - -#include "angband.h" - -#define MAX_HORROR 20 -#define MAX_FUNNY 22 -#define MAX_COMMENT 5 - -/* Monster gain a few levels ? */ -void monster_check_experience(int m_idx, bool_ silent) -{ - monster_type *m_ptr = &m_list[m_idx]; - monster_race *r_ptr = &r_info[m_ptr->r_idx]; - char m_name[80]; - - /* Get the name */ - monster_desc(m_name, m_ptr, 0); - - /* Gain levels while possible */ - while ((m_ptr->level < MONSTER_LEVEL_MAX) && - (m_ptr->exp >= (u32b)(MONSTER_EXP(m_ptr->level + 1)))) - { - /* Gain a level */ - m_ptr->level++; - - if (m_ptr->ml && (!silent)) cmsg_format(TERM_L_BLUE, "%^s gains a level.", m_name); - - /* Gain hp */ - if (magik(80)) - { - m_ptr->maxhp += r_ptr->hside; - m_ptr->hp += r_ptr->hside; - } - - /* Gain speed */ - if (magik(40)) - { - int speed = randint(2); - m_ptr->speed += speed; - m_ptr->mspeed += speed; - } - - /* Gain ac */ - if (magik(50)) - { - m_ptr->ac += (r_ptr->ac / 10) ? r_ptr->ac / 10 : 1; - } - - /* Gain melee power */ - if (magik(30)) - { - int i = rand_int(3), tries = 20; - - while ((tries--) && !m_ptr->blow[i].d_dice) i = rand_int(3); - - m_ptr->blow[i].d_dice++; - } - } -} - -/* Monster gain some xp */ -void monster_gain_exp(int m_idx, u32b exp, bool_ silent) -{ - monster_type *m_ptr = &m_list[m_idx]; - - m_ptr->exp += exp; - if (wizard) - { - char m_name[80]; - - /* Get the name */ - monster_desc(m_name, m_ptr, 0); - - if (!silent) msg_format("%^s gains %ld exp.", m_name, exp); - } - - monster_check_experience(m_idx, silent); -} - -void monster_set_level(int m_idx, int level) -{ - monster_type *m_ptr = &m_list[m_idx]; - - if (level > 150) level = 150; - - if (m_ptr->level < level) - { - m_ptr->exp = MONSTER_EXP(level); - monster_check_experience(m_idx, TRUE); - } -} - -/* Will add, sub, .. */ -s32b modify_aux(s32b a, s32b b, char mod) -{ - switch (mod) - { - case MEGO_ADD: - return (a + b); - break; - case MEGO_SUB: - return (a - b); - break; - case MEGO_FIX: - return (b); - break; - case MEGO_PRC: - return (a * b / 100); - break; - default: - msg_format("WARNING, unmatching MEGO(%d).", mod); - return (0); - } -} - -/* Is this ego ok for this monster ? */ -bool_ mego_ok(int r_idx, int ego) -{ - monster_ego *re_ptr = &re_info[ego]; - monster_race *r_ptr = &r_info[r_idx]; - bool_ ok = FALSE; - int i; - - /* needed flags */ - if (re_ptr->flags1 && ((re_ptr->flags1 & r_ptr->flags1) != re_ptr->flags1)) return FALSE; - if (re_ptr->flags2 && ((re_ptr->flags2 & r_ptr->flags2) != re_ptr->flags2)) return FALSE; - if (re_ptr->flags3 && ((re_ptr->flags3 & r_ptr->flags3) != re_ptr->flags3)) return FALSE; - if (re_ptr->flags7 && ((re_ptr->flags7 & r_ptr->flags7) != re_ptr->flags7)) return FALSE; - if (re_ptr->flags8 && ((re_ptr->flags8 & r_ptr->flags8) != re_ptr->flags8)) return FALSE; - if (re_ptr->flags9 && ((re_ptr->flags9 & r_ptr->flags9) != re_ptr->flags9)) return FALSE; - - /* unwanted flags */ - if (re_ptr->hflags1 && (re_ptr->hflags1 & r_ptr->flags1)) return FALSE; - if (re_ptr->hflags2 && (re_ptr->hflags2 & r_ptr->flags2)) return FALSE; - if (re_ptr->hflags3 && (re_ptr->hflags3 & r_ptr->flags3)) return FALSE; - if (re_ptr->hflags7 && (re_ptr->hflags7 & r_ptr->flags7)) return FALSE; - if (re_ptr->hflags8 && (re_ptr->hflags8 & r_ptr->flags8)) return FALSE; - if (re_ptr->hflags9 && (re_ptr->hflags9 & r_ptr->flags9)) return FALSE; - - /* Need good race -- IF races are specified */ - if (re_ptr->r_char[0]) - { - for (i = 0; i < 5; i++) - { - if (r_ptr->d_char == re_ptr->r_char[i]) ok = TRUE; - } - if (!ok) return FALSE; - } - if (re_ptr->nr_char[0]) - { - for (i = 0; i < 5; i++) - { - if (r_ptr->d_char == re_ptr->nr_char[i]) return (FALSE); - } - } - - /* Passed all tests ? */ - return TRUE; -} - -/* Choose an ego type */ -int pick_ego_monster(int r_idx) -{ - /* Assume no ego */ - int ego = 0, lvl; - int tries = max_re_idx + 10; - monster_ego *re_ptr; - - if ((!(dungeon_flags2 & DF2_ELVEN)) && (!(dungeon_flags2 & DF2_DWARVEN))) - { - /* No townspeople ego */ - if (!r_info[r_idx].level) return 0; - - /* First are we allowed to find an ego */ - if (!magik(MEGO_CHANCE)) return 0; - - /* Lets look for one */ - while (tries--) - { - /* Pick one */ - ego = rand_range(1, max_re_idx - 1); - re_ptr = &re_info[ego]; - - /* No hope so far */ - if (!mego_ok(r_idx, ego)) continue; - - /* Not too much OoD */ - lvl = r_info[r_idx].level; - MODIFY(lvl, re_ptr->level, 0); - lvl -= ((dun_level / 2) + (rand_int(dun_level / 2))); - if (lvl < 1) lvl = 1; - if (rand_int(lvl)) continue; - - /* Each ego types have a rarity */ - if (rand_int(re_ptr->rarity)) continue; - - /* We finally got one ? GREAT */ - return ego; - } - } - /* Bypass restrictions for themed townspeople */ - else - { - if (dungeon_flags2 & DF2_ELVEN) - ego = test_mego_name("Elven"); - else if (dungeon_flags2 & DF2_DWARVEN) - ego = test_mego_name("Dwarven"); - - if (mego_ok(r_idx, ego)) - return ego; - } - - /* Found none ? so sad, well no ego for the time being */ - return 0; -} - -/* - * Return a (monster_race*) with the combination of the monster - * properties and the ego type - */ -monster_race* race_info_idx(int r_idx, int ego) -{ - static monster_race race; - monster_ego *re_ptr = &re_info[ego]; - monster_race *r_ptr = &r_info[r_idx], *nr_ptr = ∽̱ - int i; - - /* No work needed */ - if (!ego) return r_ptr; - - /* Copy the base monster */ - COPY(nr_ptr, r_ptr, monster_race); - - /* Adjust the values */ - for (i = 0; i < 4; i++) - { - s32b j, k; - - j = modify_aux(nr_ptr->blow[i].d_dice, re_ptr->blow[i].d_dice, re_ptr->blowm[i][0]); - if (j < 0) j = 0; - k = modify_aux(nr_ptr->blow[i].d_side, re_ptr->blow[i].d_side, re_ptr->blowm[i][1]); - if (k < 0) k = 0; - - nr_ptr->blow[i].d_dice = j; - nr_ptr->blow[i].d_side = k; - - if (re_ptr->blow[i].method) nr_ptr->blow[i].method = re_ptr->blow[i].method; - if (re_ptr->blow[i].effect) nr_ptr->blow[i].effect = re_ptr->blow[i].effect; - } - - MODIFY(nr_ptr->hdice, re_ptr->hdice, 1); - MODIFY(nr_ptr->hside, re_ptr->hside, 1); - - MODIFY(nr_ptr->ac, re_ptr->ac, 0); - - MODIFY(nr_ptr->sleep, re_ptr->sleep, 0); - - MODIFY(nr_ptr->aaf, re_ptr->aaf, 1); - MODIFY(nr_ptr->speed, re_ptr->speed, 50); - MODIFY(nr_ptr->mexp, re_ptr->mexp, 0); - - MODIFY(nr_ptr->weight, re_ptr->weight, 10); - - nr_ptr->freq_inate = (nr_ptr->freq_inate > re_ptr->freq_inate) - ? nr_ptr->freq_inate : re_ptr->freq_inate; - nr_ptr->freq_spell = (nr_ptr->freq_spell > re_ptr->freq_spell) - ? nr_ptr->freq_spell : re_ptr->freq_spell; - - MODIFY(nr_ptr->level, re_ptr->level, 1); - - /* Take off some flags */ - nr_ptr->flags1 &= ~(re_ptr->nflags1); - nr_ptr->flags2 &= ~(re_ptr->nflags2); - nr_ptr->flags3 &= ~(re_ptr->nflags3); - nr_ptr->flags4 &= ~(re_ptr->nflags4); - nr_ptr->flags5 &= ~(re_ptr->nflags5); - nr_ptr->flags6 &= ~(re_ptr->nflags6); - nr_ptr->flags7 &= ~(re_ptr->nflags7); - nr_ptr->flags8 &= ~(re_ptr->nflags8); - nr_ptr->flags9 &= ~(re_ptr->nflags9); - - /* Add some flags */ - nr_ptr->flags1 |= re_ptr->mflags1; - nr_ptr->flags2 |= re_ptr->mflags2; - nr_ptr->flags3 |= re_ptr->mflags3; - nr_ptr->flags4 |= re_ptr->mflags4; - nr_ptr->flags5 |= re_ptr->mflags5; - nr_ptr->flags6 |= re_ptr->mflags6; - nr_ptr->flags7 |= re_ptr->mflags7; - nr_ptr->flags8 |= re_ptr->mflags8; - nr_ptr->flags9 |= re_ptr->mflags9; - - /* Change the char/attr is needed */ - if (re_ptr->d_char != MEGO_CHAR_ANY) - { - nr_ptr->d_char = re_ptr->d_char; - nr_ptr->x_char = re_ptr->d_char; - } - if (re_ptr->d_attr != MEGO_CHAR_ANY) - { - nr_ptr->d_attr = re_ptr->d_attr; - nr_ptr->x_attr = re_ptr->d_attr; - } - - /* And finanly return a pointer to a fully working monster race */ - return nr_ptr; -} - -static cptr horror_desc[MAX_HORROR] = -{ - "abominable", - "abysmal", - "appalling", - "baleful", - "blasphemous", - - "disgusting", - "dreadful", - "filthy", - "grisly", - "hideous", - - "hellish", - "horrible", - "infernal", - "loathsome", - "nightmarish", - - "repulsive", - "sacrilegious", - "terrible", - "unclean", - "unspeakable", -}; - -static cptr funny_desc[MAX_FUNNY] = -{ - "silly", - "hilarious", - "absurd", - "insipid", - "ridiculous", - - "laughable", - "ludicrous", - "far-out", - "groovy", - "postmodern", - - "fantastic", - "dadaistic", - "cubistic", - "cosmic", - "awesome", - - "incomprehensible", - "fabulous", - "amazing", - "incredible", - "chaotic", - - "wild", - "preposterous", -}; - -static cptr funny_comments[MAX_COMMENT] = -{ - "Wow, cosmic, man!", - "Rad!", - "Groovy!", - "Cool!", - "Far out!" -}; - - -int get_wilderness_flag(void) -{ - int x = p_ptr->wilderness_x; - int y = p_ptr->wilderness_y; - - if (dun_level) - return (RF8_DUNGEON); - else - return (1L << wf_info[wild_map[y][x].feat].terrain_idx); -} - - -/* - * Delete a monster by index. - * - * When a monster is deleted, all of its objects are deleted. - */ -void delete_monster_idx(int i) -{ - int x, y, j; - - monster_type *m_ptr = &m_list[i]; - - monster_race *r_ptr = race_inf(m_ptr); - - s16b this_o_idx, next_o_idx = 0; - - bool_ had_lite = FALSE; - ; - - - /* Get location */ - y = m_ptr->fy; - x = m_ptr->fx; - - /* Hack -- Reduce the racial counter */ - r_ptr->cur_num--; - r_ptr->on_saved = FALSE; - - /* Hack -- count the number of "reproducers" */ - if (r_ptr->flags4 & (RF4_MULTIPLY)) num_repro--; - - /* XXX XXX XXX remove monster light source */ - if (r_ptr->flags9 & (RF9_HAS_LITE)) had_lite = TRUE; - - - /* Hack -- remove target monster */ - if (i == target_who) target_who = 0; - - /* Hack -- remove tracked monster */ - if (i == health_who) health_track(0); - - /* Hack -- remove tracked monster */ - if (i == p_ptr->control) p_ptr->control = 0; - - for (j = m_max - 1; j >= 1; j--) - { - /* Access the monster */ - monster_type *t_ptr = &m_list[j]; - - /* Ignore "dead" monsters */ - if (!t_ptr->r_idx) continue; - - if (t_ptr->target == i) t_ptr->target = -1; - } - - /* Monster is gone */ - cave[y][x].m_idx = 0; - - - /* Delete objects */ - for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) - { - object_type * o_ptr; - - /* Acquire object */ - o_ptr = &o_list[this_o_idx]; - - /* Acquire next object */ - next_o_idx = o_ptr->next_o_idx; - - /* Hack -- efficiency */ - o_ptr->held_m_idx = 0; - - if ( p_ptr->preserve ) - { - /* Hack -- Preserve unknown artifacts */ - if (artifact_p(o_ptr) && !object_known_p(o_ptr)) - { - /* Mega-Hack -- Preserve the artifact */ - if (o_ptr->tval == TV_RANDART) - { - random_artifacts[o_ptr->sval].generated = FALSE; - } - else if (k_info[o_ptr->k_idx].flags3 & TR3_NORM_ART) - { - k_info[o_ptr->k_idx].artifact = FALSE; - } - else - { - a_info[o_ptr->name1].cur_num = 0; - } - } - } - /* Delete the object */ - delete_object_idx(this_o_idx); - } - - /* Delete mind & special race if needed */ - if (m_ptr->sr_ptr) - KILL(m_ptr->sr_ptr, monster_race); - if (m_ptr->mind) - KILL(m_ptr->mind, monster_mind); - - /* Wipe the Monster */ - m_ptr = WIPE(m_ptr, monster_type); - - /* Count monsters */ - m_cnt--; - - /* Do we survided our fate ? */ - if ((dungeon_type == DUNGEON_DEATH) && (!m_cnt)) - { - msg_print("You overcome your fate, mortal!"); - - dungeon_type = DUNGEON_WILDERNESS; - dun_level = 0; - - p_ptr->leaving = TRUE; - } - - /* Update monster light */ - if (had_lite) p_ptr->update |= (PU_MON_LITE); - - /* Update monster list window */ - p_ptr->window |= (PW_M_LIST); - - /* Visual update */ - lite_spot(y, x); -} - - -/* - * Delete the monster, if any, at a given location - */ -void delete_monster(int y, int x) -{ - cave_type *c_ptr; - - /* Paranoia */ - if (!in_bounds(y, x)) return; - - /* Check the grid */ - c_ptr = &cave[y][x]; - - /* Delete the monster (if any) */ - if (c_ptr->m_idx) delete_monster_idx(c_ptr->m_idx); -} - - -/* - * Move an object from index i1 to index i2 in the object list - */ -static void compact_monsters_aux(int i1, int i2) -{ - int y, x, j; - - cave_type *c_ptr; - - monster_type *m_ptr; - - s16b this_o_idx, next_o_idx = 0; - - - /* Do nothing */ - if (i1 == i2) return; - - - /* Old monster */ - m_ptr = &m_list[i1]; - - /* Location */ - y = m_ptr->fy; - x = m_ptr->fx; - - /* Cave grid */ - c_ptr = &cave[y][x]; - - /* Update the cave */ - c_ptr->m_idx = i2; - - /* Repair objects being carried by monster */ - for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) - { - object_type * o_ptr; - - /* Acquire object */ - o_ptr = &o_list[this_o_idx]; - - /* Acquire next object */ - next_o_idx = o_ptr->next_o_idx; - - /* Reset monster pointer */ - o_ptr->held_m_idx = i2; - } - - /* Hack -- Update the control */ - if (p_ptr->control == i1) p_ptr->control = i2; - - /* Hack -- Update the doppleganger */ - if (doppleganger == i1) doppleganger = i2; - - /* Hack -- Update the target */ - if (target_who == i1) target_who = i2; - - /* Hack -- Update the health bar */ - if (health_who == i1) health_track(i2); - - for (j = m_max - 1; j >= 1; j--) - { - /* Access the monster */ - monster_type *t_ptr = &m_list[j]; - - /* Ignore "dead" monsters */ - if (!t_ptr->r_idx) continue; - - if (t_ptr->target == i1) t_ptr->target = i2; - } - - /* Structure copy */ - COPY(&m_list[i2], &m_list[i1], monster_type); - - /* Delete mind & special race if needed */ - if (m_list[i1].sr_ptr) - KILL(m_list[i1].sr_ptr, monster_race); - if (m_list[i1].mind) - KILL(m_list[i1].mind, monster_mind); - - /* Wipe the hole */ - m_ptr = WIPE(&m_list[i1], monster_type); -} - - -/* - * Compact and Reorder the monster list - * - * This function can be very dangerous, use with caution! - * - * When actually "compacting" monsters, we base the saving throw - * on a combination of monster level, distance from player, and - * current "desperation". - * - * After "compacting" (if needed), we "reorder" the monsters into a more - * compact order, and we reset the allocation info, and the "live" array. - */ -void compact_monsters(int size) -{ - int i, num, cnt; - int cur_lev, cur_dis, chance; - - - /* Message (only if compacting) */ - if (size) msg_print("Compacting monsters..."); - - - /* Compact at least 'size' objects */ - for (num = 0, cnt = 1; num < size; cnt++) - { - /* Get more vicious each iteration */ - cur_lev = 5 * cnt; - - /* Get closer each iteration */ - cur_dis = 5 * (20 - cnt); - - /* Check all the monsters */ - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr = &m_list[i]; - - monster_race *r_ptr = race_inf(m_ptr); - - /* Paranoia -- skip "dead" monsters */ - if (!m_ptr->r_idx) continue; - - /* Hack -- High level monsters start out "immune" */ - if (m_ptr->level > cur_lev) continue; - - /* Ignore nearby monsters */ - if ((cur_dis > 0) && (m_ptr->cdis < cur_dis)) continue; - - /* Saving throw chance */ - chance = 90; - - /* Only compact "Quest" Monsters in emergencies */ - if ((m_ptr->mflag & MFLAG_QUEST) && (cnt < 1000)) chance = 100; - - /* Try not to compact Unique Monsters */ - if (r_ptr->flags1 & (RF1_UNIQUE)) chance = 99; - - /* All monsters get a saving throw */ - if (rand_int(100) < chance) continue; - - /* Delete the monster */ - delete_monster_idx(i); - - /* Count the monster */ - num++; - } - } - - - /* Excise dead monsters (backwards!) */ - for (i = m_max - 1; i >= 1; i--) - { - /* Get the i'th monster */ - monster_type *m_ptr = &m_list[i]; - - /* Skip real monsters */ - if (m_ptr->r_idx) continue; - - /* Move last monster into open hole */ - compact_monsters_aux(m_max - 1, i); - - /* Compress "m_max" */ - m_max--; - } -} - -/* - * Delete/Remove all the monsters when the player leaves the level - * - * This is an efficient method of simulating multiple calls to the - * "delete_monster()" function, with no visual effects. - */ -void wipe_m_list(void) -{ - int i; - - /* Delete all the monsters */ - for (i = m_max - 1; i >= 1; i--) - { - monster_type *m_ptr = &m_list[i]; - - monster_race *r_ptr = race_inf(m_ptr); - - /* Skip dead monsters */ - if (!m_ptr->r_idx) continue; - - /* Mega-Hack -- preserve Unique's XXX XXX XXX */ - - /* Hack -- Reduce the racial counter */ - r_ptr->cur_num--; - - /* Monster is gone */ - cave[m_ptr->fy][m_ptr->fx].m_idx = 0; - - /* Delete mind & special race if needed */ - if (m_ptr->sr_ptr) - KILL(m_ptr->sr_ptr, monster_race); - if (m_ptr->mind) - KILL(m_ptr->mind, monster_mind); - - - /* Wipe the Monster */ - m_ptr = WIPE(m_ptr, monster_type); - } - - /* Reset "m_max" */ - m_max = 1; - - /* Reset "m_cnt" */ - m_cnt = 0; - - /* Hack -- reset "reproducer" count */ - num_repro = 0; - - /* Hack -- no more target */ - target_who = 0; - - /* Reset control */ - p_ptr->control = 0; - - /* Hack -- no more tracking */ - health_track(0); -} - - -/* - * Acquires and returns the index of a "free" monster. - * - * This routine should almost never fail, but it *can* happen. - */ -s16b m_pop(void) -{ - int i; - - - /* Normal allocation */ - if (m_max < max_m_idx) - { - /* Access the next hole */ - i = m_max; - - /* Expand the array */ - m_max++; - - /* Count monsters */ - m_cnt++; - - /* Return the index */ - return (i); - } - - - /* Recycle dead monsters */ - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr; - - /* Acquire monster */ - m_ptr = &m_list[i]; - - /* Skip live monsters */ - if (m_ptr->r_idx) continue; - - /* Count monsters */ - m_cnt++; - - /* Use this monster */ - return (i); - } - - - /* Warn the player (except during dungeon creation) */ - if (character_dungeon) msg_print("Too many monsters!"); - - /* Try not to crash */ - return (0); -} - - - - -/* - * Apply a "monster restriction function" to the "monster allocation table" - */ -errr get_mon_num_prep(void) -{ - int i; - - /* Scan the allocation table */ - for (i = 0; i < alloc_race_size; i++) - { - /* Get the entry */ - alloc_entry *entry = &alloc_race_table[i]; - - /* Accept monsters which pass the restriction, if any */ - if ((!get_mon_num_hook || (*get_mon_num_hook)(entry->index)) && - (!get_mon_num2_hook || (*get_mon_num2_hook)(entry->index))) - { - /* Accept this monster */ - entry->prob2 = entry->prob1; - } - - /* Do not use this monster */ - else - { - /* Decline this monster */ - entry->prob2 = 0; - } - } - - /* Success */ - return (0); -} - -/* - * Some dungeon types restrict the possible monsters. - * Return TRUE is the monster is OK and FALSE otherwise - */ -bool_ apply_rule(monster_race *r_ptr, byte rule) -{ - dungeon_info_type *d_ptr = &d_info[dungeon_type]; - - if (d_ptr->rules[rule].mode == DUNGEON_MODE_NONE) - { - return TRUE; - } - else if ((d_ptr->rules[rule].mode == DUNGEON_MODE_AND) || (d_ptr->rules[rule].mode == DUNGEON_MODE_NAND)) - { - int a; - - if (d_ptr->rules[rule].mflags1) - { - if ((d_ptr->rules[rule].mflags1 & r_ptr->flags1) != d_ptr->rules[rule].mflags1) - return FALSE; - } - if (d_ptr->rules[rule].mflags2) - { - if ((d_ptr->rules[rule].mflags2 & r_ptr->flags2) != d_ptr->rules[rule].mflags2) - return FALSE; - } - if (d_ptr->rules[rule].mflags3) - { - if ((d_ptr->rules[rule].mflags3 & r_ptr->flags3) != d_ptr->rules[rule].mflags3) - return FALSE; - } - if (d_ptr->rules[rule].mflags4) - { - if ((d_ptr->rules[rule].mflags4 & r_ptr->flags4) != d_ptr->rules[rule].mflags4) - return FALSE; - } - if (d_ptr->rules[rule].mflags5) - { - if ((d_ptr->rules[rule].mflags5 & r_ptr->flags5) != d_ptr->rules[rule].mflags5) - return FALSE; - } - if (d_ptr->rules[rule].mflags6) - { - if ((d_ptr->rules[rule].mflags6 & r_ptr->flags6) != d_ptr->rules[rule].mflags6) - return FALSE; - } - if (d_ptr->rules[rule].mflags7) - { - if ((d_ptr->rules[rule].mflags7 & r_ptr->flags7) != d_ptr->rules[rule].mflags7) - return FALSE; - } - if (d_ptr->rules[rule].mflags8) - { - if ((d_ptr->rules[rule].mflags8 & r_ptr->flags8) != d_ptr->rules[rule].mflags8) - return FALSE; - } - if (d_ptr->rules[rule].mflags9) - { - if ((d_ptr->rules[rule].mflags9 & r_ptr->flags9) != d_ptr->rules[rule].mflags9) - return FALSE; - } - for (a = 0; a < 5; a++) - { - if (d_ptr->rules[rule].r_char[a] && (d_ptr->rules[rule].r_char[a] != r_ptr->d_char)) return FALSE; - } - - /* All checks passed ? lets go ! */ - return TRUE; - } - else if ((d_ptr->rules[rule].mode == DUNGEON_MODE_OR) || (d_ptr->rules[rule].mode == DUNGEON_MODE_NOR)) - { - int a; - - if (d_ptr->rules[rule].mflags1 && (r_ptr->flags1 & d_ptr->rules[rule].mflags1)) return TRUE; - if (d_ptr->rules[rule].mflags2 && (r_ptr->flags2 & d_ptr->rules[rule].mflags2)) return TRUE; - if (d_ptr->rules[rule].mflags3 && (r_ptr->flags3 & d_ptr->rules[rule].mflags3)) return TRUE; - if (d_ptr->rules[rule].mflags4 && (r_ptr->flags4 & d_ptr->rules[rule].mflags4)) return TRUE; - if (d_ptr->rules[rule].mflags5 && (r_ptr->flags5 & d_ptr->rules[rule].mflags5)) return TRUE; - if (d_ptr->rules[rule].mflags6 && (r_ptr->flags6 & d_ptr->rules[rule].mflags6)) return TRUE; - if (d_ptr->rules[rule].mflags7 && (r_ptr->flags7 & d_ptr->rules[rule].mflags7)) return TRUE; - if (d_ptr->rules[rule].mflags8 && (r_ptr->flags8 & d_ptr->rules[rule].mflags8)) return TRUE; - if (d_ptr->rules[rule].mflags9 && (r_ptr->flags9 & d_ptr->rules[rule].mflags9)) return TRUE; - - for (a = 0; a < 5; a++) - if (d_ptr->rules[rule].r_char[a] == r_ptr->d_char) return TRUE; - - /* All checks failled ? Sorry ... */ - return FALSE; - } - - /* Should NEVER happen */ - return FALSE; -} - -bool_ restrict_monster_to_dungeon(int r_idx) -{ - dungeon_info_type *d_ptr = &d_info[dungeon_type]; - monster_race *r_ptr = &r_info[r_idx]; - - /* Select a random rule */ - byte rule = d_ptr->rule_percents[rand_int(100)]; - - /* Apply the rule */ - bool_ rule_ret = apply_rule(r_ptr, rule); - - /* Should the rule be right or not ? */ - if ((d_ptr->rules[rule].mode == DUNGEON_MODE_NAND) || (d_ptr->rules[rule].mode == DUNGEON_MODE_NOR)) rule_ret = !rule_ret; - - /* Rule ok ? */ - if (rule_ret) return TRUE; - - /* Not allowed */ - return FALSE; -} - -/* Ugly hack, let summon unappropriate monsters */ -bool_ summon_hack = FALSE; - -/* - * Choose a monster race that seems "appropriate" to the given level - * - * This function uses the "prob2" field of the "monster allocation table", - * and various local information, to calculate the "prob3" field of the - * same table, which is then used to choose an "appropriate" monster, in - * a relatively efficient manner. - * - * Note that "town" monsters will *only* be created in the town, and - * "normal" monsters will *never* be created in the town, unless the - * "level" is "modified", for example, by polymorph or summoning. - * - * There is a small chance (1/50) of "boosting" the given depth by - * a small amount (up to four levels), except in the town. - * - * It is (slightly) more likely to acquire a monster of the given level - * than one of a lower level. This is done by choosing several monsters - * appropriate to the given level and keeping the "hardest" one. - * - * Note that if no monsters are "appropriate", then this function will - * fail, and return zero, but this should *almost* never happen. - */ -s16b get_mon_num(int level) -{ - int i, j, p; - - int r_idx; - - long value, total; - - monster_race *r_ptr; - - alloc_entry *table = alloc_race_table; - - int in_tome; - - /* Boost the level */ - if (level > 0) - { - /* Occasional "nasty" monster */ - if (rand_int(NASTY_MON) == 0) - { - /* Pick a level bonus */ - int d = level / 4 + 2; - - /* Boost the level */ - level += ((d < 5) ? d : 5); - } - - /* Occasional "nasty" monster */ - if (rand_int(NASTY_MON) == 0) - { - /* Pick a level bonus */ - int d = level / 4 + 2; - - /* Boost the level */ - level += ((d < 5) ? d : 5); - } - } - - - /* Reset total */ - total = 0L; - - /* Check whether this is ToME or a module */ - in_tome = strcmp(game_module, "ToME") == 0; - - /* Process probabilities */ - for (i = 0; i < alloc_race_size; i++) - { - /* Monsters are sorted by depth */ - if (table[i].level > level) break; - - /* Default */ - table[i].prob3 = 0; - - /* Access the "r_idx" of the chosen monster */ - r_idx = table[i].index; - - /* Access the actual race */ - r_ptr = &r_info[r_idx]; - - /* Hack -- "unique" monsters must be "unique" */ - if ((r_ptr->flags1 & (RF1_UNIQUE)) && - (r_ptr->cur_num >= r_ptr->max_num)) - { - continue; - } - - /* Depth Monsters never appear out of depth */ - if ((r_ptr->flags1 & (RF1_FORCE_DEPTH)) && (r_ptr->level > dun_level)) - { - continue; - } - - /* Depth Monsters never appear out of their depth */ - if ((r_ptr->flags9 & (RF9_ONLY_DEPTH)) && (r_ptr->level != dun_level)) - { - continue; - } - - if(in_tome) - { - /* Zangbandish monsters not allowed */ - if (r_ptr->flags8 & RF8_ZANGBAND) continue; - - /* Lovecraftian monsters not allowed */ - if (r_ptr->flags8 & RF8_CTHANGBAND) continue; - } - - /* Joke monsters allowed ? or not ? */ - if (!joke_monsters && (r_ptr->flags8 & RF8_JOKEANGBAND)) continue; - - /* Some dungeon types restrict the possible monsters */ - if (!summon_hack && !restrict_monster_to_dungeon(r_idx) && dun_level) continue; - - /* Accept */ - table[i].prob3 = table[i].prob2; - - /* Total */ - total += table[i].prob3; - } - - /* No legal monsters */ - if (total <= 0) return (0); - - - /* Pick a monster */ - value = rand_int(total); - - /* Find the monster */ - for (i = 0; i < alloc_race_size; i++) - { - /* Found the entry */ - if (value < table[i].prob3) break; - - /* Decrement */ - value = value - table[i].prob3; - } - - - /* Power boost */ - p = rand_int(100); - - /* Try for a "harder" monster once (50%) or twice (10%) */ - if (p < 60) - { - /* Save old */ - j = i; - - /* Pick a monster */ - value = rand_int(total); - - /* Find the monster */ - for (i = 0; i < alloc_race_size; i++) - { - /* Found the entry */ - if (value < table[i].prob3) break; - - /* Decrement */ - value = value - table[i].prob3; - } - - /* Keep the "best" one */ - if (table[i].level < table[j].level) i = j; - } - - /* Try for a "harder" monster twice (10%) */ - if (p < 10) - { - /* Save old */ - j = i; - - /* Pick a monster */ - value = rand_int(total); - - /* Find the monster */ - for (i = 0; i < alloc_race_size; i++) - { - /* Found the entry */ - if (value < table[i].prob3) break; - - /* Decrement */ - value = value - table[i].prob3; - } - - /* Keep the "best" one */ - if (table[i].level < table[j].level) i = j; - } - - - /* Result */ - return (table[i].index); -} - - - - - -/* - * Build a string describing a monster in some way. - * - * We can correctly describe monsters based on their visibility. - * We can force all monsters to be treated as visible or invisible. - * We can build nominatives, objectives, possessives, or reflexives. - * We can selectively pronominalize hidden, visible, or all monsters. - * We can use definite or indefinite descriptions for hidden monsters. - * We can use definite or indefinite descriptions for visible monsters. - * - * Pronominalization involves the gender whenever possible and allowed, - * so that by cleverly requesting pronominalization / visibility, you - * can get messages like "You hit someone. She screams in agony!". - * - * Reflexives are acquired by requesting Objective plus Possessive. - * - * If no m_ptr arg is given (?), the monster is assumed to be hidden, - * unless the "Assume Visible" mode is requested. - * - * If no r_ptr arg is given, it is extracted from m_ptr and r_info - * If neither m_ptr nor r_ptr is given, the monster is assumed to - * be neuter, singular, and hidden (unless "Assume Visible" is set), - * in which case you may be in trouble... :-) - * - * I am assuming that no monster name is more than 70 characters long, - * so that "char desc[80];" is sufficiently large for any result. - * - * Mode Flags: - * 0x01 --> Objective (or Reflexive) - * 0x02 --> Possessive (or Reflexive) - * 0x04 --> Use indefinites for hidden monsters ("something") - * 0x08 --> Use indefinites for visible monsters ("a kobold") - * 0x10 --> Pronominalize hidden monsters - * 0x20 --> Pronominalize visible monsters - * 0x40 --> Assume the monster is hidden - * 0x80 --> Assume the monster is visible - * 0x100 --> Ignore insanity - * - * Useful Modes: - * 0x00 --> Full nominative name ("the kobold") or "it" - * 0x04 --> Full nominative name ("the kobold") or "something" - * 0x80 --> Genocide resistance name ("the kobold") - * 0x88 --> Killing name ("a kobold") - * 0x22 --> Possessive, genderized if visible ("his") or "its" - * 0x23 --> Reflexive, genderized if visible ("himself") or "itself" - */ -void monster_desc(char *desc, monster_type *m_ptr, int mode) -{ - cptr res; - monster_race *r_ptr = race_inf(m_ptr); - cptr b_name = (r_name + r_ptr->name); - char silly_name[80], name[100]; - bool_ seen, pron; - int insanity = (p_ptr->msane - p_ptr->csane) * 100 / p_ptr->msane; - - if (m_ptr->ego) - { - if (re_info[m_ptr->ego].before) sprintf(name, "%s %s", re_name + re_info[m_ptr->ego].name, b_name); - else sprintf(name, "%s %s", b_name, re_name + re_info[m_ptr->ego].name); - } - else - { - sprintf(name, "%s", b_name); - } - - /* - * Are we hallucinating? (Idea from Nethack...) - * insanity roll added by pelpel - */ - if (!(mode & 0x100) && (p_ptr->image || (rand_int(300) < insanity))) - { - if (rand_int(2) == 0) - { - monster_race *hallu_race; - - do - { - hallu_race = &r_info[randint(max_r_idx - 2)]; - } - while (hallu_race->flags1 & RF1_UNIQUE); - - strcpy(silly_name, (r_name + hallu_race->name)); - } - else - { - get_rnd_line("silly.txt", silly_name); - } - - strcpy(name, silly_name); - } - - /* Can we "see" it (exists + forced, or visible + not unforced) */ - seen = (m_ptr && ((mode & 0x80) || (!(mode & 0x40) && m_ptr->ml))); - - /* Sexed Pronouns (seen and allowed, or unseen and allowed) */ - pron = (m_ptr && ((seen && (mode & 0x20)) || (!seen && (mode & 0x10)))); - - - /* First, try using pronouns, or describing hidden monsters */ - if (!seen || pron) - { - /* an encoding of the monster "sex" */ - int kind = 0x00; - - /* Extract the gender (if applicable) */ - if (r_ptr->flags1 & (RF1_FEMALE)) kind = 0x20; - else if (r_ptr->flags1 & (RF1_MALE)) kind = 0x10; - - /* Ignore the gender (if desired) */ - if (!m_ptr || !pron) kind = 0x00; - - - /* Assume simple result */ - res = "it"; - - /* Brute force: split on the possibilities */ - switch (kind | (mode & 0x07)) - { - /* Neuter, or unknown */ - case 0x00: - res = "it"; - break; - case 0x01: - res = "it"; - break; - case 0x02: - res = "its"; - break; - case 0x03: - res = "itself"; - break; - case 0x04: - res = "something"; - break; - case 0x05: - res = "something"; - break; - case 0x06: - res = "something's"; - break; - case 0x07: - res = "itself"; - break; - - /* Male (assume human if vague) */ - case 0x10: - res = "he"; - break; - case 0x11: - res = "him"; - break; - case 0x12: - res = "his"; - break; - case 0x13: - res = "himself"; - break; - case 0x14: - res = "someone"; - break; - case 0x15: - res = "someone"; - break; - case 0x16: - res = "someone's"; - break; - case 0x17: - res = "himself"; - break; - - /* Female (assume human if vague) */ - case 0x20: - res = "she"; - break; - case 0x21: - res = "her"; - break; - case 0x22: - res = "her"; - break; - case 0x23: - res = "herself"; - break; - case 0x24: - res = "someone"; - break; - case 0x25: - res = "someone"; - break; - case 0x26: - res = "someone's"; - break; - case 0x27: - res = "herself"; - break; - } - - /* Copy the result */ - (void)strcpy(desc, res); - } - - - /* Handle visible monsters, "reflexive" request */ - else if ((mode & 0x02) && (mode & 0x01)) - { - /* The monster is visible, so use its gender */ - if (r_ptr->flags1 & (RF1_FEMALE)) strcpy(desc, "herself"); - else if (r_ptr->flags1 & (RF1_MALE)) strcpy(desc, "himself"); - else strcpy(desc, "itself"); - } - - - /* Handle all other visible monster requests */ - else - { - /* It could be a Unique */ - if ((r_ptr->flags1 & (RF1_UNIQUE)) && !(p_ptr->image)) - { - /* Start with the name (thus nominative and objective) */ - (void)strcpy(desc, name); - } - - /* It could be an indefinite monster */ - else if (mode & 0x08) - { - /* XXX Check plurality for "some" */ - - /* Indefinite monsters need an indefinite article */ - (void)strcpy(desc, is_a_vowel(name[0]) ? "an " : "a "); - (void)strcat(desc, name); - } - - /* It could be a normal, definite, monster */ - else - { - /* Definite monsters need a definite article */ - if (m_ptr->status >= MSTATUS_PET) - (void)strcpy(desc, "your "); - else - (void)strcpy(desc, "the "); - - (void)strcat(desc, name); - } - - /* Handle the Possessive as a special afterthought */ - if (mode & 0x02) - { - /* XXX Check for trailing "s" */ - - /* Simply append "apostrophe" and "s" */ - (void)strcat(desc, "'s"); - } - } -} - -void monster_race_desc(char *desc, int r_idx, int ego) -{ - monster_race *r_ptr = &r_info[r_idx]; - cptr b_name = (r_name + r_ptr->name); - char name[80]; - - if (ego) - { - if (re_info[ego].before) sprintf(name, "%s %s", re_name + re_info[ego].name, b_name); - else sprintf(name, "%s %s", b_name, re_name + re_info[ego].name); - } - else - { - sprintf(name, "%s", b_name); - } - - /* It could be a Unique */ - if (r_ptr->flags1 & RF1_UNIQUE) - { - /* Start with the name (thus nominative and objective) */ - (void)strcpy(desc, name); - } - - /* It could be a normal, definite, monster */ - else - { - /* Definite monsters need a definite article */ - (void)strcpy(desc, is_a_vowel(name[0]) ? "an " : "a "); - - (void)strcat(desc, name); - } -} - - - -/* - * Learn about a monster (by "probing" it) - */ -void lore_do_probe(int m_idx) -{ - monster_type *m_ptr = &m_list[m_idx]; - - monster_race *r_ptr = &r_info[m_ptr->r_idx]; - - /* Hack -- Memorize some flags */ - r_ptr->r_flags1 = r_ptr->flags1; - r_ptr->r_flags2 = r_ptr->flags2; - r_ptr->r_flags3 = r_ptr->flags3; - - /* Update monster recall window */ - if (monster_race_idx == m_ptr->r_idx) - { - /* Window stuff */ - p_ptr->window |= (PW_MONSTER); - } -} - - -/* - * Take note that the given monster just dropped some treasure - * - * Note that learning the "GOOD"/"GREAT" flags gives information - * about the treasure (even when the monster is killed for the first - * time, such as uniques, and the treasure has not been examined yet). - * - * This "indirect" method is used to prevent the player from learning - * exactly how much treasure a monster can drop from observing only - * a single example of a drop. This method actually observes how much - * gold and items are dropped, and remembers that information to be - * described later by the monster recall code. - */ -void lore_treasure(int m_idx, int num_item, int num_gold) -{ - monster_type *m_ptr = &m_list[m_idx]; - - monster_race *r_ptr = &r_info[m_ptr->r_idx]; - - /* Note the number of things dropped */ - if (num_item > r_ptr->r_drop_item) r_ptr->r_drop_item = num_item; - if (num_gold > r_ptr->r_drop_gold) r_ptr->r_drop_gold = num_gold; - - /* Hack -- memorize the good/great flags */ - if (r_ptr->flags1 & (RF1_DROP_GOOD)) r_ptr->r_flags1 |= (RF1_DROP_GOOD); - if (r_ptr->flags1 & (RF1_DROP_GREAT)) r_ptr->r_flags1 |= (RF1_DROP_GREAT); - - /* Update monster recall window */ - if (monster_race_idx == m_ptr->r_idx) - { - /* Window stuff */ - p_ptr->window |= (PW_MONSTER); - } -} - - - -void sanity_blast(monster_type * m_ptr, bool_ necro) -{ - bool_ happened = FALSE; - int power = 100; - - if (!necro) - { - char m_name[80]; - monster_race *r_ptr; - - if (m_ptr != NULL) r_ptr = race_inf(m_ptr); - else return; - - power = (m_ptr->level) + 10; - - if (m_ptr != NULL) - { - monster_desc(m_name, m_ptr, 0); - - if (!(r_ptr->flags1 & RF1_UNIQUE)) - { - if (r_ptr->flags1 & RF1_FRIENDS) - power /= 2; - } - else power *= 2; - - if (!hack_mind) - return ; /* No effect yet, just loaded... */ - - if (!(m_ptr->ml)) - return ; /* Cannot see it for some reason */ - - if (!(r_ptr->flags2 & RF2_ELDRITCH_HORROR)) - return ; /* oops */ - - - - if ((is_friend(m_ptr) > 0) && (randint(8) != 1)) - return ; /* Pet eldritch horrors are safe most of the time */ - - - if (randint(power) < p_ptr->skill_sav) - { - return ; /* Save, no adverse effects */ - } - - - if (p_ptr->image) - { - /* Something silly happens... */ - msg_format("You behold the %s visage of %s!", - funny_desc[(randint(MAX_FUNNY)) - 1], m_name); - if (randint(3) == 1) - { - msg_print(funny_comments[randint(MAX_COMMENT) - 1]); - p_ptr->image = (p_ptr->image + randint(m_ptr->level)); - } - return ; /* Never mind; we can't see it clearly enough */ - } - - /* Something frightening happens... */ - msg_format("You behold the %s visage of %s!", - horror_desc[(randint(MAX_HORROR)) - 1], m_name); - - r_ptr->r_flags2 |= RF2_ELDRITCH_HORROR; - - } - - /* Undead characters are 50% likely to be unaffected */ - if ((PRACE_FLAG(PR1_UNDEAD)) || (p_ptr->mimic_form == resolve_mimic_name("Vampire"))) - { - if (randint(100) < (25 + (p_ptr->lev))) return; - } - } - else - { - msg_print("Your sanity is shaken by reading the Necronomicon!"); - } - if (randint(power) < p_ptr->skill_sav) /* Mind blast */ - { - if (!p_ptr->resist_conf) - { - (void)set_confused(p_ptr->confused + rand_int(4) + 4); - } - if ((!p_ptr->resist_chaos) && (randint(3) == 1)) - { - (void) set_image(p_ptr->image + rand_int(250) + 150); - } - return; - } - - if (randint(power) < p_ptr->skill_sav) /* Lose int & wis */ - { - do_dec_stat (A_INT, STAT_DEC_NORMAL); - do_dec_stat (A_WIS, STAT_DEC_NORMAL); - return; - } - - - if (randint(power) < p_ptr->skill_sav) /* Brain smash */ - { - if (!p_ptr->resist_conf) - { - (void)set_confused(p_ptr->confused + rand_int(4) + 4); - } - if (!p_ptr->free_act) - { - (void)set_paralyzed(p_ptr->paralyzed + rand_int(4) + 4); - } - while (rand_int(100) > p_ptr->skill_sav) - (void)do_dec_stat(A_INT, STAT_DEC_NORMAL); - while (rand_int(100) > p_ptr->skill_sav) - (void)do_dec_stat(A_WIS, STAT_DEC_NORMAL); - if (!p_ptr->resist_chaos) - { - (void) set_image(p_ptr->image + rand_int(250) + 150); - } - return; - } - - if (randint(power) < p_ptr->skill_sav) /* Permanent lose int & wis */ - { - if (dec_stat(A_INT, 10, TRUE)) happened = TRUE; - if (dec_stat(A_WIS, 10, TRUE)) happened = TRUE; - if (happened) - msg_print("You feel much less sane than before."); - return; - } - - - if (randint(power) < p_ptr->skill_sav) /* Amnesia */ - { - - if (lose_all_info()) - msg_print("You forget everything in your utmost terror!"); - return; - } - - p_ptr->update |= PU_BONUS; - handle_stuff(); -} - - -/* - * This function updates the monster record of the given monster - * - * This involves extracting the distance to the player, checking - * for visibility (natural, infravision, see-invis, telepathy), - * updating the monster visibility flag, redrawing or erasing the - * monster when the visibility changes, and taking note of any - * "visual" features of the monster (cold-blooded, invisible, etc). - * - * The only monster fields that are changed here are "cdis" (the - * distance from the player), "los" (clearly visible to player), - * and "ml" (visible to the player in any way). - * - * There are a few cases where the calling routine knows that the - * distance from the player to the monster has not changed, and so - * we have a special parameter "full" to request distance computation. - * This lets many calls to this function run very quickly. - * - * Note that every time a monster moves, we must call this function - * for that monster, and update distance. Note that every time the - * player moves, we must call this function for every monster, and - * update distance. Note that every time the player "state" changes - * in certain ways (including "blindness", "infravision", "telepathy", - * and "see invisible"), we must call this function for every monster. - * - * The routines that actually move the monsters call this routine - * directly, and the ones that move the player, or notice changes - * in the player state, call "update_monsters()". - * - * Routines that change the "illumination" of grids must also call - * this function, since the "visibility" of some monsters may be - * based on the illumination of their grid. - * - * Note that this function is called once per monster every time the - * player moves, so it is important to optimize it for monsters which - * are far away. Note the optimization which skips monsters which - * are far away and were completely invisible last turn. - * - * Note the optimized "inline" version of the "distance()" function. - * - * Note that only monsters on the current panel can be "visible", - * and then only if they are (1) in line of sight and illuminated - * by light or infravision, or (2) nearby and detected by telepathy. - * - * The player can choose to be disturbed by several things, including - * "disturb_move" (monster which is viewable moves in some way), and - * "disturb_near" (monster which is "easily" viewable moves in some - * way). Note that "moves" includes "appears" and "disappears". - * - * Note the new "xtra" field which encodes several state flags such - * as "detected last turn", and "detected this turn", and "currently - * in line of sight", all of which are used for visibility testing. - */ -void update_mon(int m_idx, bool_ full) -{ - monster_type *m_ptr = &m_list[m_idx]; - - monster_race *r_ptr = race_inf(m_ptr); - - /* The current monster location */ - int fy = m_ptr->fy; - int fx = m_ptr->fx; - - bool_ old_ml = m_ptr->ml; - - /* Seen at all */ - bool_ flag = FALSE; - - /* Seen by vision */ - bool_ easy = FALSE; - - /* Seen by telepathy */ - bool_ hard = FALSE; - - /* Various extra flags */ - bool_ do_empty_mind = FALSE; - bool_ do_weird_mind = FALSE; - bool_ do_invisible = FALSE; - bool_ do_cold_blood = FALSE; - - - /* Calculate distance */ - if (full) - { - int d, dy, dx; - - /* Distance components */ - dy = (p_ptr->py > fy) ? (p_ptr->py - fy) : (fy - p_ptr->py); - dx = (p_ptr->px > fx) ? (p_ptr->px - fx) : (fx - p_ptr->px); - - /* Approximate distance */ - d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1)); - - /* Save the distance (in a byte) */ - m_ptr->cdis = (d < 255) ? d : 255; - } - - - /* Process "distant" monsters */ - if (m_ptr->cdis > MAX_SIGHT) - { - /* Ignore unseen monsters */ - if (!m_ptr->ml) return; - - /* Detected */ - if (m_ptr->mflag & (MFLAG_MARK)) flag = TRUE; - } - - - /* Process "nearby" monsters on the current "panel" */ - else if (panel_contains(fy, fx)) - { - /* Normal line of sight, and player is not blind */ - if (player_has_los_bold(fy, fx) && !p_ptr->blind) - { - /* Use "infravision" */ - if (m_ptr->cdis <= (byte)(p_ptr->see_infra)) - { - /* Infravision only works on "warm" creatures */ - /* Below, we will need to know that infravision failed */ - if (r_ptr->flags2 & (RF2_COLD_BLOOD)) do_cold_blood = TRUE; - - /* Infravision works */ - if (!do_cold_blood) easy = flag = TRUE; - } - - /* Use "illumination" */ - if (player_can_see_bold(fy, fx)) - { - /* Take note of invisibility */ - if (r_ptr->flags2 & (RF2_INVISIBLE)) do_invisible = TRUE; - - /* Visible, or detectable, monsters get seen */ - if (!do_invisible || p_ptr->see_inv) easy = flag = TRUE; - } - } - - /* Telepathy can see all "nearby" monsters with "minds" */ - if (p_ptr->telepathy) - { - /* Assume we cant see */ - bool_ can_esp = FALSE; - - /* Different ESP */ - if ((p_ptr->telepathy & ESP_ORC) && (r_ptr->flags3 & RF3_ORC)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_SPIDER) && (r_ptr->flags7 & RF7_SPIDER)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_TROLL) && (r_ptr->flags3 & RF3_TROLL)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_DRAGON) && (r_ptr->flags3 & RF3_DRAGON)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_GIANT) && (r_ptr->flags3 & RF3_GIANT)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_DEMON) && (r_ptr->flags3 & RF3_DEMON)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_UNDEAD) && (r_ptr->flags3 & RF3_UNDEAD)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_EVIL) && (r_ptr->flags3 & RF3_EVIL)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_ANIMAL) && (r_ptr->flags3 & RF3_ANIMAL)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_THUNDERLORD) && (r_ptr->flags3 & RF3_THUNDERLORD)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_GOOD) && (r_ptr->flags3 & RF3_GOOD)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_NONLIVING) && (r_ptr->flags3 & RF3_NONLIVING)) can_esp = TRUE; - if ((p_ptr->telepathy & ESP_UNIQUE) && ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags3 & RF3_UNIQUE_4))) can_esp = TRUE; - if (p_ptr->telepathy & ESP_ALL) can_esp = TRUE; - - /* Only do this when we can really detect monster */ - if (can_esp) - { - /* Empty mind, no telepathy */ - if (r_ptr->flags2 & (RF2_EMPTY_MIND)) - { - do_empty_mind = TRUE; - } - - /* Weird mind, occasional telepathy */ - else if (r_ptr->flags2 & (RF2_WEIRD_MIND)) - { - do_weird_mind = TRUE; - if (rand_int(100) < 10) - { - hard = TRUE; - flag = TRUE; - } - } - - /* Normal mind, allow telepathy */ - else - { - hard = TRUE; - flag = TRUE; - } - } - } - - /* Apply "detection" spells */ - if (m_ptr->mflag & (MFLAG_MARK)) flag = TRUE; - - /* Hack -- Wizards have "perfect telepathy" */ - if (wizard) flag = TRUE; - } - - - /* The monster is now visible */ - if (flag) - { - /* It was previously unseen */ - if (!m_ptr->ml) - { - /* Mark as visible */ - m_ptr->ml = TRUE; - - /* Draw the monster */ - lite_spot(fy, fx); - - /* Update health bar as needed */ - if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH); - - /* Update monster list window */ - p_ptr->window |= (PW_M_LIST); - - /* Hack -- Count "fresh" sightings */ - if (r_ptr->r_sights < MAX_SHORT) r_ptr->r_sights++; - - /* Disturb on appearance */ - if (disturb_move) - { - if (disturb_pets || (is_friend(m_ptr) <= 0)) disturb(1, 0); - } - } - - /* Apply telepathy */ - if (hard) - { - /* Hack -- Memorize mental flags */ - if (r_ptr->flags2 & (RF2_SMART)) r_ptr->r_flags2 |= (RF2_SMART); - if (r_ptr->flags2 & (RF2_STUPID)) r_ptr->r_flags2 |= (RF2_STUPID); - } - - /* Memorize various observable flags */ - if (do_empty_mind) r_ptr->r_flags2 |= (RF2_EMPTY_MIND); - if (do_weird_mind) r_ptr->r_flags2 |= (RF2_WEIRD_MIND); - if (do_cold_blood) r_ptr->r_flags2 |= (RF2_COLD_BLOOD); - if (do_invisible) r_ptr->r_flags2 |= (RF2_INVISIBLE); - } - - /* The monster is not visible */ - else - { - /* It was previously seen */ - if (m_ptr->ml) - { - /* Mark as not visible */ - m_ptr->ml = FALSE; - - /* Erase the monster */ - lite_spot(fy, fx); - - /* Update health bar as needed */ - if (health_who == m_idx) p_ptr->redraw |= (PR_HEALTH); - - /* Update monster list window */ - p_ptr->window |= (PW_M_LIST); - - /* Disturb on disappearance*/ - if (disturb_move) - { - if (disturb_pets || (is_friend(m_ptr) <= 0)) disturb(1, 0); - } - } - } - - - /* The monster is now easily visible */ - if (easy) - { - - if (m_ptr->ml != old_ml) - { - if (r_ptr->flags2 & RF2_ELDRITCH_HORROR) - { - sanity_blast(m_ptr, FALSE); - } - } - - /* Change */ - if (!(m_ptr->mflag & (MFLAG_VIEW))) - { - /* Mark as easily visible */ - m_ptr->mflag |= (MFLAG_VIEW); - - /* Disturb on appearance */ - if (disturb_near) - { - if (disturb_pets || (is_friend(m_ptr) <= 0)) disturb(1, 0); - } - - } - } - - /* The monster is not easily visible */ - else - { - /* Change */ - if (m_ptr->mflag & (MFLAG_VIEW)) - { - /* Mark as not easily visible */ - m_ptr->mflag &= ~(MFLAG_VIEW); - - /* Update monster list window */ - p_ptr->window |= (PW_M_LIST); - - /* Disturb on disappearance */ - if (disturb_near) - { - if (disturb_pets || (is_friend(m_ptr) <= 0)) disturb(1, 0); - } - } - } -} - - - - -/* - * This function simply updates all the (non-dead) monsters (see above). - */ -void update_monsters(bool_ full) -{ - int i; - - /* Update each (live) monster */ - for (i = 1; i < m_max; i++) - { - monster_type *m_ptr = &m_list[i]; - - /* Skip dead monsters */ - if (!m_ptr->r_idx) continue; - - /* Update the monster */ - update_mon(i, full); - } -} - - -void monster_carry(monster_type *m_ptr, int m_idx, object_type *q_ptr) -{ - object_type *o_ptr; - - /* Get new object */ - int o_idx = o_pop(); - - if (o_idx) - { - /* Get the item */ - o_ptr = &o_list[o_idx]; - - /* Structure copy */ - object_copy(o_ptr, q_ptr); - - /* Build a stack */ - o_ptr->next_o_idx = m_ptr->hold_o_idx; - - o_ptr->held_m_idx = m_idx; - o_ptr->ix = 0; - o_ptr->iy = 0; - - m_ptr->hold_o_idx = o_idx; - } - - else - { - /* Hack -- Preserve artifacts */ - if (q_ptr->name1) - { - a_info[q_ptr->name1].cur_num = 0; - } - else if (k_info[q_ptr->k_idx].flags3 & TR3_NORM_ART) - { - k_info[q_ptr->k_idx].artifact = 0; - } - else if (q_ptr->tval == TV_RANDART) - { - random_artifacts[q_ptr->sval].generated = FALSE; - } - } -} - - -static int possible_randart[] = -{ - TV_MSTAFF, - TV_BOOMERANG, - TV_DIGGING, - TV_HAFTED, - TV_POLEARM, - TV_AXE, - TV_SWORD, - TV_BOOTS, - TV_GLOVES, - TV_HELM, - TV_CROWN, - TV_SHIELD, - TV_CLOAK, - TV_SOFT_ARMOR, - TV_HARD_ARMOR, - TV_LITE, - TV_AMULET, - TV_RING, - -1, -}; - - -bool_ kind_is_randart(int k_idx) -{ - int max; - object_kind *k_ptr = &k_info[k_idx]; - - if (!kind_is_legal(k_idx)) return (FALSE); - - for (max = 0; possible_randart[max] != -1; max++) - { - if (k_ptr->tval == possible_randart[max]) return (TRUE); - } - return (FALSE); -} - -/* - * Attempt to place a monster of the given race at the given location. - * - * To give the player a sporting chance, any monster that appears in - * line-of-sight and is extremely dangerous can be marked as - * "FORCE_SLEEP", which will cause them to be placed with low energy, - * which often (but not always) lets the player move before they do. - * - * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters. - * - * XXX XXX XXX Use special "here" and "dead" flags for unique monsters, - * remove old "cur_num" and "max_num" fields. - * - * XXX XXX XXX Actually, do something similar for artifacts, to simplify - * the "preserve" mode, and to make the "what artifacts" flag more useful. - * - * This is the only function which may place a monster in the dungeon, - * except for the savefile loading code. - */ -bool_ bypass_r_ptr_max_num = FALSE; -int place_monster_result = 0; -bool_ place_monster_one_no_drop = FALSE; -monster_race *place_monster_one_race = NULL; -s16b place_monster_one(int y, int x, int r_idx, int ego, bool_ slp, int status) -{ - int i; - char dummy[5]; - bool_ add_level = FALSE; - int min_level = 0, max_level = 0; - - cave_type *c_ptr; - - monster_type *m_ptr; - - monster_race *r_ptr = &r_info[r_idx]; - - cptr name = (r_name + r_ptr->name); - - /* Grab the special race if needed */ - if (place_monster_one_race) - { - r_ptr = place_monster_one_race; - } - - /* DO NOT PLACE A MONSTER IN THE SMALL SCALE WILDERNESS !!! */ - if (p_ptr->wild_mode) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Verify location */ - if (!in_bounds(y, x)) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Require empty space */ - if (!cave_empty_bold(y, x)) - { - if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster(%d): EMPTY BOLD", r_idx); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Require no monster free grid, or special permission */ - if ((cave[y][x].info & CAVE_FREE) && (!m_allow_special[r_idx])) - { - if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster(%d): CAVE_FREE", r_idx); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Hack -- no creation on glyph of warding */ - if (cave[y][x].feat == FEAT_GLYPH) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - if (cave[y][x].feat == FEAT_MINOR_GLYPH) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Nor on the between */ - if (cave[y][x].feat == FEAT_BETWEEN) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Nor on the altars */ - if ((cave[y][x].feat >= FEAT_ALTAR_HEAD) - && (cave[y][x].feat <= FEAT_ALTAR_TAIL)) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Nor on the Pattern */ - if ((cave[y][x].feat >= FEAT_PATTERN_START) - && (cave[y][x].feat <= FEAT_PATTERN_XTRA2)) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Paranoia */ - if (!r_idx) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Paranoia */ - if (!r_ptr->name) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Are we allowed to continue ? */ - if (process_hooks(HOOK_NEW_MONSTER, "(d)", r_idx)) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Ego Uniques are NOT to be created */ - if ((r_ptr->flags1 & RF1_UNIQUE) && ego) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Now could we generate an Ego Monster */ - /* Grab the special race if needed */ - if (place_monster_one_race) - { - r_ptr = place_monster_one_race; - } - else - { - r_ptr = race_info_idx(r_idx, ego); - } - - if (!monster_can_cross_terrain(cave[y][x].feat, r_ptr)) - { - if (wizard) cmsg_print(TERM_L_RED, "WARNING: Refused monster: cannot cross terrain"); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Unallow some uniques to be generated outside of their quests/special levels/dungeons */ - if ((r_ptr->flags9 & RF9_SPECIAL_GENE) && (!m_allow_special[r_idx])) - { - if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster(%d): SPECIAL_GENE", r_idx); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Disallow Spirits in The Void, now this *IS* an ugly hack, I hate to do it ... */ - if ((r_ptr->flags7 & RF7_SPIRIT) && (dungeon_type != DUNGEON_VOID)) - { - if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster(%d): SPIRIT in non VOID", r_idx); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Fully forbid it */ - if (r_ptr->flags9 & RF9_NEVER_GENE) - { - if (wizard) cmsg_print(TERM_L_RED, "WARNING: Refused monster: NEVER_GENE"); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Hack -- "unique" monsters must be "unique" */ - if ((r_ptr->flags1 & (RF1_UNIQUE)) && (r_ptr->max_num == -1) && (!m_allow_special[r_idx])) - { - /* Cannot create */ - if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster %d: unique not unique", r_idx); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* The monster is already on an unique level */ - if (r_ptr->on_saved) - { - if (wizard) cmsg_print(TERM_L_RED, "WARNING: Refused monster: unique already on saved level"); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Hack -- "unique" monsters must be "unique" */ - if ((r_ptr->flags1 & (RF1_UNIQUE)) && (r_ptr->cur_num >= r_ptr->max_num) && (r_ptr->max_num != -1) && (!bypass_r_ptr_max_num)) - { - /* Cannot create */ - if (wizard) cmsg_format(TERM_L_RED, "WARNING: Refused monster %d: cur_num >= max_num", r_idx); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Depth monsters may NOT be created out of depth */ - if ((r_ptr->flags1 & (RF1_FORCE_DEPTH)) && (dun_level < r_ptr->level)) - { - /* Cannot create */ - if (wizard) cmsg_print(TERM_L_RED, "WARNING: FORCE_DEPTH"); - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - /* Powerful monster */ - if (r_ptr->level > dun_level) - { - /* Unique monsters */ - if (r_ptr->flags1 & (RF1_UNIQUE)) - { - /* Message for cheaters */ - if ((cheat_hear) || (p_ptr->precognition)) msg_format("Deep Unique (%s).", name); - - /* Boost rating by twice delta-depth */ - rating += (r_ptr->level - dun_level) * 2; - } - - /* Normal monsters */ - else - { - /* Message for cheaters */ - if ((cheat_hear) || (p_ptr->precognition)) msg_format("Deep Monster (%s).", name); - - /* Boost rating by delta-depth */ - rating += (r_ptr->level - dun_level); - } - } - - /* Note the monster */ - else if (r_ptr->flags1 & (RF1_UNIQUE)) - { - /* Unique monsters induce message */ - if ((cheat_hear) || (p_ptr->precognition)) msg_format("Unique (%s).", name); - } - - - /* Access the location */ - c_ptr = &cave[y][x]; - - /* Make a new monster */ - c_ptr->m_idx = m_pop(); - hack_m_idx_ii = c_ptr->m_idx; - - /* Mega-Hack -- catch "failure" */ - if (!c_ptr->m_idx) - { - if (place_monster_one_race) KILL(place_monster_one_race, monster_race); - return 0; - } - - - /* Get a new monster record */ - m_ptr = &m_list[c_ptr->m_idx]; - - /* Save the race */ - m_ptr->r_idx = r_idx; - m_ptr->ego = ego; - - /* No special, no mind */ - m_ptr->sr_ptr = place_monster_one_race; - m_ptr->mind = NULL; - - /* Place the monster at the location */ - m_ptr->fy = y; - m_ptr->fx = x; - - /* No "damage" yet */ - m_ptr->stunned = 0; - m_ptr->confused = 0; - m_ptr->monfear = 0; - - /* No target yet */ - m_ptr->target = -1; - - /* Unknown distance */ - m_ptr->cdis = 0; - - /* No flags */ - m_ptr->mflag = 0; - - /* Not visible */ - m_ptr->ml = FALSE; - - /* No objects yet */ - m_ptr->hold_o_idx = 0; - - m_ptr->status = status; - - /* Friendly? */ - if (m_ptr->status < MSTATUS_FRIEND && r_ptr->flags7 & RF7_PET) - { - m_ptr->status = MSTATUS_FRIEND; - } - if (m_ptr->status < MSTATUS_NEUTRAL && r_ptr->flags7 & RF7_NEUTRAL) - { - m_ptr->status = MSTATUS_NEUTRAL; - } - - /* Assume no sleeping */ - m_ptr->csleep = 0; - - /* Enforce sleeping if needed */ - if (slp && r_ptr->sleep) - { - int val = r_ptr->sleep; - m_ptr->csleep = ((val * 2) + randint(val * 10)); - } - - /* Generate the monster's inventory(if any) */ - /* Only if not fated to die */ - if ((dungeon_type != DUNGEON_DEATH) && (!place_monster_one_no_drop)) - { - bool_ good = (r_ptr->flags1 & (RF1_DROP_GOOD)) ? TRUE : FALSE; - bool_ great = (r_ptr->flags1 & (RF1_DROP_GREAT)) ? TRUE : FALSE; - - bool_ do_gold = (!(r_ptr->flags1 & (RF1_ONLY_ITEM))); - bool_ do_item = (!(r_ptr->flags1 & (RF1_ONLY_GOLD))); - bool_ do_mimic = (r_ptr->flags9 & (RF9_MIMIC)); - int j; - - int force_coin = get_coin_type(r_ptr); - - int dump_item = 0; - int dump_gold = 0; - object_type forge; - object_type *q_ptr; - - int number = 0; - - /* Average dungeon and monster levels */ - object_level = (dun_level + r_ptr->level) / 2; - - /* Determine how much we can drop */ - if ((r_ptr->flags1 & (RF1_DROP_60)) && (rand_int(100) < 60)) number++; - if ((r_ptr->flags1 & (RF1_DROP_90)) && (rand_int(100) < 90)) number++; - if (r_ptr->flags1 & (RF1_DROP_1D2)) number += damroll(1, 2); - if (r_ptr->flags1 & (RF1_DROP_2D2)) number += damroll(2, 2); - if (r_ptr->flags1 & (RF1_DROP_3D2)) number += damroll(3, 2); - if (r_ptr->flags1 & (RF1_DROP_4D2)) number += damroll(4, 2); - if (r_ptr->flags9 & (RF9_MIMIC)) number = 1; - - /* Hack -- handle creeping coins */ - coin_type = force_coin; - - if (r_ptr->flags7 & RF7_DROP_RANDART) - { - int tries = 1000; - obj_theme theme; - int i; - - /* Get local object */ - q_ptr = &forge; - - theme.treasure = 101; - theme.combat = 101; - theme.magic = 101; - theme.tools = 101; - - init_match_theme(theme); - - /* Apply restriction */ - get_obj_num_hook = kind_is_legal; - - /* Rebuild allocation table */ - get_obj_num_prep(); - - i = 0; - while (tries) - { - tries--; - i = get_obj_num(dun_level); - if (!i) continue; - - if (!kind_is_randart(i)) continue; - break; - } - - /* Invalidate the cached allocation table */ - alloc_kind_table_valid = FALSE; - - if (tries) - { - object_prep(q_ptr, i); - create_artifact(q_ptr, FALSE, TRUE); - q_ptr->found = OBJ_FOUND_MONSTER; - q_ptr->found_aux1 = m_ptr->r_idx; - q_ptr->found_aux2 = m_ptr->ego; - q_ptr->found_aux3 = dungeon_type; - q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level); - - monster_carry(m_ptr, c_ptr->m_idx, q_ptr); - } - } - - /* Drop some objects */ - for (j = 0; j < number; j++) - { - /* Get local object */ - q_ptr = &forge; - - /* Wipe the object */ - object_wipe(q_ptr); - - /* Make Gold */ - if ((!do_mimic) && do_gold && (!do_item || (rand_int(100) < 50))) - { - /* Make some gold */ - if (!make_gold(q_ptr)) continue; - - /* XXX XXX XXX */ - dump_gold++; - } - - /* Make Object */ - else - { - /* Make an object */ - if (!do_mimic) - { - if (!make_object(q_ptr, good, great, r_ptr->drops)) continue; - } - else - { - /* Try hard for mimics */ - int tries = 1000; - - while (tries--) - { - if (make_object(q_ptr, good, great, r_ptr->drops)) break; - } - /* BAD */ - if (!tries) continue; - } - - /* XXX XXX XXX */ - dump_item++; - } - - q_ptr->found = OBJ_FOUND_MONSTER; - q_ptr->found_aux1 = m_ptr->r_idx; - q_ptr->found_aux2 = m_ptr->ego; - q_ptr->found_aux3 = dungeon_type; - q_ptr->found_aux4 = level_or_feat(dungeon_type, dun_level); - monster_carry(m_ptr, c_ptr->m_idx, q_ptr); - } - - /* Reset the object level */ - object_level = dun_level; - - /* Reset "coin" type */ - coin_type = 0; - } - place_monster_one_no_drop = FALSE; - - - /* Assign maximal hitpoints */ - if (r_ptr->flags1 & (RF1_FORCE_MAXHP)) - { - m_ptr->maxhp = maxroll(r_ptr->hdice, r_ptr->hside); - } - else - { - m_ptr->maxhp = damroll(r_ptr->hdice, r_ptr->hside); - } - - /* And start out fully healthy */ - m_ptr->hp = m_ptr->maxhp; - - /* Some basic info */ - for (i = 0; i < 4; i++) - { - m_ptr->blow[i].method = r_ptr->blow[i].method; - m_ptr->blow[i].effect = r_ptr->blow[i].effect; - m_ptr->blow[i].d_dice = r_ptr->blow[i].d_dice; - m_ptr->blow[i].d_side = r_ptr->blow[i].d_side; - } - m_ptr->ac = r_ptr->ac; - m_ptr->level = r_ptr->level; - m_ptr->speed = r_ptr->speed; - m_ptr->exp = MONSTER_EXP(m_ptr->level); - - /* Extract the monster base speed */ - m_ptr->mspeed = m_ptr->speed; - - /* Hack -- small racial variety */ - if (!(r_ptr->flags1 & (RF1_UNIQUE))) - { - /* Allow some small variation per monster */ - i = extract_energy[m_ptr->speed] / 10; - if (i) m_ptr->mspeed += rand_spread(0, i); - } - - - if (dungeon_flags2 & DF2_ADJUST_LEVEL_1_2) - { - min_level = max_level = dun_level / 2; - add_level = TRUE; - } - if (dungeon_flags1 & DF1_ADJUST_LEVEL_1) - { - if (!min_level) min_level = dun_level; - max_level = dun_level; - add_level = TRUE; - } - if (dungeon_flags1 & DF1_ADJUST_LEVEL_2) - { - if (!min_level) min_level = dun_level * 2; - max_level = dun_level * 2; - add_level = TRUE; - } - if (add_level) monster_set_level(c_ptr->m_idx, rand_range(min_level, max_level)); - - /* Give a random starting energy */ - m_ptr->energy = (byte)rand_int(100); - - /* Force monster to wait for player */ - if (r_ptr->flags1 & (RF1_FORCE_SLEEP)) - { - /* Monster is still being nice */ - m_ptr->mflag |= (MFLAG_NICE); - - /* Must repair monsters */ - repair_monsters = TRUE; - } - - /* Hack -- see "process_monsters()" */ - if (c_ptr->m_idx < hack_m_idx) - { - /* Monster is still being born */ - m_ptr->mflag |= (MFLAG_BORN); - } - - - /* Update the monster */ - update_mon(c_ptr->m_idx, TRUE); - - - /* Hack -- Count the number of "reproducers" */ - if (r_ptr->flags4 & (RF4_MULTIPLY)) num_repro++; - - - /* Hack -- Notice new multi-hued monsters */ - if (r_ptr->flags1 & (RF1_ATTR_MULTI)) shimmer_monsters = TRUE; - - /* Hack -- we need to modify the REAL r_info, not the fake one */ - r_ptr = &r_info[r_idx]; - - /* Hack -- Count the monsters on the level */ - r_ptr->cur_num++; - - /* Unique monsters on saved levels should be "marked" */ - if ((r_ptr->flags1 & RF1_UNIQUE) && get_dungeon_save(dummy)) - { - r_ptr->on_saved = TRUE; - } - - place_monster_one_race = NULL; - - /* Success */ - place_monster_result = c_ptr->m_idx; - return c_ptr->m_idx; -} - -/* - * Maximum size of a group of monsters - */ -#define GROUP_MAX 32 - - -/* - * Attempt to place a "group" of monsters around the given location - */ -static bool_ place_monster_group(int y, int x, int r_idx, bool_ slp, int status) -{ - monster_race *r_ptr = &r_info[r_idx]; - - int old, n, i; - int total = 0, extra = 0; - - int hack_n = 0; - - byte hack_y[GROUP_MAX]; - byte hack_x[GROUP_MAX]; - - - /* Pick a group size */ - total = randint(13); - - /* Hard monsters, small groups */ - if (r_ptr->level > dun_level) - { - extra = r_ptr->level - dun_level; - extra = 0 - randint(extra); - } - - /* Easy monsters, large groups */ - else if (r_ptr->level < dun_level) - { - extra = dun_level - r_ptr->level; - extra = randint(extra); - } - - /* Hack -- limit group reduction */ - if (extra > 12) extra = 12; - - /* Modify the group size */ - total += extra; - - /* Minimum size */ - if (total < 1) total = 1; - - /* Maximum size */ - if (total > GROUP_MAX) total = GROUP_MAX; - - - /* Save the rating */ - old = rating; - - /* Start on the monster */ - hack_n = 1; - hack_x[0] = x; - hack_y[0] = y; - - /* Puddle monsters, breadth first, up to total */ - for (n = 0; (n < hack_n) && (hack_n < total); n++) - { - /* Grab the location */ - int hx = hack_x[n]; - int hy = hack_y[n]; - - /* Check each direction, up to total */ - for (i = 0; (i < 8) && (hack_n < total); i++) - { - int mx = hx + ddx_ddd[i]; - int my = hy + ddy_ddd[i]; - - /* Walls and Monsters block flow */ - if (!cave_empty_bold(my, mx)) continue; - - /* Attempt to place another monster */ - if (place_monster_one(my, mx, r_idx, pick_ego_monster(r_idx), slp, status)) - { - /* Add it to the "hack" set */ - hack_y[hack_n] = my; - hack_x[hack_n] = mx; - hack_n++; - } - } - } - - /* Hack -- restore the rating */ - rating = old; - - - /* Success */ - return (TRUE); -} - - -/* - * Hack -- help pick an escort type - */ -static int place_monster_idx = 0; - -/* - * Hack -- help pick an escort type - */ -static bool_ place_monster_okay(int r_idx) -{ - monster_race *r_ptr = &r_info[place_monster_idx]; - - monster_race *z_ptr = &r_info[r_idx]; - - /* Hack - Escorts have to have the same dungeon flag */ - if (monster_dungeon(place_monster_idx) != monster_dungeon(r_idx)) return (FALSE); - - /* Require similar "race" */ - if (z_ptr->d_char != r_ptr->d_char) return (FALSE); - - /* Skip more advanced monsters */ - if (z_ptr->level > r_ptr->level) return (FALSE); - - /* Skip unique monsters */ - if (z_ptr->flags1 & (RF1_UNIQUE)) return (FALSE); - - /* Paranoia -- Skip identical monsters */ - if (place_monster_idx == r_idx) return (FALSE); - - /* Okay */ - return (TRUE); -} - - -/* - * Attempt to place a monster of the given race at the given location - * - * Note that certain monsters are now marked as requiring "friends". - * These monsters, if successfully placed, and if the "grp" parameter - * is TRUE, will be surrounded by a "group" of identical monsters. - * - * Note that certain monsters are now marked as requiring an "escort", - * which is a collection of monsters with similar "race" but lower level. - * - * Some monsters induce a fake "group" flag on their escorts. - * - * Note the "bizarre" use of non-recursion to prevent annoying output - * when running a code profiler. - * - * Note the use of the new "monster allocation table" code to restrict - * the "get_mon_num()" function to "legal" escort types. - */ -bool_ place_monster_aux(int y, int x, int r_idx, bool_ slp, bool_ grp, int status) -{ - int i; - monster_race *r_ptr = &r_info[r_idx]; - bool_ (*old_get_mon_num_hook)(int r_idx); - - - /* Place one monster, or fail */ - if (!place_monster_one(y, x, r_idx, pick_ego_monster(r_idx), slp, status)) return (FALSE); - - - /* Require the "group" flag */ - if (!grp) return (TRUE); - - - /* Friends for certain monsters */ - if (r_ptr->flags1 & (RF1_FRIENDS)) - { - /* Attempt to place a group */ - (void)place_monster_group(y, x, r_idx, slp, status); - } - - - /* Escorts for certain monsters */ - if (r_ptr->flags1 & (RF1_ESCORT)) - { - old_get_mon_num_hook = get_mon_num_hook; - - /* Set the escort index */ - place_monster_idx = r_idx; - - /* Set the escort hook */ - get_mon_num_hook = place_monster_okay; - - /* Prepare allocation table */ - get_mon_num_prep(); - - /* Try to place several "escorts" */ - for (i = 0; i < 50; i++) - { - int nx, ny, z, d = 3; - - /* Pick a location */ - scatter(&ny, &nx, y, x, d); - - /* Require empty grids */ - if (!cave_empty_bold(ny, nx)) continue; - - set_mon_num2_hook(ny, nx); - - /* Prepare allocation table */ - get_mon_num_prep(); - - /* Pick a random race */ - z = get_mon_num(r_ptr->level); - - /* Reset restriction */ - get_mon_num2_hook = NULL; - - /* Prepare allocation table */ - get_mon_num_prep(); - - /* Handle failure */ - if (!z) break; - - /* Place a single escort */ - place_monster_one(ny, nx, z, pick_ego_monster(z), slp, status); - - /* Place a "group" of escorts if needed */ - if ((r_info[z].flags1 & (RF1_FRIENDS)) || - (r_ptr->flags1 & (RF1_ESCORTS))) - { - /* Place a group of monsters */ - (void)place_monster_group(ny, nx, z, slp, status); - } - } - - /* Reset restriction */ - get_mon_num_hook = old_get_mon_num_hook; - - /* Prepare allocation table */ - get_mon_num_prep(); - } - - /* Success */ - return (TRUE); -} - - -/* - * Hack -- attempt to place a monster at the given location - * - * Attempt to find a monster appropriate to the "monster_level" - */ -bool_ place_monster(int y, int x, bool_ slp, bool_ grp) -{ - int r_idx; - - /* Set monster restriction */ - set_mon_num2_hook(y, x); - - /* Prepare allocation table */ - get_mon_num_prep(); - - /* Pick a monster */ - r_idx = get_mon_num(monster_level); - - /* Reset restriction */ - get_mon_num2_hook = NULL; - - /* Prepare allocation table */ - get_mon_num_prep(); - - /* Handle failure */ - if (!r_idx) return (FALSE); - - /* Attempt to place the monster */ - if (place_monster_aux(y, x, r_idx, slp, grp, MSTATUS_ENEMY)) return (TRUE); - - /* Oops */ - return (FALSE); -} - - -#ifdef MONSTER_HORDES - -bool_ alloc_horde(int y, int x) -{ - int r_idx = 0; - monster_race * r_ptr = NULL; - monster_type * m_ptr; - int attempts = 1000; - - set_mon_num2_hook(y, x); - - /* Prepare allocation table */ - get_mon_num_prep(); - - while (--attempts) - { - /* Pick a monster */ - r_idx = get_mon_num(monster_level); - - /* Handle failure */ - if (!r_idx) return (FALSE); - - r_ptr = &r_info[r_idx]; - - if (!(r_ptr->flags1 & (RF1_UNIQUE)) - && !(r_ptr->flags1 & (RF1_ESCORTS))) - break; - } - - get_mon_num2_hook = NULL; - - /* Prepare allocation table */ - get_mon_num_prep(); - - if (attempts < 1) return FALSE; - - attempts = 1000; - - while (--attempts) - { - /* Attempt to place the monster */ - if (place_monster_aux(y, x, r_idx, FALSE, FALSE, MSTATUS_ENEMY)) break; - } - - if (attempts < 1) return FALSE; - - - m_ptr = &m_list[hack_m_idx_ii]; - - summon_kin_type = r_ptr->d_char; - - for (attempts = randint(10) + 5; attempts; attempts--) - { - (void) summon_specific(m_ptr->fy, m_ptr->fx, dun_level, SUMMON_KIN); - } - - return TRUE; -} - -#endif /* MONSTER_HORDES */ - -/* - * Attempt to allocate a random monster in the dungeon. - * - * Place the monster at least "dis" distance from the player. - * - * Use "slp" to choose the initial "sleep" status - * - * Use "monster_level" for the monster level - */ -bool_ alloc_monster(int dis, bool_ slp) -{ - int y, x; - int attempts_left = 10000; - - /* Find a legal, distant, unoccupied, space */ - while (attempts_left--) - { - /* Pick a location */ - y = rand_int(cur_hgt); - x = rand_int(cur_wid); - - /* Require empty floor grid (was "naked") */ - if (!cave_empty_bold(y, x)) continue; - - /* Accept far away grids */ - if (distance(y, x, p_ptr->py, p_ptr->px) > dis) break; - } - - if (!attempts_left) - { - if (cheat_xtra || cheat_hear) - { - msg_print("Warning! Could not allocate a new monster. Small level?"); - } - - return (FALSE); - } - - -#ifdef MONSTER_HORDES - if (randint(5000) <= dun_level) - { - if (alloc_horde(y, x)) - { - if ((cheat_hear) || (p_ptr->precognition)) msg_print("Monster horde."); - return (TRUE); - } - } - else - { -#endif /* MONSTER_HORDES */ - - /* Attempt to place the monster, allow groups */ - if (place_monster(y, x, slp, TRUE)) return (TRUE); - -#ifdef MONSTER_HORDES - } -#endif /* MONSTER_HORDES */ - - /* Nope */ - return (FALSE); -} - - - - -/* - * Hack -- the "type" of the current "summon specific" - */ -static int summon_specific_type = 0; - - -/* - * Hack -- help decide if a monster race is "okay" to summon - */ -bool_ summon_specific_okay(int r_idx) -{ - monster_race *r_ptr = &r_info[r_idx]; - - bool_ okay = FALSE; - - /* Hack - Only summon dungeon monsters */ - if (!monster_dungeon(r_idx)) return (FALSE); - - /* Hack -- no specific type specified */ - if (!summon_specific_type) return (TRUE); - - /* Check our requirements */ - switch (summon_specific_type) - { - case SUMMON_ANT: - { - okay = ((r_ptr->d_char == 'a') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_SPIDER: - { - okay = ((r_ptr->d_char == 'S') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_HOUND: - { - okay = (((r_ptr->d_char == 'C') || (r_ptr->d_char == 'Z')) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_HYDRA: - { - okay = ((r_ptr->d_char == 'M') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_ANGEL: - { - okay = ((r_ptr->d_char == 'A') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_DEMON: - { - okay = ((r_ptr->flags3 & (RF3_DEMON)) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_UNDEAD: - { - okay = ((r_ptr->flags3 & (RF3_UNDEAD)) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_DRAGON: - { - okay = ((r_ptr->flags3 & (RF3_DRAGON)) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_HI_UNDEAD: - { - okay = ((r_ptr->d_char == 'L') || - (r_ptr->d_char == 'V') || - (r_ptr->d_char == 'W')); - break; - } - - case SUMMON_HI_DRAGON: - { - okay = (r_ptr->d_char == 'D'); - break; - } - - case SUMMON_WRAITH: - { - okay = (r_ptr->d_char == 'W'); - break; - } - - case SUMMON_GHOST: - { - okay = (r_ptr->d_char == 'G'); - break; - } - - case SUMMON_UNIQUE: - { - okay = (r_ptr->flags1 & (RF1_UNIQUE)) ? TRUE : FALSE; - break; - } - - case SUMMON_BIZARRE1: - { - okay = ((r_ptr->d_char == 'm') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - case SUMMON_BIZARRE2: - { - okay = ((r_ptr->d_char == 'b') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - case SUMMON_BIZARRE3: - { - okay = ((r_ptr->d_char == 'Q') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_BIZARRE4: - { - okay = ((r_ptr->d_char == 'v') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_BIZARRE5: - { - okay = ((r_ptr->d_char == '$') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_BIZARRE6: - { - okay = (((r_ptr->d_char == '!') || - (r_ptr->d_char == '?') || - (r_ptr->d_char == '=') || - (r_ptr->d_char == '$') || - (r_ptr->d_char == '|')) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_HI_DEMON: - { - okay = ((r_ptr->flags3 & (RF3_DEMON)) && - (r_ptr->d_char == 'U') && - !(r_ptr->flags1 & RF1_UNIQUE)); - break; - } - - - case SUMMON_KIN: - { - okay = ((r_ptr->d_char == summon_kin_type) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_DAWN: - { - okay = ((strstr((r_name + r_ptr->name), "the Dawn")) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_ANIMAL: - { - okay = ((r_ptr->flags3 & (RF3_ANIMAL)) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_ANIMAL_RANGER: - { - okay = ((r_ptr->flags3 & (RF3_ANIMAL)) && - (strchr("abcflqrwBCIJKMRS", r_ptr->d_char)) && - !(r_ptr->flags3 & (RF3_DRAGON)) && - !(r_ptr->flags3 & (RF3_EVIL)) && - !(r_ptr->flags3 & (RF3_UNDEAD)) && - !(r_ptr->flags3 & (RF3_DEMON)) && - !(r_ptr->flags4 || r_ptr->flags5 || r_ptr->flags6) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_HI_UNDEAD_NO_UNIQUES: - { - okay = (((r_ptr->d_char == 'L') || - (r_ptr->d_char == 'V') || - (r_ptr->d_char == 'W')) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_HI_DRAGON_NO_UNIQUES: - { - okay = ((r_ptr->d_char == 'D') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_NO_UNIQUES: - { - okay = (!(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_PHANTOM: - { - okay = ((strstr((r_name + r_ptr->name), "Phantom")) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_ELEMENTAL: - { - okay = ((strstr((r_name + r_ptr->name), "lemental")) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_THUNDERLORD: - { - okay = (r_ptr->flags3 & RF3_THUNDERLORD) ? TRUE : FALSE; - break; - } - - case SUMMON_BLUE_HORROR: - { - okay = ((strstr((r_name + r_ptr->name), "lue horror")) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_BUG: - { - okay = ((strstr((r_name + r_ptr->name), "Software bug")) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_RNG: - { - okay = ((strstr((r_name + r_ptr->name), "Random Number Generator")) && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - case SUMMON_MINE: - { - okay = (r_ptr->flags1 & RF1_NEVER_MOVE) ? TRUE : FALSE; - break; - } - - case SUMMON_HUMAN: - { - okay = ((r_ptr->d_char == 'p') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_SHADOWS: - { - okay = ((r_ptr->d_char == 'G') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_QUYLTHULG: - { - okay = ((r_ptr->d_char == 'Q') && - !(r_ptr->flags1 & (RF1_UNIQUE))); - break; - } - - case SUMMON_LUA: - { - okay = summon_lua_okay(r_idx); - break; - } - } - - /* Result */ - return (okay); -} - - -/* - * Place a monster (of the specified "type") near the given - * location. Return TRUE if a monster was actually summoned. - * - * We will attempt to place the monster up to 10 times before giving up. - * - * Note: SUMMON_UNIQUE and SUMMON_WRAITH (XXX) will summon Unique's - * Note: SUMMON_HI_UNDEAD and SUMMON_HI_DRAGON may summon Unique's - * Note: None of the other summon codes will ever summon Unique's. - * - * This function has been changed. We now take the "monster level" - * of the summoning monster as a parameter, and use that, along with - * the current dungeon level, to help determine the level of the - * desired monster. Note that this is an upper bound, and also - * tends to "prefer" monsters of that level. Currently, we use - * the average of the dungeon and monster levels, and then add - * five to allow slight increases in monster power. - * - * Note that we use the new "monster allocation table" creation code - * to restrict the "get_mon_num()" function to the set of "legal" - * monsters, making this function much faster and more reliable. - * - * Note that this function may not succeed, though this is very rare. - */ -int summon_specific_level = 0; -bool_ summon_specific(int y1, int x1, int lev, int type) -{ - int i, x, y, r_idx; - bool_ Group_ok = TRUE; - bool_ (*old_get_mon_num_hook)(int r_idx); - - /* Look for a location */ - for (i = 0; i < 20; ++i) - { - /* Pick a distance */ - int d = (i / 15) + 1; - - /* Pick a location */ - scatter(&y, &x, y1, x1, d); - - /* Require "empty" floor grid */ - if (!cave_empty_bold(y, x)) continue; - - /* Hack -- no summon on glyph of warding */ - if (cave[y][x].feat == FEAT_GLYPH) continue; - if (cave[y][x].feat == FEAT_MINOR_GLYPH) continue; - - /* Nor on the between */ - if (cave[y][x].feat == FEAT_BETWEEN) return (FALSE); - - /* ... nor on the Pattern */ - if ((cave[y][x].feat >= FEAT_PATTERN_START) && - (cave[y][x].feat <= FEAT_PATTERN_XTRA2)) - continue; - - /* Okay */ - break; - } - - /* Failure */ - if (i == 20) return (FALSE); - - /* Save the "summon" type */ - summon_specific_type = type; - - /* Backup the old hook */ - old_get_mon_num_hook = get_mon_num_hook; - - /* Require "okay" monsters */ - get_mon_num_hook = summon_specific_okay; - - /* Prepare allocation table */ - get_mon_num_prep(); - - - /* Pick a monster, using the level calculation */ - summon_hack = TRUE; - r_idx = get_mon_num((dun_level + lev) / 2 + 5); - summon_hack = FALSE; - -#ifdef R_IDX_TESTING_HACK - r_idx = 356; -#endif - - /* Reset restriction */ - get_mon_num_hook = old_get_mon_num_hook; - - /* Prepare allocation table */ - get_mon_num_prep(); - - - /* Handle failure */ - if (!r_idx) return (FALSE); - - - if ((type == SUMMON_DAWN) || (type == SUMMON_BLUE_HORROR)) - { - Group_ok = FALSE; - } - - /* Attempt to place the monster (awake, allow groups) */ - if (!place_monster_aux(y, x, r_idx, FALSE, Group_ok, MSTATUS_ENEMY)) return (FALSE); - if (summon_specific_level) - { - monster_set_level(place_monster_result, summon_specific_level); - summon_specific_level = 0; - } - - /* Success */ - return (TRUE); -} - - - -bool_ summon_specific_friendly(int y1, int x1, int lev, int type, bool_ Group_ok) -{ - int i, x, y, r_idx; - bool_ (*old_get_mon_num_hook)(int r_idx); - - /* Look for a location */ - for (i = 0; i < 20; ++i) - { - /* Pick a distance */ - int d = (i / 15) + 1; - - /* Pick a location */ - scatter(&y, &x, y1, x1, d); - - /* Require "empty" floor grid */ - if (!cave_empty_bold(y, x)) continue; - - /* Hack -- no summon on glyph of warding */ - if (cave[y][x].feat == FEAT_GLYPH) continue; - if (cave[y][x].feat == FEAT_MINOR_GLYPH) continue; - - /* Nor on the between */ - if (cave[y][x].feat == FEAT_BETWEEN) return (FALSE); - - /* ... nor on the Pattern */ - if ((cave[y][x].feat >= FEAT_PATTERN_START) && - (cave[y][x].feat <= FEAT_PATTERN_XTRA2)) - continue; - - /* Okay */ - break; - } - - /* Failure */ - if (i == 20) return (FALSE); - - old_get_mon_num_hook = get_mon_num_hook; - - /* Save the "summon" type */ - summon_specific_type = type; - - /* Require "okay" monsters */ - get_mon_num_hook = summon_specific_okay; - - /* Prepare allocation table */ - get_mon_num_prep(); - - /* Pick a monster, using the level calculation */ - r_idx = get_mon_num((dun_level + lev) / 2 + 5); - -#ifdef R_IDX_TESTING_HACK - r_idx = 356; -#endif - - /* Reset restriction */ - get_mon_num_hook = old_get_mon_num_hook; - - /* Prepare allocation table */ - get_mon_num_prep(); - - /* Handle failure */ - if (!r_idx) return (FALSE); - - /* Attempt to place the monster (awake, allow groups) */ - if (!place_monster_aux(y, x, r_idx, FALSE, Group_ok, MSTATUS_PET)) return (FALSE); - if (summon_specific_level) - { - monster_set_level(place_monster_result, summon_specific_level); - summon_specific_level = 0; - } - - /* Success */ - return (TRUE); -} - - -/* - * Swap the players/monsters (if any) at two locations XXX XXX XXX - */ -void monster_swap(int y1, int x1, int y2, int x2) -{ - int m1, m2; - - monster_type *m_ptr; - cave_type *c_ptr1, *c_ptr2; - - c_ptr1 = &cave[y1][x1]; - c_ptr2 = &cave[y2][x2]; - - /* Monsters */ - m1 = c_ptr1->m_idx; - m2 = c_ptr2->m_idx; - - - /* Update grids */ - c_ptr1->m_idx = m2; - c_ptr2->m_idx = m1; - - - /* Monster 1 */ - if (m1 > 0) - { - m_ptr = &m_list[m1]; - - /* Move monster */ - m_ptr->fy = y2; - m_ptr->fx = x2; - - /* Update monster */ - update_mon(m1, TRUE); - } - - /* Player 1 */ - else if (m1 < 0) - { - /* Move player */ - p_ptr->py = y2; - p_ptr->px = x2; - - /* Check for new panel (redraw map) */ - verify_panel(); - - /* Update stuff */ - p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE); - - /* Update the monsters */ - p_ptr->update |= (PU_DISTANCE); - - /* Window stuff */ - /* It's probably not a good idea to recalculate the - * overhead view each turn. - - p_ptr->window |= (PW_OVERHEAD); - */ - } - - /* Monster 2 */ - if (m2 > 0) - { - m_ptr = &m_list[m2]; - - /* Move monster */ - m_ptr->fy = y1; - m_ptr->fx = x1; - - /* Update monster */ - update_mon(m2, TRUE); - } - - /* Player 2 */ - else if (m2 > 0) - { - /* Move player */ - p_ptr->py = y1; - p_ptr->px = x1; - - /* Check for new panel (redraw map) */ - verify_panel(); - - /* Update stuff */ - p_ptr->update |= (PU_VIEW | PU_FLOW | PU_MON_LITE); - - /* Update the monsters */ - p_ptr->update |= (PU_DISTANCE); - - /* Window stuff */ - /* It's probably not a good idea to recalculate the - * overhead view each turn. - - p_ptr->window |= (PW_OVERHEAD); - */ - } - - - /* Redraw */ - lite_spot(y1, x1); - lite_spot(y2, x2); -} - - -/* - * Hack -- help decide if a monster race is "okay" to summon - */ -static bool_ mutate_monster_okay(int r_idx) -{ - monster_race *r_ptr = &r_info[r_idx]; - - bool_ okay = FALSE; - - /* Hack - Only summon dungeon monsters */ - if (!monster_dungeon(r_idx)) return (FALSE); - - okay = ((r_ptr->d_char == summon_kin_type) && !(r_ptr->flags1 & (RF1_UNIQUE)) - && (r_ptr->level >= dun_level)); - - return okay; -} - - -/* - * Let the given monster attempt to reproduce. - * - * Note that "reproduction" REQUIRES empty space. - */ -bool_ multiply_monster(int m_idx, bool_ charm, bool_ clone) -{ - monster_type *m_ptr = &m_list[m_idx]; - monster_race *r_ptr = race_inf(m_ptr); - - int i, y, x, new_race; - - bool_ result = FALSE; - - if (no_breeds) - { - msg_print("It tries to breed but it fails!"); - return FALSE; - } - - /* Try up to 18 times */ - for (i = 0; i < 18; i++) - { - int d = 1; - - - /* Pick a location */ - scatter(&y, &x, m_ptr->fy, m_ptr->fx, d); - - /* Require an "empty" floor grid */ - if (!cave_empty_bold(y, x)) continue; - - new_race = m_ptr->r_idx; - - /* It can mutate into a nastier monster */ - if ((rand_int(100) < 3) && (!clone)) - { - bool_ (*old_get_mon_num_hook)(int r_idx); - - /* Backup the old hook */ - old_get_mon_num_hook = get_mon_num_hook; - - /* Require "okay" monsters */ - get_mon_num_hook = mutate_monster_okay; - - /* Prepare allocation table */ - get_mon_num_prep(); - - summon_kin_type = r_ptr->d_char; - - /* Pick a monster, using the level calculation */ - new_race = get_mon_num(dun_level + 5); - - /* Reset restriction */ - get_mon_num_hook = old_get_mon_num_hook; - - /* Prepare allocation table */ - get_mon_num_prep(); - } - - /* Create a new monster (awake, no groups) */ - result = place_monster_aux(y, x, new_race, FALSE, FALSE, (charm) ? MSTATUS_PET : MSTATUS_ENEMY); - - /* Done */ - break; - } - - if (clone && result) m_list[hack_m_idx_ii].smart |= SM_CLONED; - - /* Result */ - return (result); -} - - - - - -/* - * Dump a message describing a monster's reaction to damage - * - * Technically should attempt to treat "Beholder"'s as jelly's - */ -bool_ hack_message_pain_may_silent = FALSE; -void message_pain_hook(cptr fmt, ...) -{ - va_list vp; - - char buf[1024]; - - /* Begin the Varargs Stuff */ - va_start(vp, fmt); - - /* Format the args, save the length */ - (void)vstrnfmt(buf, 1024, fmt, vp); - - /* End the Varargs Stuff */ - va_end(vp); - - if (hack_message_pain_may_silent) - monster_msg(buf); - else - msg_print(buf); -} - -void message_pain(int m_idx, int dam) -{ - long oldhp, newhp, tmp; - int percentage; - monster_type *m_ptr = &m_list[m_idx]; - monster_race *r_ptr = race_inf(m_ptr); - char m_name[80]; - - /* Get the monster name */ - monster_desc(m_name, m_ptr, 0); - - /* Notice non-damage */ - if (dam == 0) - { - message_pain_hook("%^s is unharmed.", m_name); - return; - } - - /* Note -- subtle fix -CFT */ - newhp = (long)(m_ptr->hp); - oldhp = newhp + (long)(dam); - tmp = (newhp * 100L) / oldhp; - percentage = (int)(tmp); - - - /* Jelly's, Mold's, Vortex's, Quthl's */ - if (strchr("jmvQ", r_ptr->d_char)) - { - if (percentage > 95) - message_pain_hook("%^s barely notices.", m_name); - else if (percentage > 75) - message_pain_hook("%^s flinches.", m_name); - else if (percentage > 50) - message_pain_hook("%^s squelches.", m_name); - else if (percentage > 35) - message_pain_hook("%^s quivers in pain.", m_name); - else if (percentage > 20) - message_pain_hook("%^s writhes about.", m_name); - else if (percentage > 10) - message_pain_hook("%^s writhes in agony.", m_name); - else - message_pain_hook("%^s jerks limply.", m_name); - } - - /* Dogs and Hounds */ - else if (strchr("CZ", r_ptr->d_char)) - { - if (percentage > 95) - message_pain_hook("%^s shrugs off the attack.", m_name); - else if (percentage > 75) - message_pain_hook("%^s snarls with pain.", m_name); - else if (percentage > 50) - message_pain_hook("%^s yelps in pain.", m_name); - else if (percentage > 35) - message_pain_hook("%^s howls in pain.", m_name); - else if (percentage > 20) - message_pain_hook("%^s howls in agony.", m_name); - else if (percentage > 10) - message_pain_hook("%^s writhes in agony.", m_name); - else - message_pain_hook("%^s yelps feebly.", m_name); - } - - /* One type of monsters (ignore,squeal,shriek) */ - else if (strchr("FIKMRSXabclqrst", r_ptr->d_char)) - { - if (percentage > 95) - message_pain_hook("%^s ignores the attack.", m_name); - else if (percentage > 75) - message_pain_hook("%^s grunts with pain.", m_name); - else if (percentage > 50) - message_pain_hook("%^s squeals in pain.", m_name); - else if (percentage > 35) - message_pain_hook("%^s shrieks in pain.", m_name); - else if (percentage > 20) - message_pain_hook("%^s shrieks in agony.", m_name); - else if (percentage > 10) - message_pain_hook("%^s writhes in agony.", m_name); - else - message_pain_hook("%^s cries out feebly.", m_name); - } - - /* Another type of monsters (shrug,cry,scream) */ - else - { - if (percentage > 95) - message_pain_hook("%^s shrugs off the attack.", m_name); - else if (percentage > 75) - message_pain_hook("%^s grunts with pain.", m_name); - else if (percentage > 50) - message_pain_hook("%^s cries out in pain.", m_name); - else if (percentage > 35) - message_pain_hook("%^s screams in pain.", m_name); - else if (percentage > 20) - message_pain_hook("%^s screams in agony.", m_name); - else if (percentage > 10) - message_pain_hook("%^s writhes in agony.", m_name); - else - message_pain_hook("%^s cries out feebly.", m_name); - } -} - - - -/* - * Learn about an "observed" resistance. - */ -void update_smart_learn(int m_idx, int what) -{ - monster_type *m_ptr = &m_list[m_idx]; - - monster_race *r_ptr = race_inf(m_ptr); - - - /* Not allowed to learn */ - if (!smart_learn) return; - - /* Too stupid to learn anything */ - if (r_ptr->flags2 & (RF2_STUPID)) return; - - /* Not intelligent, only learn sometimes */ - if (!(r_ptr->flags2 & (RF2_SMART)) && (rand_int(100) < 50)) return; - - - /* XXX XXX XXX */ - - /* Analyze the knowledge */ - switch (what) - { - case DRS_ACID: - if (p_ptr->resist_acid) m_ptr->smart |= (SM_RES_ACID); - if (p_ptr->oppose_acid) m_ptr->smart |= (SM_OPP_ACID); - if (p_ptr->immune_acid) m_ptr->smart |= (SM_IMM_ACID); - break; - - case DRS_ELEC: - if (p_ptr->resist_elec) m_ptr->smart |= (SM_RES_ELEC); - if (p_ptr->oppose_elec) m_ptr->smart |= (SM_OPP_ELEC); - if (p_ptr->immune_elec) m_ptr->smart |= (SM_IMM_ELEC); - break; - - case DRS_FIRE: - if (p_ptr->resist_fire) m_ptr->smart |= (SM_RES_FIRE); - if (p_ptr->oppose_fire) m_ptr->smart |= (SM_OPP_FIRE); - if (p_ptr->immune_fire) m_ptr->smart |= (SM_IMM_FIRE); - break; - - case DRS_COLD: - if (p_ptr->resist_cold) m_ptr->smart |= (SM_RES_COLD); - if (p_ptr->oppose_cold) m_ptr->smart |= (SM_OPP_COLD); - if (p_ptr->immune_cold) m_ptr->smart |= (SM_IMM_COLD); - break; - - case DRS_POIS: - if (p_ptr->resist_pois) m_ptr->smart |= (SM_RES_POIS); - if (p_ptr->oppose_pois) m_ptr->smart |= (SM_OPP_POIS); - break; - - - case DRS_NETH: - if (p_ptr->resist_neth) m_ptr->smart |= (SM_RES_NETH); - break; - - case DRS_LITE: - if (p_ptr->resist_lite) m_ptr->smart |= (SM_RES_LITE); - break; - - case DRS_DARK: - if (p_ptr->resist_dark) m_ptr->smart |= (SM_RES_DARK); - break; - - case DRS_FEAR: - if (p_ptr->resist_fear) m_ptr->smart |= (SM_RES_FEAR); - break; - - case DRS_CONF: - if (p_ptr->resist_conf) m_ptr->smart |= (SM_RES_CONF); - break; - - case DRS_CHAOS: - if (p_ptr->resist_chaos) m_ptr->smart |= (SM_RES_CHAOS); - break; - - case DRS_DISEN: - if (p_ptr->resist_disen) m_ptr->smart |= (SM_RES_DISEN); - break; - - case DRS_BLIND: - if (p_ptr->resist_blind) m_ptr->smart |= (SM_RES_BLIND); - break; - - case DRS_NEXUS: - if (p_ptr->resist_nexus) m_ptr->smart |= (SM_RES_NEXUS); - break; - - case DRS_SOUND: - if (p_ptr->resist_sound) m_ptr->smart |= (SM_RES_SOUND); - break; - - case DRS_SHARD: - if (p_ptr->resist_shard) m_ptr->smart |= (SM_RES_SHARD); - break; - - - case DRS_FREE: - if (p_ptr->free_act) m_ptr->smart |= (SM_IMM_FREE); - break; - - case DRS_MANA: - if (!p_ptr->msp) m_ptr->smart |= (SM_IMM_MANA); - break; - - case DRS_REFLECT: - if (p_ptr->reflect) m_ptr-> smart |= (SM_IMM_REFLECT); - break; - } -} - - -/* - * Place the player in the dungeon XXX XXX - */ -s16b player_place(int y, int x) -{ - /* Paranoia XXX XXX */ - if (cave[y][x].m_idx != 0) return (0); - - /* Save player location */ - p_ptr->py = y; - p_ptr->px = x; - - /* Success */ - return ( -1); -} - -/* - * Drop all items carried by a monster - */ -void monster_drop_carried_objects(monster_type *m_ptr) -{ - s16b this_o_idx, next_o_idx = 0; - object_type forge; - object_type *o_ptr; - object_type *q_ptr; - - - /* Drop objects being carried */ - for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) - { - /* Acquire object */ - o_ptr = &o_list[this_o_idx]; - - /* Acquire next object */ - next_o_idx = o_ptr->next_o_idx; - - /* Paranoia */ - o_ptr->held_m_idx = 0; - - /* Get local object */ - q_ptr = &forge; - - /* Copy the object */ - object_copy(q_ptr, o_ptr); - - /* Delete the object */ - delete_object_idx(this_o_idx); - - /* Drop it */ - drop_near(q_ptr, -1, m_ptr->fy, m_ptr->fx); - } - - /* Forget objects */ - m_ptr->hold_o_idx = 0; -} |