/** * Process a monster's turn * * In several cases, we directly update the monster lore * * Note that a monster is only allowed to "reproduce" if there * are a limited number of "reproducing" monsters on the current * level. This should prevent the level from being "swamped" by * reproducing monsters. It also allows a large mass of mice to * prevent a louse from multiplying, but this is a small price to * pay for a simple multiplication method. * * XXX Monster fear is slightly odd, in particular, monsters will * fixate on opening a door even if they cannot open it. Actually, * the same thing happens to normal monsters when they hit a door * * In addition, monsters which *cannot* open or bash down a door * will still stand there trying to open it... XXX XXX XXX * * Technically, need to check for monster in the way combined * with that monster being in a wall (or door?) XXX */ static void monster_turn(struct chunk *c, struct monster *mon) { struct monster_lore *lore = get_lore(mon->race); bool did_something = false; int i; int dir = 0; bool stagger = false; bool tracking = false; char m_name[80]; /* Get the monster name */ monster_desc(m_name, sizeof(m_name), mon, MDESC_CAPITAL | MDESC_IND_HID); /* Try to multiply - this can use up a turn */ if (monster_turn_multiply(c, mon)) return; /* Attempt to cast a spell */ if (make_attack_spell(mon)) return; /* Work out what kind of movement to use - AI or staggered movement */ if (!monster_turn_should_stagger(mon)) { if (!get_move(c, mon, &dir, &tracking)) return; } else { stagger = true; } /* Process moves */ for (i = 0; i < 5 && !did_something; i++) { int oy = mon->fy; int ox = mon->fx; /* Get the direction (or stagger) */ int d = (stagger ? ddd[randint0(8)] : side_dirs[dir][i]); /* Get the destination */ int ny = oy + ddy[d]; int nx = ox + ddx[d]; /* Tracking monsters have their best direction, don't change */ if ((i > 0) && !stagger && !square_isview(c, oy, ox) && tracking) { break; } /* Check if we can move */ if (!monster_turn_can_move(c, mon, m_name, nx, ny, &did_something)) continue; /* Try to break the glyph if there is one. This can happen multiple * times per turn because failure does not break the loop */ if (square_iswarded(c, ny, nx) && !monster_turn_glyph(c, mon, nx, ny)) continue; /* Break a decoy if there is one */ if (square_isdecoyed(c, ny, nx)) { /* Learn about if the monster attacks */ if (monster_is_visible(mon)) rf_on(lore->flags, RF_NEVER_BLOW); /* Some monsters never attack */ if (rf_has(mon->race->flags, RF_NEVER_BLOW)) continue; /* Wait a minute... */ square_destroy_decoy(c, ny, nx); did_something = true; break; } /* The player is in the way. */ if (square_isplayer(c, ny, nx)) { /* Learn about if the monster attacks */ if (monster_is_visible(mon)) rf_on(lore->flags, RF_NEVER_BLOW); /* Some monsters never attack */ if (rf_has(mon->race->flags, RF_NEVER_BLOW)) continue; /* Otherwise, attack the player */ make_attack_normal(mon, player); did_something = true; break; } else { /* Some monsters never move */ if (rf_has(mon->race->flags, RF_NEVER_MOVE)) { /* Learn about lack of movement */ if (monster_is_visible(mon)) rf_on(lore->flags, RF_NEVER_MOVE); return; } } /* A monster is in the way, try to push past/kill */ if (square_monster(c, ny, nx)) { did_something = monster_turn_try_push(c, mon, m_name, nx, ny); } else { /* Otherwise we can just move */ monster_swap(oy, ox, ny, nx); did_something = true; } /* Scan all objects in the grid, if we reached it */ if (mon == square_monster(c, ny, nx)) { monster_desc(m_name, sizeof(m_name), mon, MDESC_CAPITAL | MDESC_IND_HID); monster_turn_grab_objects(c, mon, m_name, nx, ny); } } if (did_something) { /* Learn about no lack of movement */ if (monster_is_visible(mon)) rf_on(lore->flags, RF_NEVER_MOVE); /* Possible disturb */ if (monster_is_visible(mon) && monster_is_in_view(mon) && OPT(player, disturb_near)) disturb(player, 0); } /* Hack -- get "bold" if out of options */ if (!did_something && mon->m_timed[MON_TMD_FEAR]) mon_clear_timed(mon, MON_TMD_FEAR, MON_TMD_FLG_NOTIFY, false); /* If we see an unaware monster do something, become aware of it */ if (did_something && monster_is_camouflaged(mon)) become_aware(mon); }
/** * Monster is recognisably a monster to the player */ bool monster_is_obvious(const struct monster *mon) { return monster_is_visible(mon) && !monster_is_camouflaged(mon); }