void on_p_hit_m(int m_idx) { if (p_ptr->special_attack & ATTACK_CONFUSE) { monster_type *m_ptr = &m_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; char m_name[MAX_NLEN]; monster_desc(m_name, m_ptr, 0); p_ptr->special_attack &= ~(ATTACK_CONFUSE); msg_print("Your hands stop glowing."); p_ptr->redraw |= (PR_STATUS); if (r_ptr->flags3 & RF3_NO_CONF) { mon_lore_3(m_ptr, RF3_NO_CONF); msg_format("%^s is unaffected.", m_name); } else if (randint0(100) < r_ptr->level) { msg_format("%^s is unaffected.", m_name); } else { msg_format("%^s appears confused.", m_name); (void)set_monster_confused(m_idx, MON_CONFUSED(m_ptr) + 10 + randint0(p_ptr->lev) / 5); } } }
/*! * @brief フロアに存在する全モンスターを消去する / * Hack -- Delete all monsters * @return なし */ static void do_cmd_wiz_zap_all(void) { int i; /* Genocide everyone */ for (i = 1; i < m_max; i++) { monster_type *m_ptr = &m_list[i]; /* Paranoia -- Skip dead monsters */ if (!m_ptr->r_idx) continue; /* Skip the mount */ if (i == p_ptr->riding) continue; if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) { char m_name[80]; monster_desc(m_name, m_ptr, MD_INDEF_VISIBLE); do_cmd_write_nikki(NIKKI_NAMED_PET, RECORD_NAMED_PET_WIZ_ZAP, m_name); } /* Delete this monster */ delete_monster_idx(i); } }
bool target_set_closest(int mode) { int y, x, m_idx; monster_type *m_ptr; char m_name[80]; bool visibility; struct point_set *targets; /* Cancel old target */ target_set_monster(0); /* Get ready to do targetting */ targets = target_set_interactive_prepare(mode); /* If nothing was prepared, then return */ if (point_set_size(targets) < 1) { msg("No Available Target."); point_set_dispose(targets); return FALSE; } /* Find the first monster in the queue */ y = targets->pts[0].y; x = targets->pts[0].x; m_idx = cave->m_idx[y][x]; /* Target the monster, if possible */ if ((m_idx <= 0) || !target_able(m_idx)) { msg("No Available Target."); point_set_dispose(targets); return FALSE; } /* Target the monster */ m_ptr = cave_monster(cave, m_idx); monster_desc(m_name, sizeof(m_name), m_ptr, 0x00); if (!(mode & TARGET_QUIET)) msg("%^s is targeted.", m_name); Term_fresh(); /* Set up target information */ monster_race_track(m_ptr->r_idx); health_track(p_ptr, cave->m_idx[y][x]); target_set_monster(m_idx); /* Visual cue */ Term_get_cursor(&visibility); (void)Term_set_cursor(TRUE); move_cursor_relative(y, x); Term_redraw_section(x, y, x, y); /* TODO: what's an appropriate amount of time to spend highlighting */ Term_xtra(TERM_XTRA_DELAY, 150); (void)Term_set_cursor(visibility); point_set_dispose(targets); return TRUE; }
/** * Attack the monster at the given location * * We get blows until energy drops below that required for another blow, or * until the target monster dies. Each blow is handled by py_attack_real(). * We don't allow @ to spend more than 100 energy in one go, to avoid slower * monsters getting double moves. */ void py_attack(int y, int x) { int blow_energy = 10000 / p_ptr->state.num_blows; int blows = 0; bool fear = FALSE; monster_type *m_ptr = cave_monster(cave, cave->m_idx[y][x]); /* disturb the player */ disturb(p_ptr, 0,0); /* Initialize the energy used */ p_ptr->energy_use = 0; /* Attack until energy runs out or enemy dies. We limit energy use to 100 * to avoid giving monsters a possible double move. */ while (p_ptr->energy >= blow_energy * (blows + 1)) { bool stop = py_attack_real(y, x, &fear); p_ptr->energy_use += blow_energy; if (stop || p_ptr->energy_use + blow_energy > 100) break; blows++; } /* Hack - delay fear messages */ if (fear && m_ptr->ml) { char m_name[80]; monster_desc(m_name, sizeof(m_name), m_ptr, 0); add_monster_message(m_name, cave->m_idx[y][x], MON_MSG_FLEE_IN_TERROR, TRUE); } }
/** * Attack the monster at the given location * * We get blows until energy drops below that required for another blow, or * until the target monster dies. Each blow is handled by py_attack_real(). * We don't allow @ to spend more than 100 energy in one go, to avoid slower * monsters getting double moves. */ void py_attack(int y, int x) { int blow_energy = 100 * z_info->move_energy / player->state.num_blows; int blows = 0; bool fear = FALSE; struct monster *mon = square_monster(cave, y, x); /* disturb the player */ disturb(player, 0); /* Initialize the energy used */ player->upkeep->energy_use = 0; /* Attack until energy runs out or enemy dies. We limit energy use to 100 * to avoid giving monsters a possible double move. */ while (player->energy >= blow_energy * (blows + 1)) { bool stop = py_attack_real(y, x, &fear); player->upkeep->energy_use += blow_energy; if (player->upkeep->energy_use + blow_energy > z_info->move_energy || stop) break; blows++; } /* Hack - delay fear messages */ if (fear && mflag_has(mon->mflag, MFLAG_VISIBLE)) { char m_name[80]; /* Don't set monster_desc flags, since add_monster_message does string * processing on m_name */ monster_desc(m_name, sizeof(m_name), mon, MDESC_DEFAULT); add_monster_message(m_name, mon, MON_MSG_FLEE_IN_TERROR, TRUE); } }
/* Handle the Terrifying Aura of Fear! */ void fear_process_p(void) { int i, r_level; for (i = 1; i < m_max; i++) { monster_type *m_ptr = &m_list[i]; monster_race *r_ptr; if (!m_ptr->r_idx) continue; if (!m_ptr->ml) continue; r_ptr = &r_info[m_ptr->ap_r_idx]; if (!(r_ptr->flags2 & RF2_AURA_FEAR)) continue; if (is_pet(m_ptr) || is_friendly(m_ptr)) continue; if (!projectable(py, px, m_ptr->fy, m_ptr->fx)) continue; r_level = _r_level(r_ptr); if (!fear_save_p(r_level/MAX(1, m_ptr->cdis-2))) { char m_name[80]; monster_desc(m_name, m_ptr, 0); msg_format("You behold the terrifying visage of %s!", m_name); mon_lore_2(m_ptr, RF2_AURA_FEAR); fear_add_p(r_level/MAX(1, m_ptr->cdis-2)); } } }
/* * Hack -- Display the "name" and "attr/chars" of a monster race */ static void roff_top(const int r_idx, int m_idx) { byte a1, a2; char c1, c2; char desc[80]; monster_race *r_ptr = &r_info[r_idx]; /* Describe the monster */ if (m_idx) { /* Describe the monster */ monster_desc(desc, sizeof(desc), m_idx, 0x80); /* Capitalise the first letter */ if (islower(desc[0])) desc[0] = toupper(desc[0]); } /* Not describing a specific monster, so hack a description */ else { /* Get the name */ race_desc(desc, sizeof(desc), r_idx, 0x400, 1); /* Capitalise the first letter */ if (islower(desc[0])) desc[0] = toupper(desc[0]); } /* Get the chars */ c1 = r_ptr->d_char; c2 = r_ptr->x_char; /* Get the attrs */ a1 = r_ptr->d_attr; a2 = r_ptr->x_attr; /* Clear the top line */ Term_erase(0, 0, 255); /* Reset the cursor */ Term_gotoxy(0, 0); /* Dump the name */ Term_addstr(-1, TERM_WHITE, desc); if (!use_dbltile && !use_trptile) { /* Append the "standard" attr/char info */ Term_addstr(-1, TERM_WHITE, " ('"); Term_addch(a1, c1); Term_addstr(-1, TERM_WHITE, "')"); /* Append the "optional" attr/char info */ Term_addstr(-1, TERM_WHITE, "/('"); Term_addch(a2, c2); if (use_bigtile && (a2 & 0x80)) Term_addch(255, -1); Term_addstr(-1, TERM_WHITE, "'):"); } }
void _rodeo_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Rodeo"); break; case SPELL_DESC: var_set_string(res, ""); break; case SPELL_CAST: { char m_name[80]; monster_type *m_ptr; monster_race *r_ptr; int rlev; var_set_bool(res, FALSE); if (p_ptr->riding) { msg_print("You are already riding."); return; } if (!do_riding(TRUE)) return; var_set_bool(res, TRUE); m_ptr = &m_list[p_ptr->riding]; r_ptr = &r_info[m_ptr->r_idx]; monster_desc(m_name, m_ptr, 0); msg_format("You ride on %s.", m_name); if (is_pet(m_ptr)) break; rlev = r_ptr->level; if (r_ptr->flags1 & RF1_UNIQUE) rlev = rlev * 3 / 2; if (rlev > 60) rlev = 60+(rlev-60)/2; if ( randint1(skills_riding_current() / 120 + p_ptr->lev * 2 / 3) > rlev && one_in_(2) && !p_ptr->inside_arena && !p_ptr->inside_battle && !(r_ptr->flags7 & RF7_GUARDIAN) && !(r_ptr->flags1 & RF1_QUESTOR) && rlev < p_ptr->lev * 3 / 2 + randint0(p_ptr->lev / 5) ) { msg_format("You tame %s.", m_name); set_pet(m_ptr); } else { msg_format("You have thrown off by %s.", m_name); rakuba(1,TRUE); p_ptr->riding = 0; } break; } default: default_spell(cmd, res); break; } }
/* * Determine if a given grid may be "walked" */ static bool do_cmd_walk_test(int y, int x) { int m_idx = cave->m_idx[y][x]; /* Allow attack on visible monsters if unafraid */ if ((m_idx > 0) && (cave_monster(cave, m_idx)->ml) && !is_mimicking(m_idx)) { /* Handle player fear */ if(check_state(p_ptr, OF_AFRAID, p_ptr->state.flags)) { /* Extract monster name (or "it") */ char m_name[80]; const monster_type *m_ptr; m_ptr = cave_monster(cave, m_idx); monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Message */ msgt(MSG_AFRAID, "You are too afraid to attack %s!", m_name); /* Nope */ return (FALSE); } return (TRUE); } /* If we don't know the grid, allow attempts to walk into it */ if (!(cave->info[y][x] & CAVE_MARK)) return TRUE; /* Require open space */ if (!cave_floor_bold(y, x)) { /* Rubble */ if (cave->feat[y][x] == FEAT_RUBBLE) msgt(MSG_HITWALL, "There is a pile of rubble in the way!"); /* Door */ else if (cave->feat[y][x] < FEAT_SECRET) return TRUE; /* Wall */ else msgt(MSG_HITWALL, "There is a wall in the way!"); /* Cancel repeat */ disturb(p_ptr, 0, 0); /* Nope */ return (FALSE); } /* Okay */ return (TRUE); }
/** * Attempts to set the timer of the given monster effect to `timer`. * * Checks to see if the monster resists the effect, using mon_resist_effect(). * If not, the effect is set to `timer` turns. If `timer` is 0, or if the * effect timer was 0, or if MON_TMD_FLG_NOTIFY is set in `flag`, then a * message is printed, unless MON_TMD_FLG_NOMESSAGE is set in `flag`. * * Set a timed monster event to 'v'. Give messages if the right flags are set. * Check if the monster is able to resist the spell. Mark the lore. * Returns TRUE if the monster was affected. * Return FALSE if the monster was unaffected. */ static bool mon_set_timed(monster_type *m_ptr, int ef_idx, int timer, u16b flag, bool id) { mon_timed_effect *effect; int m_note = 0; int resisted; int old_timer; assert(ef_idx >= 0 && ef_idx < MON_TMD_MAX); effect = &effects[ef_idx]; assert(m_ptr); old_timer = m_ptr->m_timed[ef_idx]; /* Ignore dead monsters */ if (!m_ptr->r_idx) return FALSE; /* No change */ if (old_timer == timer) return FALSE; if (timer == 0) { /* Turning off, usually mention */ m_note = effect->message_end; flag |= MON_TMD_FLG_NOTIFY; } else if (old_timer == 0) { /* Turning on, usually mention */ flag |= MON_TMD_FLG_NOTIFY; m_note = effect->message_begin; } else if (timer > old_timer) { /* Different message for increases, but don't automatically mention. */ m_note = effect->message_increase; } /* Determine if the monster resisted or not */ resisted = mon_resist_effect(m_ptr, ef_idx, timer, flag); if (resisted) m_note = MON_MSG_UNAFFECTED; else m_ptr->m_timed[ef_idx] = timer; if (p_ptr->health_who == m_ptr->midx) p_ptr->redraw |= (PR_HEALTH); /* Update the visuals, as appropriate. */ p_ptr->redraw |= (PR_MONLIST); /* Print a message if there is one, if the effect allows for it, and if * either the monster is visible, or we're trying to ID something */ if (m_note && (m_ptr->ml || id) && !(flag & MON_TMD_FLG_NOMESSAGE) && (flag & MON_TMD_FLG_NOTIFY)) { char m_name[80]; monster_desc(m_name, sizeof(m_name), m_ptr, 0x04); add_monster_message(m_name, m_ptr->midx, m_note, TRUE); } return !resisted; }
/* Monster Fear */ bool fear_process_m(int m_idx) { monster_type *m_ptr = &m_list[m_idx]; if (MON_MONFEAR(m_ptr) && !MON_CSLEEP(m_ptr)) { if (fear_save_m(m_ptr)) { bool recovered = FALSE; if (fear_save_m(m_ptr)) { set_monster_monfear(m_idx, 0); recovered = TRUE; } else { monster_race *r_ptr = &r_info[m_ptr->ap_r_idx]; recovered = set_monster_monfear(m_idx, MON_MONFEAR(m_ptr) - randint1(r_ptr->level / 20 + 1)); } if (recovered && is_seen(m_ptr)) { char m_name[80]; char m_poss[80]; monster_desc(m_poss, m_ptr, MD_PRON_VISIBLE | MD_POSSESSIVE); monster_desc(m_name, m_ptr, 0); msg_format("%^s recovers %s courage.", m_name, m_poss); } } else if (one_in_(3) && !fear_save_m(m_ptr)) { if (is_seen(m_ptr)) { char m_name[80]; monster_desc(m_name, m_ptr, 0); msg_format("%^s is scared stiff!", m_name); } return FALSE; } } return TRUE; }
void _grasp_spell(int cmd, variant *res) { switch (cmd) { case SPELL_NAME: var_set_string(res, "Vampiric Grasp"); break; case SPELL_DESC: var_set_string(res, "Pulls a target creature to you."); break; case SPELL_CAST: { int m_idx; bool fear = FALSE; monster_type *m_ptr; monster_race *r_ptr; char m_name[MAX_NLEN]; var_set_bool(res, FALSE); if (!target_set(TARGET_KILL)) break; if (!cave[target_row][target_col].m_idx) break; if (!player_has_los_bold(target_row, target_col)) break; if (!projectable(py, px, target_row, target_col)) break; var_set_bool(res, TRUE); m_idx = cave[target_row][target_col].m_idx; m_ptr = &m_list[m_idx]; r_ptr = &r_info[m_ptr->r_idx]; monster_desc(m_name, m_ptr, 0); if (r_ptr->flagsr & RFR_RES_TELE) { if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flagsr & RFR_RES_ALL)) { if (is_original_ap_and_seen(m_ptr)) r_ptr->r_flagsr |= RFR_RES_TELE; msg_format("%s is unaffected!", m_name); break; } else if (r_ptr->level > randint1(100)) { if (is_original_ap_and_seen(m_ptr)) r_ptr->r_flagsr |= RFR_RES_TELE; msg_format("%s resists!", m_name); break; } } msg_format("You grasp %s.", m_name); teleport_monster_to(m_idx, py, px, 100, TELEPORT_PASSIVE); mon_take_hit(m_idx, damroll(10, 10), &fear, extract_note_dies(real_r_ptr(m_ptr))); break; } default: default_spell(cmd, res); break; } }
/* * Determine if a given grid may be "walked" */ static bool do_cmd_walk_test(int y, int x) { /* Allow attack on visible monsters if unafraid */ if ((cave_m_idx[y][x] > 0) && (mon_list[cave_m_idx[y][x]].ml)) { /* Handle player fear */ if(p_ptr->state.afraid) { /* Extract monster name (or "it") */ char m_name[80]; monster_type *m_ptr; m_ptr = &mon_list[cave_m_idx[y][x]]; monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Message */ message_format(MSG_AFRAID, 0, "You are too afraid to attack %s!", m_name); /* Nope */ return (FALSE); } return (TRUE); } /* If we don't know the grid, allow attempts to walk into it */ if (!(cave_info[y][x] & CAVE_MARK)) return TRUE; /* Require open space or PASS_WALL/KILL_WALL flag -Simon */ if (!cave_floor_bold(y, x) && !(player_has(PF_PASS_WALL) || player_has(PF_KILL_WALL))) { /* Rubble */ if (cave_feat[y][x] == FEAT_RUBBLE) message(MSG_HITWALL, 0, "There is a pile of rubble in the way!"); /* Door */ else if (cave_feat[y][x] < FEAT_SECRET) return TRUE; /* Wall */ else message(MSG_HITWALL, 0, "There is a wall in the way!"); /* Cancel repeat */ disturb(0, 0); /* Nope */ return (FALSE); } /* Okay */ return (TRUE); }
/** * Wake a monster or reduce its depth of sleep * * Chance of waking up is dependent only on the player's stealth, but the * amount of sleep reduction takes into account the monster's distance from * the player. Currently straight line distance is used; possibly this * should take into account dungeon structure. */ static void monster_reduce_sleep(struct chunk *c, struct monster *mon) { bool woke_up = false; int stealth = player->state.skills[SKILL_STEALTH]; int player_noise = 1 << (30 - stealth); int notice = randint0(1024); struct monster_lore *lore = get_lore(mon->race); /* Aggravation */ if (player_of_has(player, OF_AGGRAVATE)) { char m_name[80]; /* Wake the monster */ mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false); /* Get the monster name */ monster_desc(m_name, sizeof(m_name), mon, MDESC_CAPITAL | MDESC_IND_HID); /* Notify the player if aware */ if (monster_is_obvious(mon)) msg("%s wakes up.", m_name); woke_up = true; } else if ((notice * notice * notice) <= player_noise) { int sleep_reduction = 1; int local_noise = c->noise.grids[mon->fy][mon->fx]; /* Test - wake up faster in hearing distance of the player * Note no dependence on stealth for now */ if ((local_noise > 0) && (local_noise < 50)) { sleep_reduction = (100 / local_noise); } /* Note a complete wakeup */ if (mon->m_timed[MON_TMD_SLEEP] <= sleep_reduction) { woke_up = true; } /* Monster wakes up a bit */ mon_dec_timed(mon, MON_TMD_SLEEP, sleep_reduction, MON_TMD_FLG_NOTIFY, false); /* Update knowledge */ if (monster_is_obvious(mon)) { if (!woke_up && lore->ignore < UCHAR_MAX) lore->ignore++; else if (woke_up && lore->wake < UCHAR_MAX) lore->wake++; lore_update(mon->race, lore); } } }
/** * Determine if a given grid may be "walked" */ static bool do_cmd_walk_test(int y, int x) { int m_idx = cave->squares[y][x].mon; struct monster *mon = cave_monster(cave, m_idx); /* Allow attack on visible monsters if unafraid */ if (m_idx > 0 && mflag_has(mon->mflag, MFLAG_VISIBLE) && !is_mimicking(mon)) { /* Handle player fear */ if (player_of_has(player, OF_AFRAID)) { /* Extract monster name (or "it") */ char m_name[80]; monster_desc(m_name, sizeof(m_name), mon, MDESC_DEFAULT); /* Message */ msgt(MSG_AFRAID, "You are too afraid to attack %s!", m_name); /* Nope */ return (false); } return (true); } /* If we don't know the grid, allow attempts to walk into it */ if (!square_isknown(cave, y, x)) return true; /* Require open space */ if (!square_ispassable(cave, y, x)) { if (square_isrubble(cave, y, x)) /* Rubble */ msgt(MSG_HITWALL, "There is a pile of rubble in the way!"); else if (square_iscloseddoor(cave, y, x)) /* Door */ return true; else if (square_isbright(cave, y, x)) /* Lava */ msgt(MSG_HITWALL, "The heat of the lava turns you away!"); else /* Wall */ msgt(MSG_HITWALL, "There is a wall in the way!"); /* Cancel repeat */ disturb(player, 0); /* Nope */ return (false); } /* Okay */ return (true); }
void talk_to_monster(s32b m_idx) { char m_name[100]; /* Extract monster name (or "it") */ monster_desc(m_name, get_monster(m_idx), 0); /* Process hook if there are any */ if (!process_hooks(HOOK_CHAT, "(d)", m_idx)) { msg_print("The monster does not want to chat."); } }
/** * Monster self-healing. * * \param m_ptr is the monster casting * \param rlev is its level * \param seen is whether @ can see it */ static void heal_self(struct monster *m_ptr, int rlev, bool seen) { char m_name[80], m_poss[80]; /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_STANDARD); /* Get the monster possessive ("his"/"her"/"its") */ monster_desc(m_poss, sizeof(m_poss), m_ptr, MDESC_PRO_VIS | MDESC_POSS); /* Heal some */ m_ptr->hp += (rlev * 6); /* Fully healed */ if (m_ptr->hp >= m_ptr->maxhp) { m_ptr->hp = m_ptr->maxhp; if (seen) msg("%s looks REALLY healthy!", m_name); else msg("%s sounds REALLY healthy!", m_name); } else if (seen) { /* Partially healed */ msg("%s looks healthier.", m_name); } else { msg("%s sounds healthier.", m_name); } /* Redraw (later) if needed */ if (p_ptr->health_who == m_ptr) p_ptr->redraw |= (PR_HEALTH); /* Cancel fear */ if (m_ptr->m_timed[MON_TMD_FEAR]) { mon_clear_timed(m_ptr, MON_TMD_FEAR, MON_TMD_FLG_NOMESSAGE, FALSE); msg("%s recovers %s courage.", m_name, m_poss); } }
/** * Drain mana from the player, healing the caster. * * \param m_idx is the monster casting * \param rlev is its level * \param seen is whether @ can see it */ static void drain_mana(int m_idx, int rlev, bool seen) { monster_type *m_ptr = cave_monster(cave, m_idx); int r1; char m_name[80]; /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0x00); if (!p_ptr->csp) { msg("The draining fails."); if (OPT(birth_ai_learn) && !(m_ptr->smart & SM_IMM_MANA)) { msg("%^s notes that you have no mana!", m_name); m_ptr->smart |= SM_IMM_MANA; } return; } /* Attack power */ r1 = (randint1(rlev) / 2) + 1; /* Full drain */ if (r1 >= p_ptr->csp) { r1 = p_ptr->csp; p_ptr->csp = 0; p_ptr->csp_frac = 0; } /* Partial drain */ else p_ptr->csp -= r1; /* Redraw mana */ p_ptr->redraw |= PR_MANA; /* Heal the monster */ if (m_ptr->hp < m_ptr->maxhp) { m_ptr->hp += (6 * r1); if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp; /* Redraw (later) if needed */ if (p_ptr->health_who == m_idx) p_ptr->redraw |= (PR_HEALTH); /* Special message */ if (seen) msg("%^s appears healthier.", m_name); } }
void fear_update_m(monster_type *m_ptr) { monster_race *r_ptr = &r_info[m_ptr->ap_r_idx]; if ((r_ptr->flags2 & RF2_AURA_FEAR) && m_ptr->ml && !is_pet(m_ptr) && !is_friendly(m_ptr)) { int r_level = _r_level(r_ptr); if (!fear_save_p(r_level)) { char m_name[80]; monster_desc(m_name, m_ptr, 0); msg_format("You behold the terrifying visage of %s!", m_name); mon_lore_2(m_ptr, RF2_AURA_FEAR); fear_add_p(r_level); } } }
/** * Try to push past / kill another monster. Returns true on success. */ static bool process_monster_try_push(struct chunk *c, struct monster *mon, const char *m_name, int nx, int ny) { struct monster *mon1 = square_monster(c, ny, nx); struct monster_lore *lore = get_lore(mon->race); /* Kill weaker monsters */ int kill_ok = rf_has(mon->race->flags, RF_KILL_BODY); /* Move weaker monsters if they can swap places */ /* (not in a wall) */ int move_ok = (rf_has(mon->race->flags, RF_MOVE_BODY) && square_ispassable(c, mon->fy, mon->fx)); if (compare_monsters(mon, mon1) > 0) { /* Learn about pushing and shoving */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { rf_on(lore->flags, RF_KILL_BODY); rf_on(lore->flags, RF_MOVE_BODY); } if (kill_ok || move_ok) { /* Get the names of the monsters involved */ char n_name[80]; monster_desc(n_name, sizeof(n_name), mon1, MDESC_IND_HID); /* Reveal mimics */ if (is_mimicking(mon1)) become_aware(mon1); /* Note if visible */ if (mflag_has(mon->mflag, MFLAG_VISIBLE) && mflag_has(mon->mflag, MFLAG_VIEW)) msg("%s %s %s.", m_name, kill_ok ? "tramples over" : "pushes past", n_name); /* Monster ate another monster */ if (kill_ok) delete_monster(ny, nx); monster_swap(mon->fy, mon->fx, ny, nx); return true; } } return false; }
/** * Adds to the message queue a message describing a monster's reaction * to damage. */ void message_pain(int m_idx, int dam) { long oldhp, newhp, tmp; int percentage; monster_type *m_ptr; int msg_code = MON_MSG_UNHARMED; char m_name[80]; assert(m_idx > 0); m_ptr = cave_monster(cave, m_idx); /* Get the monster name */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Notice non-damage */ if (dam == 0) { add_monster_message(m_name, m_idx, msg_code, FALSE); return; } /* Note -- subtle fix -CFT */ newhp = (long)(m_ptr->hp); oldhp = newhp + (long)(dam); tmp = (newhp * 100L) / oldhp; percentage = (int)(tmp); if (percentage > 95) msg_code = MON_MSG_95; else if (percentage > 75) msg_code = MON_MSG_75; else if (percentage > 50) msg_code = MON_MSG_50; else if (percentage > 35) msg_code = MON_MSG_35; else if (percentage > 20) msg_code = MON_MSG_20; else if (percentage > 10) msg_code = MON_MSG_10; else msg_code = MON_MSG_0; add_monster_message(m_name, m_idx, msg_code, FALSE); }
/** * Set target to closest monster. */ bool target_set_closest(int mode) { int y, x; struct monster *mon; char m_name[80]; struct point_set *targets; /* Cancel old target */ target_set_monster(0); /* Get ready to do targetting */ targets = target_get_monsters(mode); /* If nothing was prepared, then return */ if (point_set_size(targets) < 1) { msg("No Available Target."); point_set_dispose(targets); return false; } /* Find the first monster in the queue */ y = targets->pts[0].y; x = targets->pts[0].x; mon = square_monster(cave, y, x); /* Target the monster, if possible */ if (!target_able(mon)) { msg("No Available Target."); point_set_dispose(targets); return false; } /* Target the monster */ monster_desc(m_name, sizeof(m_name), mon, MDESC_CAPITAL); if (!(mode & TARGET_QUIET)) msg("%s is targeted.", m_name); /* Set up target information */ monster_race_track(player->upkeep, mon->race); health_track(player->upkeep, mon); target_set_monster(mon); point_set_dispose(targets); return true; }
/* * Anger the monster */ void anger_monster(monster_type *m_ptr) { if (p_ptr->inside_battle) return; if (is_friendly(m_ptr)) { char m_name[80]; monster_desc(m_name, m_ptr, 0); msg_format("%^s gets angry!", m_name); set_hostile(m_ptr); virtue_add(VIRTUE_INDIVIDUALISM, 1); virtue_add(VIRTUE_HONOUR, -1); virtue_add(VIRTUE_JUSTICE, -1); virtue_add(VIRTUE_COMPASSION, -1); } }
cptr duelist_current_challenge(void) { static char current_challenge[200]; /* paranoia ... this only seems to happen with wizard mode summoned monsters after a save and restore, so probably the wizard 'n' command is broken */ if (p_ptr->duelist_target_idx && !m_list[p_ptr->duelist_target_idx].r_idx) p_ptr->duelist_target_idx = 0; if (p_ptr->duelist_target_idx) { monster_desc(current_challenge, &m_list[p_ptr->duelist_target_idx], MD_ASSUME_VISIBLE); return current_challenge; } if (_equip_error()) return "Talents Disrupted"; return "No Current Challenge"; }
/* Player and monster swap places */ bool player_monster_swap(monster_type *m_ptr) { char m_name[80]; cave_type *c_ptr; if (!m_ptr) return FALSE; if (has_flag(m_ptr, FLAG_NO_PUSHBACK)) return FALSE; c_ptr = &cave[m_ptr->fy][m_ptr->fx]; m_ptr->csleep = 0; /* Extract monster name (or "it") */ monster_desc(m_name, m_ptr, 0); /* Auto-Recall if possible and visible */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx, m_ptr->ego); /* Track a new monster */ if (m_ptr->ml) health_track(c_ptr->m_idx); /* displace? */ if (cave_floor_bold(p_ptr->py, p_ptr->px) || monst_can_pass_square(m_ptr, p_ptr->py, p_ptr->px, NULL)) { msg_format("You push past %s.", m_name); m_ptr->fy = p_ptr->py; m_ptr->fx = p_ptr->px; cave[p_ptr->py][p_ptr->px].m_idx = c_ptr->m_idx; c_ptr->m_idx = 0; update_mon(cave[p_ptr->py][p_ptr->px].m_idx, TRUE); return TRUE; } else { msg_format("%^s is in your way!", m_name); energy_use = 0; return FALSE; } }
/** * Adds to the message queue a message describing a monster's reaction * to damage. */ void message_pain(struct monster *m_ptr, int dam) { long oldhp, newhp, tmp; int percentage; int msg_code = MON_MSG_UNHARMED; char m_name[80]; /* Get the monster name - don't use monster_desc flags because * add_monster_message does string processing on m_name */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_DEFAULT); /* Notice non-damage */ if (dam == 0) { add_monster_message(m_name, m_ptr, msg_code, FALSE); return; } /* Note -- subtle fix -CFT */ newhp = (long)(m_ptr->hp); oldhp = newhp + (long)(dam); tmp = (newhp * 100L) / oldhp; percentage = (int)(tmp); if (percentage > 95) msg_code = MON_MSG_95; else if (percentage > 75) msg_code = MON_MSG_75; else if (percentage > 50) msg_code = MON_MSG_50; else if (percentage > 35) msg_code = MON_MSG_35; else if (percentage > 20) msg_code = MON_MSG_20; else if (percentage > 10) msg_code = MON_MSG_10; else msg_code = MON_MSG_0; add_monster_message(m_name, m_ptr, msg_code, FALSE); }
/** * Process a monster spell * * \param index is the monster spell flag (RSF_FOO) * \param mon is the attacking monster * \param seen is whether the player can see the monster at this moment */ void do_mon_spell(int index, struct monster *mon, bool seen) { char m_name[80]; bool ident, hits = FALSE; /* Extract the monster level */ int rlev = ((mon->race->level >= 1) ? mon->race->level : 1); const struct monster_spell *spell = monster_spell_by_index(index); /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD); /* See if it hits */ if (spell->hit == 100) hits = TRUE; else if (spell->hit == 0) hits = FALSE; else hits = check_hit(player, spell->hit, rlev); /* Tell the player what's going on */ disturb(player, 1); spell_message(mon, spell, seen, hits); if (!hits) return; /* Try a saving throw if available */ if (spell->save_message && randint0(100) < player->state.skills[SKILL_SAVE]) { msg("%s", spell->save_message); return; } /* Do effects */ effect_do(spell->effect, NULL, &ident, TRUE, 0, 0, 0); return; }
/* * Turns a simple pet into a faithful companion */ void do_cmd_companion() { monster_type *m_ptr; s32b ii, jj; if (!can_create_companion()) { msg_print("You cannot get anymore companion."); return; } if (!tgt_pt(&ii, &jj)) { msg_print("You must target a pet."); return; } if (cave[jj][ii].m_idx) { char m_name[100]; m_ptr = get_monster(cave[jj][ii].m_idx); monster_desc(m_name, m_ptr, 0); if (m_ptr->faction == FACTION_PLAYER) { bool_flag(m_ptr, FLAG_PERMANENT); msg_format("%^s agrees to follow you.", m_name); } else { msg_format("%^s is not in your faction!", m_name); } } else msg_print("You must target a monster of your own faction."); }
/* * Examine a grid, return a keypress. * * The "mode" argument contains the "TARGET_LOOK" bit flag, which * indicates that the "space" key should scan through the contents * of the grid, instead of simply returning immediately. This lets * the "look" command get complete information, without making the * "target" command annoying. * * The "info" argument contains the "commands" which should be shown * inside the "[xxx]" text. This string must never be empty, or grids * containing monsters will be displayed with an extra comma. * * Note that if a monster is in the grid, we update both the monster * recall info and the health bar info to track that monster. * * This function correctly handles multiple objects per grid, and objects * and terrain features in the same grid, though the latter never happens. * * This function must handle blindness/hallucination. */ static ui_event_data target_set_interactive_aux(int y, int x, int mode, cptr info, bool list_floor_objects) { s16b this_o_idx, next_o_idx = 0; s16b this_x_idx, next_x_idx = 0; cptr s1, s2, s3; bool floored; u16b feat; ui_event_data query; char out_val[256]; char coords[20]; /* Describe the square location */ coords_desc(coords, sizeof(coords), y, x); /* Repeat forever */ while (1) { int i; char feat_name[80]; /* Terrain suffix for monsters and objects */ char terrain_suffix[200]; /* Temporary array of visible effects */ s16b x_seen[50]; u16b size_x_seen = 0; /* Paranoia */ query.key = ' '; /* Default */ s1 = "You see "; s2 = ""; s3 = "on "; /* The player */ if (cave_m_idx[y][x] < 0) { /* Description */ s1 = "You are "; /* Preposition */ s2 = "on "; } /* Feature (apply "mimic") */ feat = f_info[cave_feat[y][x]].f_mimic; /* Require knowledge about grid, or ability to see grid */ if (!(cave_info[y][x] & (CAVE_MARK)) && !player_can_see_bold(y,x)) { /* Forget feature */ feat = FEAT_NONE; } else { /* Hack -- track the current feature */ feature_kind_track(feat); /* Window stuff */ p_ptr->redraw |= (PR_FEATURE); } /* Pick a prefix */ if (*s2 && (!feat_ff1_match(feat, FF1_MOVE) || !feat_ff1_match(feat, FF1_LOS) || feat_ff1_match(feat, FF1_SHOP | FF1_DOOR) || feat_ff2_match(feat, FF2_SHALLOW | FF2_DEEP) || feat_ff3_match(feat, FF3_NEED_TREE))) { s3 = "in "; } /* Get a default name */ if (feat <= FEAT_NONE) { my_strcpy(feat_name, "an unknown grid", sizeof(feat_name)); } /* Get the real name */ else { feature_desc(feat_name, sizeof (feat_name), feat, TRUE, FALSE); } /* List all effects in the grid */ for (this_x_idx = cave_x_idx[y][x]; this_x_idx; this_x_idx = next_x_idx) { effect_type *x_ptr; /* Get the effect */ x_ptr = &x_list[this_x_idx]; /* Get the next effect */ next_x_idx = x_ptr->next_x_idx; /* Describe it, if not hidden */ if (!(x_ptr->x_flags & (EF1_HIDDEN)) && x_ptr->x_f_idx) { /* Check for available space */ if (size_x_seen < N_ELEMENTS(x_seen)) { x_seen[size_x_seen++] = x_ptr->x_f_idx; } } } /* Prepare the terrain suffix for monsters and objects */ my_strcpy(terrain_suffix, format(" %s%s", s3, feat_name), sizeof(terrain_suffix)); /* Concat the collected effect names */ for (i = 0; i < size_x_seen; i++) { char x_name[80]; /* Obtain an object description */ feature_desc(x_name, sizeof(x_name), x_seen[i], TRUE, TRUE); /* First effect */ if (i == 0) { if ((feat == FEAT_NONE) || !feat_ff1_match(feat, FF1_MOVE) || cave_any_trap_bold(y, x)) { /* Basic info */ my_strcat(terrain_suffix, format(" with %s", x_name), sizeof(terrain_suffix)); } else { /* Basic info */ my_strcat(terrain_suffix, format(" beneath %s", x_name), sizeof(terrain_suffix)); } } /* Basic info */ else if (i < (size_x_seen - 1)) { my_strcat(terrain_suffix, format(", %s", x_name), sizeof(terrain_suffix)); } /* Basic info */ else { my_strcat(terrain_suffix, format(" and %s", x_name), sizeof(terrain_suffix)); } } /* Ignore the terrain suffix if certain things happen */ if ((size_x_seen == 0) && (feat <= FEAT_FLOOR)) { terrain_suffix[0] = '\0'; } /* Hack -- hallucination */ if (p_ptr->timed[TMD_IMAGE]) { cptr name = "something strange"; /* Display a message */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s, [%s] %s (%d:%d).", s1, s2, name, info, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s [%s], %s.", s1, s2, name, info, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return" */ if ((query.key != '\n') && (query.key != '\r')) break; /* Repeat forever */ continue; } /* Actual monsters */ if (cave_m_idx[y][x] > 0) { monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; /* Visible */ if (m_ptr->ml) { bool recall = FALSE; char m_name[80]; if (m_ptr->mimic_k_idx) { /*get the description*/ mimic_desc_object(m_name, sizeof(m_name), m_ptr->mimic_k_idx); } else { /* Get the monster name ("a kobold") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0x08); /* Hack -- track this monster race */ monster_race_track(m_ptr->r_idx); /* Hack -- health bar for this monster */ health_track(cave_m_idx[y][x]); /*Track the feature*/ feature_kind_track(cave_feat[y][x]); /* Window stuff */ p_ptr->redraw |= (PR_FEATURE); /* Hack -- handle stuff */ handle_stuff(); } /* Interact */ while (1) { if (recall) button_add("[CLEAR_RECALL]", 'r'); else button_add("[RECALL]", 'r'); if (cave_o_idx[y][x] > 0)button_add("[VIEW_FLOOR]", 'f'); event_signal(EVENT_MOUSEBUTTONS); /* Recall, but not mimics */ if ((recall) && (!(m_ptr->mimic_k_idx))) { /* Save screen */ screen_save(); /* Recall on screen */ screen_roff(m_ptr->r_idx); /* Hack -- Complete the prompt (again) */ Term_addstr(-1, TERM_WHITE, format(" [r,%s]", info)); /* Command */ query = inkey_ex(); /* Load screen */ screen_load(); } /* Normal */ else { /* Basic info */ strnfmt(out_val, sizeof(out_val), "%s%s%s", s1, s2, m_name); /* Describe the monster, unless a mimic */ if (!(m_ptr->mimic_k_idx)) { char buf[80]; look_mon_desc(buf, sizeof(buf), cave_m_idx[y][x]); /* Monster state, terrain suffix, options */ my_strcat(out_val, format(" (%s)%s [r,%s]", buf, terrain_suffix, info), sizeof(out_val)); } /* Mimics */ else { /* Terrain suffix, options */ my_strcat(out_val, format("%s [I,%s]", terrain_suffix, info), sizeof(out_val)); } /* Wizards want coordinates */ if (p_ptr->wizard) { my_strcat(out_val, format(" (%d:%d)", y, x), sizeof(out_val)); } prt(out_val, 0, 0); /* Place cursor */ move_cursor_relative(y, x); /* Command */ query = inkey_ex(); } button_kill('r'); button_kill('f'); event_signal(EVENT_MOUSEBUTTONS); /* Handle fake object recall */ if (m_ptr->mimic_k_idx) { object_type body; object_type *o_ptr = &body; /* Validate input first */ if (query.key != 'I') break; /* Paranoia */ object_wipe(o_ptr); /* Prepare */ object_prep(o_ptr, m_ptr->mimic_k_idx); /* Fake history */ object_history(o_ptr, ORIGIN_FLOOR, 0); /* Clear prompt. Place cursor */ prt("", 0, 0); /* Show the fake info - EXPERIMENTAL */ object_info_screen(o_ptr); } /* Regular monsters */ else { /* Normal commands */ if (query.key != 'r') break; /* Toggle recall */ recall = !recall; } } /* Stop on everything but "return"/"space", or floor */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ') && (query.key != 'f')) break; /* continue with 'f' only if there are floor items....*/ if ((query.key == 'f') && (!cave_o_idx[y][x])) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s1 = "It is "; /* Hack -- take account of gender */ if (r_ptr->flags1 & (RF1_FEMALE)) s1 = "She is "; else if (r_ptr->flags1 & (RF1_MALE)) s1 = "He is "; /* Use a preposition */ s2 = "carrying "; /* Scan all objects being carried */ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) { char o_name[80]; object_type *o_ptr; /* Get the object */ o_ptr = &o_list[this_o_idx]; /* Get the next object */ next_o_idx = o_ptr->next_o_idx; /*Don't let the player see certain objects (used for vault treasure)*/ if ((o_ptr->ident & (IDENT_HIDE_CARRY)) && (!p_ptr->wizard) && (!cheat_peek)) continue; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ strnfmt(out_val, sizeof(out_val), "%s%s%s [%s]", s1, s2, o_name, info); /* Wizards want coordinates */ if (p_ptr->wizard) { my_strcat(out_val, format(" (%d:%d)", y, x), sizeof(out_val)); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s2 = "also carrying "; } /* Double break */ if (this_o_idx) break; /* Use a preposition */ s2 = "on "; } } /* Assume not floored */ floored = FALSE; /* Scan all objects in the grid */ if (TRUE) { int floor_list[MAX_FLOOR_STACK]; int floor_num; track_object(-floor_list[0]); handle_stuff(); /* Scan for floor objects */ floor_num = scan_floor(floor_list, MAX_FLOOR_STACK, y, x, 0x02); /* Actual pile */ if (floor_num > 1) { /* Floored */ floored = TRUE; /* Describe */ while (1) { /* Basic info */ strnfmt(out_val, sizeof(out_val), "%s%sa pile of %d objects%s [r,%s]", s1, s2, floor_num, terrain_suffix, info); /* Wizards want coordinates */ if (p_ptr->wizard) { my_strcat(out_val, format(" (%d:%d)", y, x), sizeof(out_val)); } prt(out_val, 0, 0); if (list_floor_objects) { /* Save screen */ screen_save(); /* Display */ show_floor(floor_list, floor_num, (OLIST_WEIGHT | OLIST_GOLD)); } move_cursor_relative(y, x); query = inkey_ex(); if (list_floor_objects) { screen_load(); } /* Display objects */ if (query.key == 'r') { int pos; pos = query.key - 'a'; if (0 <= pos && pos < floor_num) { track_object(-floor_list[pos]); handle_stuff(); } } /* Done */ break; } /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s1 = "It is "; /* Preposition */ s2 = "on "; } } /* Scan all objects in the grid */ for (this_o_idx = cave_o_idx[y][x]; this_o_idx; this_o_idx = next_o_idx) { object_type *o_ptr; /* Get the object */ o_ptr = &o_list[this_o_idx]; /* Get the next object */ next_o_idx = o_ptr->next_o_idx; /* Skip objects if floored */ if (floored) continue; /* Describe it */ if (o_ptr->marked) { char o_name[80]; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Basic info */ strnfmt(out_val, sizeof(out_val), "%s%s%s%s [I,%s]", s1, s2, o_name, terrain_suffix, info); /* Wizards want coordinates */ if (p_ptr->wizard) { my_strcat(out_val, format(" (%d:%d)", y, x), sizeof(out_val)); } /* Show object. Handle object recall */ while (TRUE) { /* Print the prompt */ prt(out_val, 0, 0); /* Move cursor to that location */ move_cursor_relative(y, x); /* Read input key */ query = inkey_ex(); /* No object recall */ if (query.key != 'I') break; /* Object recall. Clear the first line */ prt("", 0, 0); /* Do it */ object_info_screen(o_ptr); } /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s1 = "It is "; /* Plurals */ if (o_ptr->number != 1) s1 = "They are "; /* Preposition */ s2 = "on "; } } /* Double break */ if (this_o_idx) break; /* Display terrain */ if (TRUE) { u16b temp_feat; bool enable_recall; bool show_recall = FALSE; char temp_name[80]; /* * Display terrain and effects */ for (i = 0; i <= size_x_seen; i++) { /* Hack - This is the mark for the feature stored in cave_feat */ if (i == size_x_seen) { temp_feat = feat; /* Just copy the feature name */ my_strcpy(temp_name, feat_name, sizeof(temp_name)); } /* Any other value is an effect stored x_list */ else { temp_feat = x_seen[i]; /* Get the effect's name */ feature_desc(temp_name, sizeof(temp_name), temp_feat, TRUE, TRUE); } /* Don't display feature recall if the grid is unknown */ enable_recall = (temp_feat != FEAT_NONE); /* Handle recall */ while (TRUE) { /* Handle recall mode */ if (show_recall && enable_recall) { /* Save screen */ screen_save(); /* Recall feature on screen */ screen_feature_roff(temp_feat); } /* Display a message */ strnfmt(out_val, sizeof(out_val), "%s%s%s [%s%s]%s", s1, s2, temp_name, (enable_recall ? "r,": ""), info, (i < size_x_seen) ? " (more)": ""); /* Wizards want coordinates */ if (p_ptr->wizard) { my_strcat(out_val, format(" (%d:%d)", y, x), sizeof(out_val)); } /*Track this feature*/ feature_kind_track(temp_feat); /* Hack -- handle stuff */ handle_stuff(); prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Load screen if necessary */ if (show_recall && enable_recall) { screen_load(); } /* Stop on everything but the recall command, if enabled */ if (!enable_recall || (query.key != 'r')) break; /* Toggle recall */ show_recall = !show_recall; } /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; } } /* Hack -- handle stuff */ handle_stuff(); /* Stop on everything but "return" */ if ((query.key != '\n') && (query.key != '\r')) break; } /* Keep going */ return (query); }
/* * Examine a grid, return a keypress. * * The "mode" argument contains the "TARGET_LOOK" bit flag, which * indicates that the "space" key should scan through the contents * of the grid, instead of simply returning immediately. This lets * the "look" command get complete information, without making the * "target" command annoying. * * The "info" argument contains the "commands" which should be shown * inside the "[xxx]" text. This string must never be empty, or grids * containing monsters will be displayed with an extra comma. * * Note that if a monster is in the grid, we update both the monster * recall info and the health bar info to track that monster. * * This function correctly handles multiple objects per grid, and objects * and terrain features in the same grid, though the latter never happens. * * This function must handle blindness/hallucination. */ static ui_event_data target_set_interactive_aux(int y, int x, int mode) { s16b this_o_idx = 0, next_o_idx = 0; cptr s1, s2, s3; bool boring; bool floored; int feat; int floor_list[MAX_FLOOR_STACK]; int floor_num; ui_event_data query; char out_val[256]; char coords[20]; /* Describe the square location */ coords_desc(coords, sizeof(coords), y, x); /* Repeat forever */ while (1) { /* Paranoia */ query.key = ' '; /* Assume boring */ boring = TRUE; /* Default */ s1 = "You see "; s2 = ""; s3 = ""; /* The player */ if (cave_m_idx[y][x] < 0) { /* Description */ s1 = "You are "; /* Preposition */ s2 = "on "; } /* Hack -- hallucination */ if (p_ptr->timed[TMD_IMAGE]) { cptr name = "something strange"; /* Display a message */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return" */ if ((query.key != '\n') && (query.key != '\r')) break; /* Repeat forever */ continue; } /* Actual monsters */ if (cave_m_idx[y][x] > 0) { monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; /* Visible */ if (m_ptr->ml) { bool recall = FALSE; char m_name[80]; /* Not boring */ boring = FALSE; /* Get the monster name ("a kobold") */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND2); /* Hack -- track this monster race */ monster_race_track(m_ptr->r_idx); /* Hack -- health bar for this monster */ health_track(cave_m_idx[y][x]); /* Hack -- handle stuff */ handle_stuff(); /* Interact */ while (1) { /* Recall */ if (recall) { /* Save screen */ screen_save(); /* Recall on screen */ screen_roff(m_ptr->r_idx); /* Command */ query = inkey_ex(); /* Load screen */ screen_load(); } /* Normal */ else { char buf[80]; /* Describe the monster */ look_mon_desc(buf, sizeof(buf), cave_m_idx[y][x]); /* Describe, and prompt for recall */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s (%d:%d).", s1, s2, s3, m_name, buf, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s.", s1, s2, s3, m_name, buf, coords); } prt(out_val, 0, 0); /* Place cursor */ move_cursor_relative(y, x); /* Command */ query = inkey_ex(); } /* Normal commands */ if (query.key != 'r') break; /* Toggle recall */ recall = !recall; } /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s1 = "It is "; /* Hack -- take account of gender */ if (rf_has(r_ptr->flags, RF_FEMALE)) s1 = "She is "; else if (rf_has(r_ptr->flags, RF_MALE)) s1 = "He is "; /* Use a preposition */ s2 = "carrying "; /* Scan all objects being carried */ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) { char o_name[80]; object_type *o_ptr; /* Get the object */ o_ptr = &o_list[this_o_idx]; /* Get the next object */ next_o_idx = o_ptr->next_o_idx; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, o_name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, o_name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s2 = "also carrying "; } /* Double break */ if (this_o_idx) break; /* Use a preposition */ s2 = "on "; } } /* Assume not floored */ floored = FALSE; floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), y, x, 0x02); /* Scan all marked objects in the grid */ if ((floor_num > 0) && (!(p_ptr->timed[TMD_BLIND]) || (y == p_ptr->py && x == p_ptr->px))) { /* Not boring */ boring = FALSE; track_object(-floor_list[0]); handle_stuff(); /* If there is more than one item... */ if (floor_num > 1) while (1) { floored = TRUE; /* Describe the pile */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s (%d:%d).", s1, s2, s3, floor_num, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s.", s1, s2, s3, floor_num, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Display objects */ if (query.key == 'r') { int rdone = 0; int pos; while (!rdone) { /* Save screen */ screen_save(); /* Display */ show_floor(floor_list, floor_num, (OLIST_WEIGHT | OLIST_GOLD)); /* Describe the pile */ prt(out_val, 0, 0); query = inkey_ex(); /* Load screen */ screen_load(); pos = query.key - 'a'; if (0 <= pos && pos < floor_num) { track_object(-floor_list[pos]); handle_stuff(); continue; } rdone = 1; } /* Now that the user's done with the display loop, let's */ /* the outer loop over again */ continue; } /* Done */ break; } /* Only one object to display */ else { char o_name[80]; /* Get the single object in the list */ object_type *o_ptr = &o_list[floor_list[0]]; /* Not boring */ boring = FALSE; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, o_name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, o_name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s1 = "It is "; /* Plurals */ if (o_ptr->number != 1) s1 = "They are "; /* Preposition */ s2 = "on "; } } /* Double break */ if (this_o_idx) break; /* Feature (apply "mimic") */ feat = f_info[cave_feat[y][x]].mimic; /* Require knowledge about grid, or ability to see grid */ if (!(cave_info[y][x] & (CAVE_MARK)) && !player_can_see_bold(y,x)) { /* Forget feature */ feat = FEAT_NONE; } /* Terrain feature if needed */ if (boring || (feat > FEAT_INVIS)) { cptr name = f_info[feat].name; /* Hack -- handle unknown grids */ if (feat == FEAT_NONE) name = "unknown grid"; /* Pick a prefix */ if (*s2 && (feat >= FEAT_DOOR_HEAD)) s2 = "in "; /* Pick proper indefinite article */ s3 = (is_a_vowel(name[0])) ? "an " : "a "; /* Hack -- special introduction for store doors */ if ((feat >= FEAT_SHOP_HEAD) && (feat <= FEAT_SHOP_TAIL)) { s3 = "the entrance to the "; } /* Display a message */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; } /* Stop on everything but "return" */ if ((query.key != '\n') && (query.key != '\r')) break; } /* Keep going */ return (query); }