/* * Monster health description. * This function should not be called without a check that the monster is a mimic */ static void look_mon_desc(char *buf, size_t max, int m_idx) { monster_type *m_ptr = &mon_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; bool living = TRUE; /*monster is an undiscovered mimic, don't desccribe and return*/ if (m_ptr->mimic_k_idx) { /*Paranoia - terminate the string*/ buf[0] = '\0'; return; } /* Determine if the monster is "living" (vs "undead") */ if (monster_nonliving(r_ptr)) living = FALSE; /* Healthy monsters */ if (m_ptr->hp >= m_ptr->maxhp) { /* No damage */ my_strcpy(buf, (living ? "unhurt" : "undamaged"), max); } else { /* Calculate a health "percentage" */ int perc = 100L * m_ptr->hp / m_ptr->maxhp; if (perc >= 60) my_strcpy(buf, (living ? "somewhat wounded" : "somewhat damaged"), max); else if (perc >= 25) my_strcpy(buf, (living ? "wounded" : "damaged"), max); else if (perc >= 10) my_strcpy(buf, (living ? "badly wounded" : "badly damaged"), max); else my_strcpy(buf, (living ? "almost dead" : "almost destroyed"), max); } if (m_ptr->mflag & (MFLAG_TOWN)) my_strcat(buf, ", town", sizeof(buf)); if (m_ptr->mflag & (MFLAG_STERILE)) my_strcat(buf, ", sterile", sizeof(buf)); if (m_ptr->mflag & (MFLAG_WARY)) my_strcat(buf, ", wary", sizeof(buf)); if (m_ptr->mflag & (MFLAG_FLYING)) my_strcat(buf, ", flying", sizeof(buf)); if (m_ptr->m_timed[MON_TMD_SLEEP]) my_strcat(buf, ", asleep", max); if (m_ptr->m_timed[MON_TMD_CONF]) my_strcat(buf, ", confused", max); if (m_ptr->m_timed[MON_TMD_FEAR]) my_strcat(buf, ", afraid", max); if (m_ptr->m_timed[MON_TMD_STUN]) my_strcat(buf, ", stunned", max); if ((m_ptr->m_timed[MON_TMD_SLOW]) && (!m_ptr->m_timed[MON_TMD_FAST])) my_strcat(buf, ", slowed", max); if ((!m_ptr->m_timed[MON_TMD_SLOW]) && (m_ptr->m_timed[MON_TMD_FAST])) my_strcat(buf, ", hasted", max); }
/* * Handle the "death" of a monster. * * Disperse treasures centered at the monster location based on the * various flags contained in the monster flags fields. * * Check for "Quest" completion when a quest monster is killed. * * Note that only the player can induce "monster_death()" on Uniques or quest monsters. * * Note that monsters can now carry objects, and when a monster dies, * it drops all of its objects, which may disappear in crowded rooms. */ void monster_death(int m_idx, int who) { int i; int total = 0; bool questlevel = FALSE; bool completed = FALSE; bool fixedquest = FALSE; bool writenote = TRUE; monster_type *m_ptr = &mon_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; /* Drop any objects the monster is carrying */ if (m_ptr->hold_o_idx) { mon_drop_held_objects(m_ptr); } /* Mega-Hack -- drop "winner" treasures */ if (r_ptr->flags1 & (RF1_DROP_CHOSEN)) { mon_drop_chosen_objects(m_ptr); } /* Drop the monster's standard loot */ mon_drop_loot(m_idx); /* Update monster list window */ p_ptr->redraw |= (PR_MONLIST); /* Count incomplete quests */ for (i = 0; i < z_info->q_max; i++) { quest_type *q_ptr = &q_info[i]; /* * Hack - don't count if player didn't kill, or on a town level * This assumes only a player can kill quest monsters!!!!! */ if (((who != SOURCE_PLAYER) && (who != SOURCE_TRAP)) || (!p_ptr->depth)) continue; /* Quest level? */ if ((q_ptr->base_level == p_ptr->depth) && !is_quest_complete(i)) { /* We are on a quest level */ questlevel = TRUE; /* Mark fixed quests */ if (quest_fixed(q_ptr)) fixedquest = TRUE; process_quest_monster_death(i, m_idx, &writenote); /* We just completed the quest */ if (q_ptr->q_flags & (QFLAG_COMPLETED)) { completed = TRUE; } } /* Count remaining permanent quests */ if (quest_fixed(q_ptr)) { if (!is_quest_complete(i)) total++; } } /* If the player kills a Unique, and the notes option is on, write a note. * If the unique is a guild questor, the note was already written */ if ((r_ptr->flags1 & (RF1_UNIQUE)) && (adult_take_notes) && (writenote)) { char note2[120]; char real_name[120]; /*write note for player ghosts*/ if (r_ptr->flags2 & (RF2_PLAYER_GHOST)) { /*paranoia*/ /* Check there is a name/ghost first */ if (player_ghost_name[0] == '\0') { /*Make sure the name has been created*/ prepare_ghost_name(); } my_strcpy(note2, format("Destroyed %^s", player_ghost_name), sizeof (note2)); } /*All other uniques*/ else { /* Get the monster's real name for the notes file */ monster_desc_race(real_name, sizeof(real_name), m_ptr->r_idx); /* Write note */ if monster_nonliving(r_ptr) my_strcpy(note2, format("Destroyed %s", real_name), sizeof (note2)); else my_strcpy(note2, format("Killed %s", real_name), sizeof (note2)); }
/* * Handle the "death" of a monster. * * Disperse treasures centered at the monster location based on the * various flags contained in the monster flags fields. * * Check for "Quest" completion when a quest monster is killed. * * Note that only the player can induce "monster_death()" on Uniques or quest monsters. * * Note that monsters can now carry objects, and when a monster dies, * it drops all of its objects, which may disappear in crowded rooms. */ void monster_death(int m_idx, int who) { int i, j, y, x; int dump_item = 0; int dump_gold = 0; int number_drops = 0; int total = 0; bool questlevel = FALSE; bool completed = FALSE; bool fixedquest = FALSE; bool writenote = TRUE; bool need_stairs = FALSE; s16b set_object_level; s16b this_o_idx, next_o_idx = 0; monster_type *m_ptr = &mon_list[m_idx]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; bool visible = (m_ptr->ml || (r_ptr->flags1 & (RF1_UNIQUE))); bool chest = (r_ptr->flags1 & (RF1_DROP_CHEST)) ? TRUE : FALSE; bool good = (r_ptr->flags1 & (RF1_DROP_GOOD)) ? TRUE : FALSE; bool great = (r_ptr->flags1 & (RF1_DROP_GREAT)) ? TRUE : FALSE; bool do_gold = (!(r_ptr->flags1 & (RF1_ONLY_ITEM))); bool do_item = (!(r_ptr->flags1 & (RF1_ONLY_GOLD))); int force_coin = get_coin_type(r_ptr); object_type *i_ptr; object_type object_type_body; /* Get the location */ y = m_ptr->fy; x = m_ptr->fx; /* Drop objects being carried */ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) { object_type *o_ptr; /* Get the object */ o_ptr = &o_list[this_o_idx]; /*Remove the mark to hide when monsters carry this object*/ o_ptr->ident &= ~(IDENT_HIDE_CARRY); /* Get the next object */ next_o_idx = o_ptr->next_o_idx; /* Paranoia */ o_ptr->held_m_idx = 0; /* Get local object */ i_ptr = &object_type_body; /* Copy the object */ object_copy(i_ptr, o_ptr); /* Delete the object */ delete_object_idx(this_o_idx); /* Drop it */ drop_near(i_ptr, -1, y, x); } /* Forget objects */ m_ptr->hold_o_idx = 0; /* Mega-Hack -- drop "winner" treasures */ if (r_ptr->flags1 & (RF1_DROP_CHOSEN)) { /* Get local object */ i_ptr = &object_type_body; /* Mega-Hack -- Prepare to make "Grond" */ object_prep(i_ptr, lookup_kind(TV_HAFTED, SV_GROND)); /* Mega-Hack -- Mark this item as "Grond" */ i_ptr->art_num = ART_GROND; /* Mega-Hack -- Actually create "Grond" */ apply_magic(i_ptr, -1, TRUE, TRUE, TRUE, FALSE); /* Remember history */ object_history(i_ptr, ORIGIN_MORGOTH, 0); /* Drop it in the dungeon */ drop_near(i_ptr, -1, y, x); /* Get local object */ i_ptr = &object_type_body; /* Mega-Hack -- Prepare to make "Morgoth's crown" */ object_prep(i_ptr, lookup_kind(TV_CROWN, SV_MORGOTH)); /* Mega-Hack -- Mark this item as "Morgoth" */ i_ptr->art_num = ART_MORGOTH; /* Mega-Hack -- Actually create "Morgoth" */ apply_magic(i_ptr, -1, TRUE, TRUE, TRUE, FALSE); /* Remember history */ object_history(i_ptr, ORIGIN_MORGOTH, 0); /* Drop it in the dungeon */ drop_near(i_ptr, -1, y, x); } /* Determine how much we can drop */ if ((r_ptr->flags1 & (RF1_DROP_60)) && (rand_int(100) < 60)) number_drops++; if ((r_ptr->flags1 & (RF1_DROP_90)) && (rand_int(100) < 90)) number_drops++; if (r_ptr->flags1 & (RF1_DROP_1D2)) number_drops += damroll(1, 2); if (r_ptr->flags1 & (RF1_DROP_2D2)) number_drops += damroll(2, 2); if (r_ptr->flags1 & (RF1_DROP_3D2)) number_drops += damroll(3, 2); if (r_ptr->flags1 & (RF1_DROP_4D2)) number_drops += damroll(4, 2); /* Hack -- handle creeping coins */ coin_type = force_coin; /* Average dungeon and monster levels */ set_object_level = object_level = (effective_depth(p_ptr->depth) + r_ptr->level) / 2; /* Drop some objects */ for (j = 0; j < number_drops; j++) { bool interesting = FALSE; /* Re-set the object level */ object_level = set_object_level; /* Get local object */ i_ptr = &object_type_body; /* Wipe the object */ object_wipe(i_ptr); /* work on the "too much junk" problem, large drops sometimes are less items with a "boost". */ if ((randint(750) < (number_drops * number_drops)) && (!(r_ptr->flags1 & (RF1_UNIQUE)))) { interesting = TRUE; number_drops -= 5; object_level += 5; /*Boundry Control*/ if (number_drops < 0) number_drops = 0; if (object_level > MAX_DEPTH) object_level = MAX_DEPTH; } /* Make Gold */ if (do_gold && (!chest) && (!do_item || (rand_int(100) < 70))) { /* Make some gold */ if (!make_gold(i_ptr)) continue; /* Assume seen XXX XXX XXX */ dump_gold++; } /* Make Object */ else { if (chest) { if (!make_object(i_ptr, good, great, DROP_TYPE_CHEST, FALSE)) continue; } /* Make an object */ else if (!make_object(i_ptr, good, great, DROP_TYPE_UNTHEMED, interesting)) continue; /* Remember history */ if (visible) object_history(i_ptr, ORIGIN_DROP_KNOWN, m_ptr->r_idx); else object_history(i_ptr, ORIGIN_DROP_UNKNOWN, 0); /* Assume seen XXX XXX XXX */ dump_item++; } /* Drop it in the dungeon */ drop_near(i_ptr, -1, y, x); } /* Re-set the object level */ object_level = set_object_level; /*If marked for a bonus item, create it and drop it */ if (m_ptr->mflag & (MFLAG_BONUS_ITEM)) { bool this_good = good; bool this_great = great; bool this_chest = chest; bool interesting = FALSE; char o_name[80]; /* Get local object */ i_ptr = &object_type_body; /* Wipe the object */ object_wipe(i_ptr); if (one_in_(50)) this_chest = TRUE; if (one_in_(15)) this_great = TRUE; if (one_in_(5)) this_good = TRUE; if ((!this_good) && (!this_great) && (!this_chest)) { object_level += 5; if (object_level > MAX_DEPTH) object_level = MAX_DEPTH; interesting = TRUE; } if (this_chest) { while (!make_object(i_ptr, TRUE, TRUE, DROP_TYPE_CHEST, FALSE)) continue; } /* Make an object */ else while (!make_object(i_ptr, this_good, this_good, DROP_TYPE_UNTHEMED, interesting)) continue; /* Remember history */ if (visible) object_history(i_ptr, ORIGIN_DROP_KNOWN, m_ptr->r_idx); else object_history(i_ptr, ORIGIN_DROP_UNKNOWN, 0); object_desc(o_name, sizeof(o_name), i_ptr, ODESC_PREFIX | ODESC_FULL); /* Drop it in the dungeon */ drop_near(i_ptr, -1, y, x); } /* Reset the object level */ object_level = effective_depth(p_ptr->depth); /* Reset "coin" type */ coin_type = 0; /* Take note of any dropped treasure */ if (visible && (dump_item || dump_gold)) { /* Take notes on treasure */ lore_treasure(m_idx, dump_item, dump_gold); } /* Update monster list window */ p_ptr->redraw |= (PR_MONLIST); /* Count incomplete quests */ for (i = 0; i < z_info->q_max; i++) { quest_type *q_ptr = &q_info[i]; /* * Hack - don't count if player didn't kill, or on a town level * This assumes only a player can kill quest monsters!!!!! * This line is also ugly coding. :) */ if (((who != SOURCE_PLAYER) && (who != SOURCE_TRAP)) || (!p_ptr->depth)) continue; /* Quest level? */ if ((q_ptr->active_level == p_ptr->depth) && (p_ptr->depth > 0)) { /* One on the level */ questlevel = TRUE; /* Require "Quest Monsters" */ if (q_ptr->mon_idx == m_ptr->r_idx) { char race_name[80]; /* Get the monster race name (singular)*/ monster_desc_race(race_name, sizeof(race_name), q_ptr->mon_idx); /* Mark kills */ q_ptr->cur_num++; /* Redraw quest indicator */ p_ptr->redraw |= (PR_QUEST_ST); /* Completed quest? */ if (q_ptr->cur_num == q_ptr->max_num) { /* Mark complete */ q_ptr->active_level = 0; /* Mark fixed quests */ if ((q_ptr->q_type == QUEST_FIXED) || (q_ptr->q_type == QUEST_FIXED_U)) fixedquest = TRUE; if (q_ptr->q_type == QUEST_GUARDIAN) need_stairs = TRUE; /* One complete */ completed = TRUE; /*make a note of the completed quest, but not for fixed or * fixed unique quests */ if ((adult_take_notes) && (!fixedquest)) { char note[120]; /* Multiple quest monsters */ if (q_ptr->max_num > 1) { plural_aux(race_name, sizeof(race_name)); } if (r_ptr->flags1 & (RF1_UNIQUE)) { /*write note*/ if monster_nonliving(r_ptr) sprintf(note, "Quest: Destroyed %s", race_name); else sprintf(note, "Quest: Killed %s", race_name); } else { /* Write note */ if monster_nonliving(r_ptr)