/** * Calculate a monster's maximum spell power. * * \param r_ptr is the monster we're studying * \param resist is the degree of resistance we're assuming to any * attack type (-1 = vulnerable ... 3 = immune) */ int best_spell_power(const monster_race *r_ptr, int resist) { const struct mon_spell *rs_ptr; const struct spell_effect *re_ptr; int dam = 0, best_dam = 0; /* Extract the monster level */ int rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1); for (rs_ptr = mon_spell_table; rs_ptr->index < RSF_MAX; rs_ptr++) { if (rsf_has(r_ptr->spell_flags, rs_ptr->index)) { /* Get the maximum basic damage output of the spell (could be 0) */ dam = mon_spell_dam(rs_ptr->index, mon_hp(r_ptr, MAXIMISE), rlev, MAXIMISE); /* For all attack forms the player can save against, damage * is halved */ if (rs_ptr->save) dam /= 2; /* Adjust the real damage by the assumed resistance (if it is a * resistable type) */ if (rs_ptr->gf) dam = adjust_dam(p_ptr, rs_ptr->gf, dam, MAXIMISE, resist); /* Add the power ratings assigned to the various possible spell * effects (which is crucial for non-damaging spells) */ for (re_ptr = spell_effect_table; re_ptr->index < RSE_MAX; re_ptr++) { if ((re_ptr->method && (re_ptr->method == rs_ptr->index)) || (re_ptr->gf && (re_ptr->gf == rs_ptr->gf))) { /* First we adjust the real damage if necessary */ if (re_ptr->power.dice) dam = (dam * re_ptr->power.dice) / 100; /* Then we add any flat rating for this effect */ dam += re_ptr->power.base; /* Then we add any rlev-dependent rating */ if (re_ptr->power.m_bonus < 0) dam += re_ptr->power.sides / (rlev + 1); else if (re_ptr->power.m_bonus > 0) dam += (re_ptr->power.sides * rlev) / 100; } } /* Update the best_dam tracker */ if (dam > best_dam) best_dam = dam; } } return best_dam; }
/** * Calculate a monster's maximum spell power. * * \param race is the monster we're studying * \param resist is the degree of resistance we're assuming to any * attack type (-1 = vulnerable ... 3 = immune) */ int best_spell_power(const struct monster_race *race, int resist) { const struct mon_spell_info *info; int dam = 0, best_dam = 0; /* Extract the monster level */ int rlev = ((race->level >= 1) ? race->level : 1); for (info = mon_spell_types; info->index < RSF_MAX; info++) { if (rsf_has(race->spell_flags, info->index)) { /* Get the spell */ const struct monster_spell *spell = monster_spell_by_index(info->index); if (!spell) continue; /* Get the maximum basic damage output of the spell (could be 0) */ dam = mon_spell_dam(info->index, mon_hp(race, MAXIMISE), race, MAXIMISE); /* For all attack forms the player can save against, damage * is halved */ if (spell->save_message) dam /= 2; /* Adjust the real damage by the assumed resistance (if it is a * resistable type) */ if (monster_spell_is_projectable(info->index)) dam = adjust_dam(player, spell->effect->params[0], dam, MAXIMISE, 1); /* Add the power rating (crucial for non-damaging spells) */ /* First we adjust the real damage if necessary */ if (spell->power.dice) dam = (dam * spell->power.dice) / 100; /* Then we add any flat rating for this effect */ dam += spell->power.base; /* Then we add any rlev-dependent rating */ if (spell->power.m_bonus == 1) dam += (spell->power.sides * rlev) / 100; else if (spell->power.m_bonus == 2) dam += spell->power.sides / (rlev + 1); } /* Update the best_dam tracker */ if (dam > best_dam) best_dam = dam; } return best_dam; }
/** * Attempts to place a monster of the given race at the given location. * * If `sleep` is true, the monster is placed with its default sleep value, * which is given in monster.txt. * * `origin` is the item origin to use for any monster drops (e.g. ORIGIN_DROP, * ORIGIN_DROP_PIT, etc.) * * To give the player a sporting chance, some especially dangerous * monsters are marked as "FORCE_SLEEP" in monster.txt, which will * cause them to be placed with low energy. This helps ensure that * if such a monster suddenly appears in line-of-sight (due to a * summon, for instance), the player gets a chance to move before * they do. * * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters. * * This is the only function which may place a monster in the dungeon, * except for the savefile loading code, which calls place_monster() * directly. */ static bool place_new_monster_one(struct chunk *c, int y, int x, struct monster_race *race, bool sleep, byte origin) { int i; struct monster *mon; struct monster monster_body; assert(square_in_bounds(c, y, x)); assert(race && race->name); /* Not where monsters already are */ if (square_monster(c, y, x)) return false; /* Not where the player already is */ if ((player->py == y) && (player->px == x)) return false; /* Prevent monsters from being placed where they cannot walk, but allow other feature types */ if (!square_is_monster_walkable(c, y, x)) return false; /* No creation on glyph of warding */ if (square_iswarded(c, y, x)) return false; /* "unique" monsters must be "unique" */ if (rf_has(race->flags, RF_UNIQUE) && race->cur_num >= race->max_num) return (false); /* Depth monsters may NOT be created out of depth */ if (rf_has(race->flags, RF_FORCE_DEPTH) && player->depth < race->level) return (false); /* Add to level feeling, note uniques for cheaters */ c->mon_rating += race->level * race->level; /* Check out-of-depth-ness */ if (race->level > c->depth) { if (rf_has(race->flags, RF_UNIQUE)) { /* OOD unique */ if (OPT(player, cheat_hear)) msg("Deep unique (%s).", race->name); } else { /* Normal monsters but OOD */ if (OPT(player, cheat_hear)) msg("Deep monster (%s).", race->name); } /* Boost rating by power per 10 levels OOD */ c->mon_rating += (race->level - c->depth) * race->level * race->level; } else if (rf_has(race->flags, RF_UNIQUE) && OPT(player, cheat_hear)) msg("Unique (%s).", race->name); /* Get local monster */ mon = &monster_body; /* Clean out the monster */ memset(mon, 0, sizeof(struct monster)); /* Save the race */ mon->race = race; /* Enforce sleeping if needed */ if (sleep && race->sleep) { int val = race->sleep; mon->m_timed[MON_TMD_SLEEP] = ((val * 2) + randint1(val * 10)); } /* Uniques get a fixed amount of HP */ if (rf_has(race->flags, RF_UNIQUE)) mon->maxhp = race->avg_hp; else { mon->maxhp = mon_hp(race, RANDOMISE); mon->maxhp = MAX(mon->maxhp, 1); } /* And start out fully healthy */ mon->hp = mon->maxhp; /* Extract the monster base speed */ mon->mspeed = race->speed; /* Hack -- small racial variety */ if (!rf_has(race->flags, RF_UNIQUE)) { /* Allow some small variation per monster */ i = turn_energy(race->speed) / 10; if (i) mon->mspeed += rand_spread(0, i); } /* Give a random starting energy */ mon->energy = (byte)randint0(50); /* Force monster to wait for player */ if (rf_has(race->flags, RF_FORCE_SLEEP)) mflag_on(mon->mflag, MFLAG_NICE); /* Radiate light? */ if (rf_has(race->flags, RF_HAS_LIGHT)) player->upkeep->update |= PU_UPDATE_VIEW; /* Is this obviously a monster? (Mimics etc. aren't) */ if (rf_has(race->flags, RF_UNAWARE)) mflag_on(mon->mflag, MFLAG_CAMOUFLAGE); else mflag_off(mon->mflag, MFLAG_CAMOUFLAGE); /* Set the color if necessary */ if (rf_has(race->flags, RF_ATTR_RAND)) mon->attr = randint1(BASIC_COLORS - 1); /* Place the monster in the dungeon */ if (!place_monster(c, y, x, mon, origin)) return (false); /* Success */ return (true); }
/** * Attempts to place a monster of the given race at the given location. * * If `sleep` is true, the monster is placed with its default sleep value, * which is given in monster.txt. * * `origin` is the item origin to use for any monster drops (e.g. ORIGIN_DROP, * ORIGIN_DROP_PIT, etc.) * * To give the player a sporting chance, some especially dangerous * monsters are marked as "FORCE_SLEEP" in monster.txt, which will * cause them to be placed with low energy. This helps ensure that * if such a monster suddenly appears in line-of-sight (due to a * summon, for instance), the player gets a chance to move before * they do. * * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters. * * This is the only function which may place a monster in the dungeon, * except for the savefile loading code, which calls place_monster() * directly. */ static bool place_new_monster_one(int y, int x, monster_race *race, bool sleep, byte origin) { int i; struct monster *mon; struct monster monster_body; assert(cave_in_bounds(cave, y, x)); assert(race && race->name); /* Require empty space */ if (!cave_isempty(cave, y, x)) return (FALSE); /* No creation on glyph of warding */ if (cave_iswarded(cave, y, x)) return FALSE; /* "unique" monsters must be "unique" */ if (rf_has(race->flags, RF_UNIQUE) && race->cur_num >= race->max_num) return (FALSE); /* Depth monsters may NOT be created out of depth */ if (rf_has(race->flags, RF_FORCE_DEPTH) && p_ptr->depth < race->level) return (FALSE); /* Add to level feeling */ cave->mon_rating += race->power / 20; /* Check out-of-depth-ness */ if (race->level > p_ptr->depth) { if (rf_has(race->flags, RF_UNIQUE)) { /* OOD unique */ if (OPT(cheat_hear)) msg("Deep unique (%s).", race->name); } else { /* Normal monsters but OOD */ if (OPT(cheat_hear)) msg("Deep monster (%s).", race->name); } /* Boost rating by power per 10 levels OOD */ cave->mon_rating += (race->level - p_ptr->depth) * race->power / 200; } /* Note uniques for cheaters */ else if (rf_has(race->flags, RF_UNIQUE) && OPT(cheat_hear)) msg("Unique (%s).", race->name); /* Get local monster */ mon = &monster_body; /* Clean out the monster */ (void)WIPE(mon, monster_type); /* Save the race */ mon->race = race; /* Enforce sleeping if needed */ if (sleep && race->sleep) { int val = race->sleep; mon->m_timed[MON_TMD_SLEEP] = ((val * 2) + randint1(val * 10)); } /* Uniques get a fixed amount of HP */ if (rf_has(race->flags, RF_UNIQUE)) mon->maxhp = race->avg_hp; else { mon->maxhp = mon_hp(race, RANDOMISE); mon->maxhp = MAX(mon->maxhp, 1); } /* And start out fully healthy */ mon->hp = mon->maxhp; /* Extract the monster base speed */ mon->mspeed = race->speed; /* Hack -- small racial variety */ if (!rf_has(race->flags, RF_UNIQUE)) { /* Allow some small variation per monster */ i = extract_energy[race->speed] / 10; if (i) mon->mspeed += rand_spread(0, i); } /* Give a random starting energy */ mon->energy = (byte)randint0(50); /* Force monster to wait for player */ if (rf_has(race->flags, RF_FORCE_SLEEP)) mon->mflag |= (MFLAG_NICE); /* Radiate light? */ if (rf_has(race->flags, RF_HAS_LIGHT)) p_ptr->update |= PU_UPDATE_VIEW; /* Is this obviously a monster? (Mimics etc. aren't) */ if (rf_has(race->flags, RF_UNAWARE)) mon->unaware = TRUE; else mon->unaware = FALSE; /* Set the color if necessary */ if (rf_has(race->flags, RF_ATTR_RAND)) mon->attr = randint1(BASIC_COLORS - 1); /* Place the monster in the dungeon */ if (!place_monster(y, x, mon, origin)) return (FALSE); /* Success */ return (TRUE); }