/** * Remove the "bad" spells from a spell list */ static void remove_bad_spells(struct monster *mon, bitflag f[RSF_SIZE]) { bitflag f2[RSF_SIZE], ai_flags[OF_SIZE], ai_pflags[PF_SIZE]; struct element_info el[ELEM_MAX]; bool know_something = false; /* Stupid monsters act randomly */ if (rf_has(mon->race->flags, RF_STUPID)) return; /* Take working copy of spell flags */ rsf_copy(f2, f); /* Don't heal if full */ if (mon->hp >= mon->maxhp) rsf_off(f2, RSF_HEAL); /* Don't haste if hasted with time remaining */ if (mon->m_timed[MON_TMD_FAST] > 10) rsf_off(f2, RSF_HASTE); /* Don't teleport to if the player is already next to us */ if (mon->cdis == 1) rsf_off(f2, RSF_TELE_TO); /* Update acquired knowledge */ of_wipe(ai_flags); pf_wipe(ai_pflags); if (OPT(birth_ai_learn)) { size_t i; /* Occasionally forget player status */ if (one_in_(100)) { of_wipe(mon->known_pstate.flags); pf_wipe(mon->known_pstate.pflags); for (i = 0; i < ELEM_MAX; i++) mon->known_pstate.el_info[i].res_level = 0; } /* Use the memorized info */ of_copy(ai_flags, mon->known_pstate.flags); pf_copy(ai_pflags, mon->known_pstate.pflags); if (!of_is_empty(ai_flags) || !pf_is_empty(ai_pflags)) know_something = true; for (i = 0; i < ELEM_MAX; i++) { el[i].res_level = mon->known_pstate.el_info[i].res_level; if (el[i].res_level != 0) know_something = true; } } /* Cancel out certain flags based on knowledge */ if (know_something) unset_spells(f2, ai_flags, ai_pflags, el, mon->race); /* use working copy of spell flags */ rsf_copy(f, f2); }
/** * Turn off spells with a side effect or a gf_type that is resisted by * something in flags, subject to intelligence and chance. * * \param spells is the set of spells we're pruning * \param flags is the set of flags we're testing * \param r_ptr is the monster type we're operating on */ void unset_spells(bitflag *spells, bitflag *flags, const monster_race *r_ptr) { const struct mon_spell *rs_ptr; const struct spell_effect *re_ptr; /* First we test the gf (projectable) spells */ for (rs_ptr = mon_spell_table; rs_ptr->index < RSF_MAX; rs_ptr++) if (rs_ptr->gf && randint0(100) < check_for_resist(p_ptr, rs_ptr->gf, flags, FALSE) * (rf_has(r_ptr->flags, RF_SMART) ? 2 : 1) * 25) rsf_off(spells, rs_ptr->index); /* ... then we test the non-gf side effects */ for (re_ptr = spell_effect_table; re_ptr->index < RSE_MAX; re_ptr++) if (re_ptr->method && re_ptr->res_flag && (rf_has(r_ptr->flags, RF_SMART) || !one_in_(3)) && of_has(flags, re_ptr->res_flag)) rsf_off(spells, re_ptr->method); }
/** * Set a spell bitflag to allow only a specific set of spell types. * * \param f is the set of spell flags we're pruning * \param type is the spell type(s) we're allowing */ void set_spells(bitflag *f, enum mon_spell_type type) { const struct mon_spell *rs_ptr; for (rs_ptr = mon_spell_table; rs_ptr->index < RSF_MAX; rs_ptr++) if (rsf_has(f, rs_ptr->index) && !(rs_ptr->type & type)) rsf_off(f, rs_ptr->index); return; }
/** * Turn off spells with a side effect or a gf_type that is resisted by * something in flags, subject to intelligence and chance. * * \param spells is the set of spells we're pruning * \param flags is the set of object flags we're testing * \param pflags is the set of player flags we're testing * \param el is what we know about the monster's elemental resists * \param race is the monster type we're operating on */ void unset_spells(bitflag *spells, bitflag *flags, bitflag *pflags, struct element_info *el, const struct monster_race *race) { const struct mon_spell_info *info; bool smart = rf_has(race->flags, RF_SMART); for (info = mon_spell_types; info->index < RSF_MAX; info++) { const struct monster_spell *spell = monster_spell_by_index(info->index); const struct effect *effect; /* Ignore missing spells */ if (!spell) continue; if (!rsf_has(spells, info->index)) continue; /* Get the effect */ effect = spell->effect; /* First we test the elemental spells */ if (info->type & (RST_BOLT | RST_BALL | RST_BREATH)) { int element = effect->params[0]; int learn_chance = el[element].res_level * (smart ? 50 : 25); if (randint0(100) < learn_chance) rsf_off(spells, info->index); } else { /* Now others with resisted effects */ while (effect) { /* Timed effects */ if ((smart || !one_in_(3)) && (effect->index == EF_TIMED_INC) && of_has(flags, timed_protect_flag(effect->params[0]))) break; /* Mana drain */ if ((smart || one_in_(2)) && (effect->index == EF_DRAIN_MANA) && pf_has(pflags, PF_NO_MANA)) break; effect = effect->next; } if (effect) rsf_off(spells, info->index); } } }
/** * Set a spell bitflag to ignore a specific set of spell types. * * \param f is the set of spell flags we're pruning * \param types is the spell type(s) we're ignoring */ void ignore_spells(bitflag *f, int types) { const struct mon_spell_info *info; for (info = mon_spell_types; info->index < RSF_MAX; info++) if (rsf_has(f, info->index) && (info->type & types)) rsf_off(f, info->index); return; }