return values: * 1: successful spell * 0: unsuccessful spell */
| 127 | * 0: unsuccessful spell |
| 128 | */ |
| 129 | int |
| 130 | castmu( |
| 131 | struct monst *mtmp, /* caster */ |
| 132 | struct attack *mattk, /* caster's current attack */ |
| 133 | boolean thinks_it_foundyou, /* might be mistaken if displaced */ |
| 134 | boolean foundyou) /* knows hero's precise location */ |
| 135 | { |
| 136 | int dmg, ml = mtmp->m_lev; |
| 137 | int ret; |
| 138 | int spellnum = 0; |
| 139 | |
| 140 | /* Three cases: |
| 141 | * -- monster is attacking you. Search for a useful spell. |
| 142 | * -- monster thinks it's attacking you. Search for a useful spell, |
| 143 | * without checking for undirected. If the spell found is directed, |
| 144 | * it fails with cursetxt() and loss of mspec_used. |
| 145 | * -- monster isn't trying to attack. Select a spell once. Don't keep |
| 146 | * searching; if that spell is not useful (or if it's directed), |
| 147 | * return and do something else. |
| 148 | * Since most spells are directed, this means that a monster that isn't |
| 149 | * attacking casts spells only a small portion of the time that an |
| 150 | * attacking monster does. |
| 151 | */ |
| 152 | if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) { |
| 153 | int cnt = 40; |
| 154 | |
| 155 | do { |
| 156 | spellnum = choose_monster_spell(mtmp, mattk->adtyp); |
| 157 | /* not trying to attack? don't allow directed spells */ |
| 158 | if (!thinks_it_foundyou) { |
| 159 | if (!is_undirected_spell(spellnum) |
| 160 | || spell_would_be_useless(mtmp, spellnum)) { |
| 161 | if (foundyou) |
| 162 | impossible( |
| 163 | "spellcasting monster found you and doesn't know it?"); |
| 164 | return M_ATTK_MISS; |
| 165 | } |
| 166 | break; |
| 167 | } |
| 168 | } while (--cnt > 0 |
| 169 | && spell_would_be_useless(mtmp, spellnum)); |
| 170 | if (cnt == 0) |
| 171 | return M_ATTK_MISS; |
| 172 | } |
| 173 | |
| 174 | /* monster unable to cast spells? */ |
| 175 | if (mtmp->mcan || mtmp->mspec_used || !ml |
| 176 | || m_seenres(mtmp, cvt_adtyp_to_mseenres(mattk->adtyp))) { |
| 177 | cursetxt(mtmp, is_undirected_spell(spellnum)); |
| 178 | return M_ATTK_MISS; |
| 179 | } |
| 180 | |
| 181 | debugpline3("castmu:%s,lvl:%i,spell:%i", noit_Monnam(mtmp), ml, spellnum); |
| 182 | |
| 183 | if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) { |
| 184 | /* monst->m_lev is unsigned (uchar), monst->mspec_used is int */ |
| 185 | mtmp->mspec_used = (int) ((mtmp->m_lev < 8) ? (10 - mtmp->m_lev) : 2); |
| 186 | } |
no test coverage detected