static size_t obj_desc_inscrip(const object_type *o_ptr, char *buf, size_t max, size_t end) { const char *u[4] = { 0, 0, 0, 0 }; int n = 0; int feel = object_pseudo(o_ptr); bitflag flags_known[OF_SIZE]; object_flags_known(o_ptr, flags_known); /* Get inscription */ if (o_ptr->note) u[n++] = quark_str(o_ptr->note); /* Use special inscription, if any */ if (!object_is_known(o_ptr) && feel) { /* cannot tell excellent vs strange vs splendid until wield */ if (!object_was_worn(o_ptr) && ego_item_p(o_ptr)) u[n++] = "ego"; else u[n++] = inscrip_text[feel]; } else if ((o_ptr->ident & IDENT_EMPTY) && !object_is_known(o_ptr)) u[n++] = "empty"; else if (!object_is_known(o_ptr) && object_was_worn(o_ptr)) { if (wield_slot(o_ptr) == INVEN_WIELD || wield_slot(o_ptr) == INVEN_BOW) u[n++] = "wielded"; else u[n++] = "worn"; } else if (!object_is_known(o_ptr) && object_was_fired(o_ptr)) u[n++] = "fired"; else if (!object_flavor_is_aware(o_ptr) && object_flavor_was_tried(o_ptr)) u[n++] = "tried"; /* Note curses */ if (flags_test(flags_known, OF_SIZE, OF_CURSE_MASK, FLAG_END)) u[n++] = "cursed"; /* Note squelch */ if (squelch_item_ok(o_ptr)) u[n++] = "squelch"; if (n) { int i; for (i = 0; i < n; i++) { if (i == 0) strnfcat(buf, max, &end, " {"); strnfcat(buf, max, &end, "%s", u[i]); if (i < n-1) strnfcat(buf, max, &end, ", "); } strnfcat(buf, max, &end, "}"); } return end; }
/** * Extract the multiplier from a given object hitting a given monster. * * \param o_ptr is the object being used to attack * \param m_ptr is the monster being attacked * \param best_s_ptr is the best applicable slay_table entry, or NULL if no * slay already known * \param real is whether this is a real attack (where we update lore) or a * simulation (where we don't) * \param known_only is whether we are using all the object flags, or only * the ones we *already* know about */ void improve_attack_modifier(object_type *o_ptr, const monster_type *m_ptr, const struct slay **best_s_ptr, bool real, bool known_only) { monster_race *r_ptr = &r_info[m_ptr->r_idx]; monster_lore *l_ptr = &l_list[m_ptr->r_idx]; bitflag f[OF_SIZE], known_f[OF_SIZE], note_f[OF_SIZE]; int i; object_flags(o_ptr, f); object_flags_known(o_ptr, known_f); for (i = 0; i < SL_MAX; i++) { const struct slay *s_ptr = &slay_table[i]; if ((known_only && !of_has(known_f, s_ptr->object_flag)) || (!known_only && !of_has(f, s_ptr->object_flag))) continue; /* Disallow forbidden off-weapon slays/brands */ if (wield_slot(o_ptr) > INVEN_BOW && wield_slot(o_ptr) < INVEN_TOTAL && !s_ptr->nonweap) continue; /* In a real attack, learn about monster resistance or slay match if: * EITHER the slay flag on the object is known, * OR the monster is vulnerable to the slay/brand */ if (real && (of_has(known_f, s_ptr->object_flag) || (s_ptr->monster_flag && rf_has(r_ptr->flags, s_ptr->monster_flag)) || (s_ptr->resist_flag && !rf_has(r_ptr->flags, s_ptr->resist_flag)) || (s_ptr->vuln_flag && rf_has(r_ptr->flags, s_ptr->vuln_flag)))) { /* notice any brand or slay that would affect monster */ of_wipe(note_f); of_on(note_f, s_ptr->object_flag); object_notice_slays(o_ptr, note_f); if (m_ptr->ml && s_ptr->monster_flag) rf_on(l_ptr->flags, s_ptr->monster_flag); if (m_ptr->ml && s_ptr->resist_flag) rf_on(l_ptr->flags, s_ptr->resist_flag); if (m_ptr->ml && s_ptr->vuln_flag) rf_on(l_ptr->flags, s_ptr->vuln_flag); } /* If the monster doesn't resist or the slay flag matches */ if ((s_ptr->brand && !rf_has(r_ptr->flags, s_ptr->resist_flag)) || (s_ptr->monster_flag && rf_has(r_ptr->flags, s_ptr->monster_flag)) || (s_ptr->vuln_flag && rf_has(r_ptr->flags, s_ptr->vuln_flag))) { /* compare multipliers to determine best attack */ if ((*best_s_ptr == NULL) || ((*best_s_ptr)->mult < s_ptr->mult)) *best_s_ptr = s_ptr; } } }
static size_t obj_desc_combat(const object_type *o_ptr, char *buf, size_t max, size_t end, bool spoil) { bitflag flags[OF_SIZE]; bitflag flags_known[OF_SIZE]; object_flags(o_ptr, flags); object_flags_known(o_ptr, flags_known); if (of_has(flags, OF_SHOW_DICE)) { /* Only display the real damage dice if the combat stats are known */ if (spoil || object_attack_plusses_are_visible(o_ptr)) strnfcat(buf, max, &end, " (%dd%d)", o_ptr->dd, o_ptr->ds); else strnfcat(buf, max, &end, " (%dd%d)", o_ptr->kind->dd, o_ptr->kind->ds); } if (of_has(flags, OF_SHOW_MULT)) { /* Display shooting power as part of the multiplier */ if (of_has(flags, OF_MIGHT) && (spoil || object_flag_is_known(o_ptr, OF_MIGHT))) strnfcat(buf, max, &end, " (x%d)", (o_ptr->sval % 10) + o_ptr->pval[which_pval(o_ptr, OF_MIGHT)]); else strnfcat(buf, max, &end, " (x%d)", o_ptr->sval % 10); } /* Show weapon bonuses */ if (spoil || object_attack_plusses_are_visible(o_ptr)) { if (wield_slot(o_ptr) == INVEN_WIELD || wield_slot(o_ptr) == INVEN_BOW || obj_is_ammo(o_ptr) || o_ptr->to_d || o_ptr->to_h) { /* Make an exception for body armor with only a to-hit penalty */ if (o_ptr->to_h < 0 && o_ptr->to_d == 0 && (o_ptr->tval == TV_SOFT_ARMOR || o_ptr->tval == TV_HARD_ARMOR || o_ptr->tval == TV_DRAG_ARMOR)) strnfcat(buf, max, &end, " (%+d)", o_ptr->to_h); /* Otherwise, always use the full tuple */ else strnfcat(buf, max, &end, " (%+d,%+d)", o_ptr->to_h, o_ptr->to_d); } } /* Show armor bonuses */ if (spoil || object_defence_plusses_are_visible(o_ptr)) { if (obj_desc_show_armor(o_ptr)) strnfcat(buf, max, &end, " [%d,%+d]", o_ptr->ac, o_ptr->to_a); else if (o_ptr->to_a) strnfcat(buf, max, &end, " [%+d]", o_ptr->to_a); } else if (obj_desc_show_armor(o_ptr)) strnfcat(buf, max, &end, " [%d]", object_was_sensed(o_ptr) ? o_ptr->ac : o_ptr->kind->ac); return end; }
void object_notice_attack_plusses(object_type *o_ptr) { if (!o_ptr->k_idx) return; if (object_attack_plusses_are_visible(o_ptr)) return; if (object_add_ident_flags(o_ptr, IDENT_ATTACK)) object_check_for_ident(o_ptr); if (wield_slot(o_ptr) == INVEN_WIELD) { char o_name[80]; object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE); message_format(MSG_PSEUDOID, 0, "You know more about the %s you are using.", o_name); } else if ((o_ptr->to_d || o_ptr->to_h) && !((o_ptr->tval == TV_HARD_ARMOR || o_ptr->tval == TV_SOFT_ARMOR) && (o_ptr->to_h < 0))) { char o_name[80]; object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE); message_format(MSG_PSEUDOID, 0, "Your %s glows.", o_name); } p_ptr->update |= (PU_BONUS); event_signal(EVENT_INVENTORY); event_signal(EVENT_EQUIPMENT); }
/** * Determine if all the properties of a wieldable item are known, * but it's not formally identified */ bool known_really(object_type * o_ptr) { bitflag otherflags[IF_SIZE]; bool needs_to_be_worn = has_bonuses(o_ptr); flags_other(o_ptr, otherflags); /* Any ego-item type must be known */ if (o_ptr->name2) if (!(e_info[o_ptr->name2].everseen)) return FALSE; /* Object flags must be known */ if (!of_is_subset(o_ptr->id_obj, o_ptr->flags_obj)) return FALSE; /* Other flags must be known */ if (!if_is_subset(o_ptr->id_other, otherflags)) return FALSE; /* Objects with bonuses need to be worn to see the bonuses */ if (needs_to_be_worn && (!(o_ptr->ident & IDENT_WORN))) return FALSE; /* No need to identify if it already has been */ if (o_ptr->ident & IDENT_KNOWN) return FALSE; /* Has to be wieldable */ if (wield_slot(o_ptr) < 0) return FALSE; /* Must be OK */ return TRUE; }
/** * Add power for modifiers */ static int modifier_power(const object_type *obj, int p, bool known) { int i, k = 1, extra_stat_bonus = 0, q; for (i = 0; i < OBJ_MOD_MAX; i++) { if (known || object_this_mod_is_visible(obj, i)) { k = obj->modifiers[i]; extra_stat_bonus += (k * mod_mult(i)); } else continue; if (mod_power(i)) { q = (k * mod_power(i) * mod_slot_mult(i, wield_slot(obj))); p += q; if (q) log_obj(format("Add %d power for %d %s, total is %d\n", q, k, mod_name(i), p)); } } /* Add extra power term if there are a lot of ability bonuses */ if (extra_stat_bonus > 249) { log_obj(format("Inhibiting - Total ability bonus of %d is too high\n", extra_stat_bonus)); p += INHIBIT_POWER; } else if (extra_stat_bonus > 0) { q = ability_power[extra_stat_bonus / 10]; if (!q) return p; p += q; log_obj(format("Add %d power for modifier total of %d, total is %d\n", q, extra_stat_bonus, p)); } return p; }
/** * Returns information about objects that can be used for digging. * * `deciturns` will be filled in with the avg number of deciturns it will * take to dig through each type of diggable terrain, and must be at least * [DIGGING_MAX]. * * Returns FALSE if the object has no effect on digging, or if the specifics * are meaningless (i.e. the object is an ego template, not a real item). */ static bool obj_known_digging(struct object *obj, int deciturns[]) { player_state state; int i; int chances[DIGGING_MAX]; int slot = wield_slot(obj); struct object *current = slot_object(player, slot); if (!tval_is_wearable(obj) || (!tval_is_melee_weapon(obj) && (obj->modifiers[OBJ_MOD_TUNNEL] <= 0))) return FALSE; /* Pretend we're wielding the object */ player->body.slots[slot].obj = obj; /* Calculate the player's hypothetical state */ calc_bonuses(player->gear, &state, TRUE); /* Stop pretending */ player->body.slots[slot].obj = current; calc_digging_chances(&state, chances); /* Digging chance is out of 1600 */ for (i = DIGGING_RUBBLE; i < DIGGING_MAX; i++) { int chance = MIN(1600, chances[i]); deciturns[i] = chance ? (16000 / chance) : 0; } return TRUE; }
void textui_obj_wield(object_type *o_ptr, int item) { int slot = wield_slot(o_ptr); /* Usually if the slot is taken we'll just replace the item in the slot, * but in some cases we need to ask the user which slot they actually * want to replace */ if (p_ptr->inventory[slot].k_idx) { if (o_ptr->tval == TV_RING) { cptr q = "Replace which ring? "; cptr s = "Error in obj_wield, please report"; item_tester_hook = obj_is_ring; if (!get_item(&slot, q, s, CMD_WIELD, USE_EQUIP)) return; } if (obj_is_ammo(o_ptr) && !object_similar(&p_ptr->inventory[slot], o_ptr, OSTACK_QUIVER)) { cptr q = "Replace which ammunition? "; cptr s = "Error in obj_wield, please report"; item_tester_hook = obj_is_ammo; if (!get_item(&slot, q, s, CMD_WIELD, USE_EQUIP)) return; } } cmd_insert(CMD_WIELD); cmd_set_arg_item(cmd_get_top(), 0, item); cmd_set_arg_number(cmd_get_top(), 1, slot); }
/* * The "wearable" tester */ static bool item_tester_hook_wear(const object_type *o_ptr) { /* Check for a usable slot */ if (wield_slot(o_ptr) >= INVEN_WIELD) return (TRUE); /* Assume not wearable */ return (FALSE); }
/** * Melee weapons assume MAX_BLOWS per turn, so we must divide by MAX_BLOWS * to get equal ratings for launchers. */ static int rescale_bow_power(const object_type *obj, int p) { if (wield_slot(obj) == slot_by_name(player, "shooting")) { p /= MAX_BLOWS; log_obj(format("Rescaling bow power, total is %d\n", p)); } return p; }
/** * Add power for non-derived flags (derived flags have flag_power 0) */ static int flags_power(const object_type *obj, int p, int verbose, ang_file *log_file, bool known) { size_t i, j; int q; bitflag flags[OF_SIZE]; /* Extract the flags */ if (known) object_flags(obj, flags); else object_flags_known(obj, flags); /* Log the flags in human-readable form */ if (verbose) log_flags(flags, log_file); /* Zero the flag counts */ for (i = 0; i < N_ELEMENTS(flag_sets); i++) flag_sets[i].count = 0; for (i = of_next(flags, FLAG_START); i != FLAG_END; i = of_next(flags, i + 1)) { if (flag_power(i)) { q = (flag_power(i) * flag_slot_mult(i, wield_slot(obj))); p += q; log_obj(format("Add %d power for %s, total is %d\n", q, flag_name(i), p)); } /* Track combinations of flag types */ for (j = 0; j < N_ELEMENTS(flag_sets); j++) if (flag_sets[j].type == obj_flag_type(i)) flag_sets[j].count++; } /* Add extra power for multiple flags of the same type */ for (i = 0; i < N_ELEMENTS(flag_sets); i++) { if (flag_sets[i].count > 1) { q = (flag_sets[i].factor * flag_sets[i].count * flag_sets[i].count); p += q; log_obj(format("Add %d power for multiple %s, total is %d\n", q, flag_sets[i].desc, p)); } /* Add bonus if item has a full set of these flags */ if (flag_sets[i].count == flag_sets[i].size) { q = flag_sets[i].bonus; p += q; log_obj(format("Add %d power for full set of %s, total is %d\n", q, flag_sets[i].desc, p)); } } return p; }
/* * The "wearable" tester */ static bool item_tester_hook_wear(object_type *o_ptr) { /*if ((o_ptr->tval == TV_SOFT_ARMOR) && (o_ptr->sval == SV_ABUNAI_MIZUGI)) if (p_ptr->psex == SEX_MALE) return FALSE;*/ /* Check for a usable slot */ if (wield_slot(o_ptr) >= INVEN_RARM) return (TRUE); /* Assume not wearable */ return (FALSE); }
/* * The "wearable" tester */ static bool item_tester_hook_wear(const object_type *o_ptr) { // Despite being a crown, the Iron Crown cannot be worn if ((o_ptr->name1 >= ART_MORGOTH_0) && (o_ptr->name1 <= ART_MORGOTH_3)) return (FALSE); /* Check for a usable slot */ if (wield_slot(o_ptr) >= INVEN_WIELD) return (TRUE); /* Assume not wearable */ return (FALSE); }
/** * Return a "feeling" (or FEEL_NONE) about an item. Method 1 (Heavy). */ int value_check_aux1(object_type * o_ptr) { int slot = wield_slot(o_ptr); /* Wieldable? */ if (slot < 0) return FEEL_NONE; /* No pseudo for lights */ if (slot == INVEN_LIGHT) return FEEL_NONE; /* Artifacts */ if (artifact_p(o_ptr)) { /* All return special now */ return FEEL_SPECIAL; } /* Ego-Items */ if (ego_item_p(o_ptr)) { /* Dubious egos (including jewellery) */ if (item_dubious(o_ptr, TRUE)) return FEEL_PERILOUS; /* Normal */ o_ptr->ident |= (IDENT_UNCURSED | IDENT_KNOW_CURSES); return FEEL_EXCELLENT; } /* Dubious items */ if (item_dubious(o_ptr, TRUE)) return FEEL_DUBIOUS_STRONG; /* Known not cursed now */ o_ptr->ident |= (IDENT_UNCURSED | IDENT_KNOW_CURSES); /* No average jewellery */ if ((slot >= INVEN_LEFT) && (slot <= INVEN_NECK)) return FEEL_GOOD_STRONG; /* Good "armor" bonus */ if (o_ptr->to_a > 0) return FEEL_GOOD_STRONG; /* Good "weapon" bonus */ if (o_ptr->to_h + o_ptr->to_d > 0) return FEEL_GOOD_STRONG; /* Default to "average" */ return FEEL_AVERAGE; }
int evaluate_object(object_type *o_ptr) { int slot = wield_slot(o_ptr); int value = 0; object_type *o_ptr2; if (slot >= 0) { o_ptr2 = &inventory[slot]; switch (slot) { case INVEN_WIELD: value = evaluate_weapon(o_ptr) - evaluate_weapon(o_ptr2); break; case INVEN_BOW: value = evaluate_bow(o_ptr) - evaluate_bow(o_ptr2); break; //case INVEN_LEFT: //case INVEN_RIGHT: //case INVEN_NECK: case INVEN_LITE: value = evaluate_light(o_ptr) - evaluate_light(o_ptr2); break; case INVEN_BODY: case INVEN_OUTER: case INVEN_ARM: case INVEN_HEAD: case INVEN_HANDS: case INVEN_FEET: value = evaluate_armour(o_ptr) - evaluate_armour(o_ptr2); break; case INVEN_QUIVER1: case INVEN_QUIVER2: // hack: the +1 means we will accept ties // in the future it is better to do arrows differently // by counting those in pack and considering how much we care about archery value = evaluate_arrow(o_ptr) - evaluate_arrow(o_ptr2) + 1; break; } } else { value = 0; } return (value); }
bool object_FA_would_be_obvious(const object_type *o_ptr) { bitflag flags[OF_SIZE]; if (!player_has(PF_CUMBER_GLOVE)) return FALSE; if ((wield_slot(o_ptr) != INVEN_HANDS) || (o_ptr->sval == SV_SET_OF_ALCHEMISTS_GLOVES)) return FALSE; object_flags(o_ptr, flags); if (of_has(flags, OF_DEX)) return FALSE; return TRUE; }
/** * To damage power */ static int to_damage_power(const object_type *obj) { int p; p = (obj->to_d * DAMAGE_POWER / 2); if (p) log_obj(format("%d power from to_dam\n", p)); /* Add second lot of damage power for non-weapons */ if ((wield_slot(obj) != slot_by_name(player, "shooting")) && !tval_is_melee_weapon(obj) && !tval_is_ammo(obj)) { int q = (obj->to_d * DAMAGE_POWER); p += q; if (q) log_obj(format("Add %d from non-weapon to_dam, total %d\n", q, p)); } return p; }
/** * Damage dice power or equivalent */ static int damage_dice_power(const object_type *obj) { int dice = 0; /* Add damage from dice for any wieldable weapon or ammo */ if (tval_is_melee_weapon(obj) || tval_is_ammo(obj)) { dice = (obj->dd * (obj->ds + 1) * DAMAGE_POWER / 4); log_obj(format("Add %d power for damage dice, ", dice)); } else if (wield_slot(obj) != slot_by_name(player, "shooting")) { /* Add power boost for nonweapons with combat flags */ if (obj->brands || obj->slays || (obj->modifiers[OBJ_MOD_BLOWS] > 0) || (obj->modifiers[OBJ_MOD_SHOTS] > 0) || (obj->modifiers[OBJ_MOD_MIGHT] > 0)) { dice = (WEAP_DAMAGE * DAMAGE_POWER); log_obj(format("Add %d power for non-weapon combat bonuses, ", dice)); } } return dice; }
/** * Add ammo damage for launchers, get multiplier and rescale */ static int ammo_damage_power(const object_type *obj, int p) { int q = 0; int launcher = -1; if (wield_slot(obj) == slot_by_name(player, "shooting")) { if (kf_has(obj->kind->kind_flags, KF_SHOOTS_SHOTS)) launcher = 0; else if (kf_has(obj->kind->kind_flags, KF_SHOOTS_ARROWS)) launcher = 1; else if (kf_has(obj->kind->kind_flags, KF_SHOOTS_BOLTS)) launcher = 2; if (launcher != -1) { q = (archery[launcher].ammo_dam * DAMAGE_POWER / 2); log_obj(format("Adding %d power from ammo, total is %d\n", q, p + q)); } } return q; }
/** * Return a "feeling" (or FEEL_NONE) about an item. Method 2 (Light). */ int value_check_aux2(object_type * o_ptr) { int slot = wield_slot(o_ptr); /* Wieldable? */ if (slot < 0) return FEEL_NONE; /* No pseudo for lights */ if (slot == INVEN_LIGHT) return FEEL_NONE; /* Dubious items (all of them) */ if (item_dubious(o_ptr, TRUE)) return FEEL_DUBIOUS_WEAK; /* Known not cursed now */ o_ptr->ident |= (IDENT_UNCURSED | IDENT_KNOW_CURSES); /* Artifacts -- except dubious ones */ if (artifact_p(o_ptr)) return FEEL_GOOD_WEAK; /* Ego-Items -- except dubious ones */ if (ego_item_p(o_ptr)) return FEEL_GOOD_WEAK; /* Good armor bonus */ if (o_ptr->to_a > 0) return FEEL_GOOD_WEAK; /* Good weapon bonuses */ if (o_ptr->to_h + o_ptr->to_d > 0) return FEEL_GOOD_WEAK; /* SJGU */ /* Default to "average" */ return FEEL_AVERAGE; }
/** * Returns information about objects that can be used for digging. * * `deciturns` will be filled in with the avg number of deciturns it will * take to dig through each type of diggable terrain, and must be at least * [DIGGING_MAX]. * * Returns false if the object has no effect on digging, or if the specifics * are meaningless (i.e. the object is an ego template, not a real item). */ static bool obj_known_digging(struct object *obj, int deciturns[]) { struct player_state state; int i; int chances[DIGGING_MAX]; int slot = wield_slot(obj); struct object *current = slot_object(player, slot); /* Doesn't remotely resemble a digger */ if (!tval_is_wearable(obj) || (!tval_is_melee_weapon(obj) && (obj->modifiers[OBJ_MOD_TUNNEL] <= 0))) return false; /* Player has no digging info */ if (!tval_is_melee_weapon(obj) && !obj->known->modifiers[OBJ_MOD_TUNNEL]) return false; /* Pretend we're wielding the object */ player->body.slots[slot].obj = obj; /* Calculate the player's hypothetical state */ memcpy(&state, &player->state, sizeof(state)); state.stat_ind[STAT_STR] = 0; //Hack - NRM state.stat_ind[STAT_DEX] = 0; //Hack - NRM calc_bonuses(player, &state, true, false); /* Stop pretending */ player->body.slots[slot].obj = current; calc_digging_chances(&state, chances); /* Digging chance is out of 1600 */ for (i = DIGGING_RUBBLE; i < DIGGING_MAX; i++) { int chance = MIN(1600, chances[i]); deciturns[i] = chance ? (16000 / chance) : 0; } return true; }
/* * Apply magic to a weapon. */ static void apply_magic_weapon(object_type *o_ptr, int level, int power) { if (power <= 0) return; o_ptr->to_h += randint1(5) + m_bonus(5, level); o_ptr->to_d += randint1(5) + m_bonus(5, level); if (power > 1) { o_ptr->to_h += m_bonus(10, level); o_ptr->to_d += m_bonus(10, level); if (wield_slot(o_ptr) == INVEN_WIELD || obj_is_ammo(o_ptr)) { /* Super-charge the damage dice */ while ((o_ptr->dd * o_ptr->ds > 0) && one_in_(10L * o_ptr->dd * o_ptr->ds)) o_ptr->dd++; /* But not too high */ if (o_ptr->dd > 9) o_ptr->dd = 9; } } }
/* * Describe damage. */ static bool describe_damage(textblock *tb, const object_type *o_ptr, player_state state, bitflag f[OF_SIZE], oinfo_detail_t mode) { const char *desc[SL_MAX] = { 0 }; size_t i, cnt; int mult[SL_MAX]; int dice, sides, dam, total_dam, plus = 0; int xtra_postcrit = 0, xtra_precrit = 0; int crit_mult, crit_div, crit_add; int old_blows = 0; object_type *bow = &p_ptr->inventory[INVEN_BOW]; bitflag tmp_f[OF_SIZE], mask[OF_SIZE]; bool weapon = (wield_slot(o_ptr) == INVEN_WIELD); bool ammo = (p_ptr->state.ammo_tval == o_ptr->tval) && (bow->kind); int multiplier = 1; bool full = mode & OINFO_FULL; /* Create the "all slays" mask */ create_mask(mask, FALSE, OFT_SLAY, OFT_KILL, OFT_BRAND, OFT_MAX); /* Use displayed dice if real dice not known */ if (full || object_attack_plusses_are_visible(o_ptr)) { dice = o_ptr->dd; sides = o_ptr->ds; } else { dice = o_ptr->kind->dd; sides = o_ptr->kind->ds; } /* Calculate damage */ dam = ((sides + 1) * dice * 5); if (weapon) { xtra_postcrit = state.dis_to_d * 10; if (object_attack_plusses_are_visible(o_ptr) || full) { xtra_precrit += o_ptr->to_d * 10; plus += o_ptr->to_h; } calculate_melee_crits(&state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); old_blows = state.num_blows; } else { /* Ammo */ if (object_attack_plusses_are_visible(o_ptr) || full) plus += o_ptr->to_h; calculate_missile_crits(&p_ptr->state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); if (object_attack_plusses_are_visible(o_ptr) || full) dam += (o_ptr->to_d * 10); if (object_attack_plusses_are_visible(bow)) dam += (bow->to_d * 10); /* Apply brands/slays from the shooter to the ammo, but only if known * Note that this is not dependent on mode, so that viewing shop-held * ammo (fully known) does not leak information about launcher */ object_flags_known(bow, tmp_f); of_union(f, tmp_f); } /* Collect slays */ /* Melee weapons get slays and brands from other items now */ if (weapon) { bool nonweap_slay = FALSE; for (i = INVEN_LEFT; i < INVEN_TOTAL; i++) { if (!p_ptr->inventory[i].kind) continue; object_flags_known(&p_ptr->inventory[i], tmp_f); /* Strip out non-slays */ of_inter(tmp_f, mask); if (of_union(f, tmp_f)) nonweap_slay = TRUE; } if (nonweap_slay) textblock_append(tb, "This weapon may benefit from one or more off-weapon brands or slays.\n"); } textblock_append(tb, "Average damage/round: "); if (ammo) multiplier = p_ptr->state.ammo_mult; /* Output damage for creatures effected by the brands or slays */ cnt = list_slays(f, mask, desc, NULL, mult, TRUE); for (i = 0; i < cnt; i++) { /* ammo mult adds fully, melee mult is times 1, so adds 1 less */ int melee_adj_mult = ammo ? 0 : 1; /* Include bonus damage and slay in stated average */ total_dam = dam * (multiplier + mult[i] - melee_adj_mult) + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); textblock_append(tb, " vs. %s, ", desc[i]); } if (cnt) textblock_append(tb, "and "); /* Include bonus damage in stated average */ total_dam = dam * multiplier + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; /* Normal damage, not considering brands or slays */ if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); if (cnt) textblock_append(tb, " vs. others"); textblock_append(tb, ".\n"); return TRUE; }
/** * Bring up objects to act on */ void do_cmd_show_obj(void) { cptr q, s; int j, item; object_type *o_ptr; char o_name[120]; byte out_color; bool accepted = FALSE; /* No restrictions */ item_tester_tval = 0; item_tester_hook = NULL; /* See what's available */ q = "Pick an item to use:"; s = "You have no items to hand."; if (!get_item(&item, q, s, CMD_NULL, (USE_INVEN | USE_EQUIP | USE_FLOOR))) return; /* Got it */ if (item >= 0) { o_ptr = &p_ptr->inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Is it really an item? */ if (!o_ptr->k_idx) return; /* No commands yet */ poss = 0; /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_FULL); /* Hack -- enforce max length */ o_name[Term->wid - 3] = '\0'; /* Acquire inventory color. Apply spellbook hack. */ out_color = proc_list_color_hack(o_ptr); /* Wear/wield */ if ((wield_slot(o_ptr) >= INVEN_WIELD) && (!SCHANGE) && (item < INVEN_WIELD)) { comm[poss] = 'w'; comm_code[poss] = CMD_WIELD; comm_descr[poss++] = "Wield"; } /* Take off equipment */ if ((item >= INVEN_WIELD) && (item < INVEN_TOTAL) && (!SCHANGE)) { comm[poss] = 't'; comm_code[poss] = CMD_TAKEOFF; comm_descr[poss++] = "Take off"; } /* Drop an item */ if ((item >= 0) && ((item < INVEN_WIELD) || (!SCHANGE))) { comm[poss] = 'd'; comm_code[poss] = CMD_DROP; comm_descr[poss++] = "Drop"; } /* Destroy an item */ if (item < INVEN_WIELD) { comm[poss] = 'k'; comm_code[poss] = CMD_DESTROY; comm_descr[poss++] = "Destroy"; } /* Identify an object */ comm[poss] = 'I'; comm_code[poss] = CMD_NULL; comm_descr[poss++] = "Inspect"; /* Pick up an object */ if ((item < 0) && inven_carry_okay(o_ptr)) { comm[poss] = 'g'; comm_code[poss] = CMD_PICKUP; comm_descr[poss++] = "Pick up"; } /* Book learnin' */ if (mp_ptr->spell_book == o_ptr->tval) { if (p_ptr->new_spells) { comm[poss] = 'G'; comm_code[poss] = CMD_STUDY_SPELL; comm_descr[poss++] = "Gain a spell"; } comm[poss] = 'b'; comm_code[poss] = CMD_BROWSE_SPELL; comm_descr[poss++] = "Browse"; comm[poss] = 'm'; comm_code[poss] = CMD_CAST; comm_descr[poss++] = "Cast a spell"; } /* Inscribe an object */ comm[poss] = '{'; comm_code[poss] = CMD_INSCRIBE; comm_descr[poss++] = "Inscribe"; /* Uninscribe an object */ if (o_ptr->note) { comm[poss] = '}'; comm_code[poss] = CMD_UNINSCRIBE; comm_descr[poss++] = "Uninscribe"; } /* Activate equipment */ if ((o_ptr->effect) && (item >= INVEN_WIELD)) { comm[poss] = 'A'; comm_code[poss] = CMD_ACTIVATE; comm_descr[poss++] = "Activate"; } /* Eat some food */ if (o_ptr->tval == TV_FOOD) { comm[poss] = 'E'; comm_code[poss] = CMD_EAT; comm_descr[poss++] = "Eat"; } if ((item < INVEN_WIELD) && ((o_ptr->tval == TV_LIGHT) || (o_ptr->tval == TV_FLASK))) { object_type *o1_ptr = &p_ptr->inventory[INVEN_LIGHT]; if (((o1_ptr->sval == SV_LIGHT_LANTERN) && ((o_ptr->tval == TV_FLASK) || ((o_ptr->tval == TV_LIGHT) && (o_ptr->sval == SV_LIGHT_LANTERN)))) || ((o1_ptr->sval == SV_LIGHT_TORCH) && (o_ptr->tval == TV_LIGHT) && (o_ptr->sval == SV_LIGHT_TORCH))) { comm[poss] = 'F'; comm_code[poss] = CMD_REFILL; comm_descr[poss++] = "Refuel"; } } /* Fire an item */ if (p_ptr->state.ammo_tval == o_ptr->tval) { comm[poss] = 'f'; comm_code[poss] = CMD_FIRE; comm_descr[poss++] = "Fire"; } /* Throw an item */ if ((item < INVEN_WIELD) || (!SCHANGE)) { comm[poss] = 'v'; comm_code[poss] = CMD_THROW; comm_descr[poss++] = "Throw"; } /* Aim a wand */ if (o_ptr->tval == TV_WAND) { comm[poss] = 'a'; comm_code[poss] = CMD_USE_WAND; comm_descr[poss++] = "Aim"; } /* Zap a rod */ if (o_ptr->tval == TV_ROD) { comm[poss] = 'z'; comm_code[poss] = CMD_USE_ROD; comm_descr[poss++] = "Zap"; } /* Quaff a potion */ if (o_ptr->tval == TV_POTION) { comm[poss] = 'q'; comm_code[poss] = CMD_QUAFF; comm_descr[poss++] = "Quaff"; } /* Read a scroll */ if (o_ptr->tval == TV_SCROLL) { comm[poss] = 'r'; comm_code[poss] = CMD_READ_SCROLL; comm_descr[poss++] = "Read"; } /* Use a staff */ if (o_ptr->tval == TV_STAFF) { comm[poss] = 'u'; comm_code[poss] = CMD_USE_STAFF; comm_descr[poss++] = "Use"; } /* Set up the screen */ screen_save(); /* Prompt */ put_str("Choose a command, or ESC:", 0, 0); /* Clear the line */ prt("", 1, 0); /* Display the item */ c_put_str(out_color, o_name, 1, 0); /* Hack - delete exact graphics rows */ if (tile_height > 1) { j = poss + 2; while ((j % tile_height) && (j <= SCREEN_ROWS)) prt("", ++j, 0); } /* Get a choice */ accepted = show_cmd_menu(TRUE); /* Load de screen */ screen_load(); /* Now set the item if valid */ if (accepted) cmd_set_arg_item(cmd_get_top(), 0, item); }
/* * Wield or wear a single item from the pack or floor */ void do_cmd_wield(void) { int item, slot; object_type *o_ptr; object_type *i_ptr; object_type object_type_body; cptr act; cptr q, s; char o_name[80]; /* Restrict the choices */ item_tester_hook = item_tester_hook_wear; /* Get an item */ q = "Wear/Wield which item? "; s = "You have nothing you can wear or wield."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Check the slot */ slot = wield_slot(o_ptr); /* Prevent wielding into a cursed slot */ if (cursed_p(&inventory[slot])) { /* Describe it */ object_desc(o_name, &inventory[slot], FALSE, 0); /* Message */ msg_format("The %s you are %s appears to be cursed.", o_name, describe_use(slot)); /* Cancel the command */ return; } /* Take a turn */ p_ptr->energy_use = 100; /* Get local object */ i_ptr = &object_type_body; /* Obtain local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Decrease the item (from the pack) */ if (item >= 0) { inven_item_increase(item, -1); inven_item_optimize(item); } /* Decrease the item (from the floor) */ else { floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } /* Get the wield slot */ o_ptr = &inventory[slot]; /* Take off existing item */ if (o_ptr->k_idx) { /* Take off existing item */ (void)inven_takeoff(slot, 255); } /* Wear the new stuff */ object_copy(o_ptr, i_ptr); /* Increase the weight */ p_ptr->total_weight += i_ptr->weight; /* Increment the equip counter by hand */ p_ptr->equip_cnt++; /* Where is the item now */ if (slot == INVEN_WIELD) { act = "You are wielding"; } else if (slot == INVEN_BOW) { act = "You are shooting with"; } else if (slot == INVEN_LIGHT) { act = "Your light source is"; } else { act = "You are wearing"; } /* Describe the result */ object_desc(o_name, o_ptr, TRUE, 3); /* Message */ msg_format("%s %s (%c).", act, o_name, index_to_label(slot)); /* Cursed! */ if (cursed_p(o_ptr)) { /* Warn the player */ msg_print("Oops! It feels deathly cold!"); /* Remove special inscription, if any */ if (o_ptr->discount >= INSCRIP_NULL) o_ptr->discount = 0; /* Sense the object if allowed */ if (o_ptr->discount == 0) o_ptr->discount = INSCRIP_CURSED; /* The object has been "sensed" */ o_ptr->ident |= (IDENT_SENSE); } /* Recalculate bonuses */ p_ptr->update |= (PU_BONUS); /* Recalculate torch */ p_ptr->update |= (PU_TORCH); /* Recalculate mana */ p_ptr->update |= (PU_MANA); /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER_0 | PW_PLAYER_1); p_ptr->redraw |= (PR_EQUIPPY); }
/* * Wield or wear a single item from the pack or floor */ void do_cmd_wield(void) { int i, item, slot; object_type forge; object_type *q_ptr; object_type *o_ptr; cptr act; char o_name[MAX_NLEN]; cptr q, s; int need_switch_wielding = 0; if (p_ptr->special_defense & KATA_MUSOU) { set_action(ACTION_NONE); } /* Restrict the choices */ item_tester_hook = item_tester_hook_wear; /* Get an item */ #ifdef JP q = "どれを装備しますか? "; s = "装備可能なアイテムがない。"; #else q = "Wear/Wield which item? "; s = "You have nothing you can wear or wield."; #endif if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Check the slot */ slot = wield_slot(o_ptr); /* Ugly hack! */ if ( object_is_melee_weapon(o_ptr) && p_ptr->pclass == CLASS_PSION && psion_weapon_graft() ) { msg_print("Failed! Your weapon is currently grafted to your arm!"); return; } switch (o_ptr->tval) { /* Shields and some misc. items */ case TV_CAPTURE: case TV_SHIELD: case TV_CARD: /* Dual wielding */ if (buki_motteruka(INVEN_RARM) && buki_motteruka(INVEN_LARM)) { /* Restrict the choices */ item_tester_hook = item_tester_hook_melee_weapon; item_tester_no_ryoute = TRUE; /* Choose a weapon from the equipment only */ #ifdef JP q = "どちらの武器と取り替えますか?"; s = "おっと。"; #else q = "Replace which weapon? "; s = "Oops."; #endif if (!get_item(&slot, q, s, (USE_EQUIP))) return; if (slot == INVEN_RARM) need_switch_wielding = INVEN_LARM; } else if (buki_motteruka(INVEN_LARM)) slot = INVEN_RARM; /* Both arms are already used by non-weapon */ else if (inventory[INVEN_RARM].k_idx && !object_is_melee_weapon(&inventory[INVEN_RARM]) && inventory[INVEN_LARM].k_idx && !object_is_melee_weapon(&inventory[INVEN_LARM])) { /* Restrict the choices */ item_tester_hook = item_tester_hook_mochikae; /* Choose a hand */ #ifdef JP q = "どちらの手に装備しますか?"; s = "おっと。"; #else q = "Equip which hand? "; s = "Oops."; #endif if (!get_item(&slot, q, s, (USE_EQUIP))) return; } break; /* Melee weapons */ case TV_DIGGING: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: /* Asking for dual wielding */ if (slot == INVEN_LARM) { #ifdef JP if (!get_check("二刀流で戦いますか?")) slot = INVEN_RARM; #else if (!get_check("Dual wielding? ")) slot = INVEN_RARM; #endif } else if (!inventory[INVEN_RARM].k_idx && buki_motteruka(INVEN_LARM)) { #ifdef JP if (!get_check("二刀流で戦いますか?")) slot = INVEN_LARM; #else if (!get_check("Dual wielding? ")) slot = INVEN_LARM; #endif } /* Both arms are already used */ else if (inventory[INVEN_LARM].k_idx && inventory[INVEN_RARM].k_idx) { /* Restrict the choices */ item_tester_hook = item_tester_hook_mochikae; /* Choose a hand */ #ifdef JP q = "どちらの手に装備しますか?"; s = "おっと。"; #else q = "Equip which hand? "; s = "Oops."; #endif if (!get_item(&slot, q, s, (USE_EQUIP))) return; if ((slot == INVEN_LARM) && !buki_motteruka(INVEN_RARM)) need_switch_wielding = INVEN_RARM; } break; /* Rings */ case TV_RING: /* Choose a ring slot */ if (inventory[INVEN_LEFT].k_idx && inventory[INVEN_RIGHT].k_idx) { #ifdef JP q = "どちらの指輪と取り替えますか?"; #else q = "Replace which ring? "; #endif } else { #ifdef JP q = "どちらの手に装備しますか?"; #else q = "Equip which hand? "; #endif } #ifdef JP s = "おっと。"; #else s = "Oops."; #endif /* Restrict the choices */ select_ring_slot = TRUE; item_tester_no_ryoute = TRUE; if (!get_item(&slot, q, s, (USE_EQUIP))) { select_ring_slot = FALSE; return; } select_ring_slot = FALSE; break; } /* Prevent wielding into a cursed slot */ if (object_is_cursed(&inventory[slot])) { /* Describe it */ object_desc(o_name, &inventory[slot], (OD_OMIT_PREFIX | OD_NAME_ONLY)); /* Message */ #ifdef JP msg_format("%s%sは呪われているようだ。", describe_use(slot) , o_name ); #else msg_format("The %s you are %s appears to be cursed.", o_name, describe_use(slot)); #endif /* Cancel the command */ return; } if (have_flag(inventory[slot].art_flags, TR_SIGNATURE)) { object_desc(o_name, &inventory[slot], (OD_OMIT_PREFIX | OD_NAME_ONLY)); msg_format("The %s you are %s is your signature item and may not be removed.", o_name, describe_use(slot)); return; } if (confirm_wear && ((object_is_cursed(o_ptr) && object_is_known(o_ptr)) || ((o_ptr->ident & IDENT_SENSE) && (FEEL_BROKEN <= o_ptr->feeling) && (o_ptr->feeling <= FEEL_CURSED)))) { char dummy[MAX_NLEN+80]; /* Describe it */ object_desc(o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY)); #ifdef JP sprintf(dummy, "本当に%s{呪われている}を使いますか?", o_name); #else sprintf(dummy, "Really use the %s {cursed}? ", o_name); #endif if (!get_check(dummy)) return; } if ((o_ptr->name1 == ART_STONEMASK) && object_is_known(o_ptr) && (p_ptr->prace != RACE_VAMPIRE) && (p_ptr->prace != RACE_ANDROID) && (p_ptr->pclass != CLASS_BLOOD_KNIGHT)) { char dummy[MAX_NLEN+80]; /* Describe it */ object_desc(o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY)); #ifdef JP sprintf(dummy, "%sを装備すると吸血鬼になります。よろしいですか?", o_name); #else msg_format("%s will transforms you into a vampire permanently when equiped.", o_name); sprintf(dummy, "Do you become a vampire?"); #endif if (!get_check(dummy)) return; } if (need_switch_wielding && !object_is_cursed(&inventory[need_switch_wielding])) { object_type *slot_o_ptr = &inventory[slot]; object_type *switch_o_ptr = &inventory[need_switch_wielding]; object_type object_tmp; object_type *otmp_ptr = &object_tmp; char switch_name[MAX_NLEN]; object_desc(switch_name, switch_o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY)); object_copy(otmp_ptr, switch_o_ptr); object_copy(switch_o_ptr, slot_o_ptr); object_copy(slot_o_ptr, otmp_ptr); #ifdef JP msg_format("%sを%sに構えなおした。", switch_name, (slot == INVEN_RARM) ? (left_hander ? "左手" : "右手") : (left_hander ? "右手" : "左手")); #else msg_format("You wield %s at %s hand.", switch_name, (slot == INVEN_RARM) ? (left_hander ? "left" : "right") : (left_hander ? "right" : "left")); #endif slot = need_switch_wielding; } /* Check if completed a quest */ for (i = 0; i < max_quests; i++) { if ((quest[i].type == QUEST_TYPE_FIND_ARTIFACT) && (quest[i].status == QUEST_STATUS_TAKEN) && (quest[i].k_idx == o_ptr->name1 || quest[i].k_idx == o_ptr->name3)) { if (record_fix_quest) do_cmd_write_nikki(NIKKI_FIX_QUEST_C, i, NULL); quest[i].status = QUEST_STATUS_COMPLETED; quest[i].complev = (byte)p_ptr->lev; #ifdef JP msg_print("クエストを達成した!"); #else msg_print("You completed the quest!"); #endif msg_print(NULL); } } if (p_ptr->personality == PERS_MUNCHKIN) { identify_item(o_ptr); /* Auto-inscription */ autopick_alter_item(item, FALSE); } /* Take a turn */ energy_use = weaponmaster_wield_hack(o_ptr); /* Get local object */ q_ptr = &forge; /* Obtain local object */ object_copy(q_ptr, o_ptr); /* Modify quantity */ q_ptr->number = 1; /* Decrease the item (from the pack) */ if (item >= 0) { inven_item_increase(item, -1); inven_item_optimize(item); } /* Decrease the item (from the floor) */ else { floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } /* Access the wield slot */ o_ptr = &inventory[slot]; /* Take off existing item */ if (o_ptr->k_idx) { /* Take off existing item */ (void)inven_takeoff(slot, 255); } /* Wear the new stuff */ object_copy(o_ptr, q_ptr); /* Player touches it */ o_ptr->marked |= OM_TOUCHED; /* Increase the weight */ p_ptr->total_weight += q_ptr->weight; /* Increment the equip counter by hand */ equip_cnt++; #ifdef JP #define STR_WIELD_RARM "%s(%c)を右手に装備した。" #define STR_WIELD_LARM "%s(%c)を左手に装備した。" #define STR_WIELD_ARMS "%s(%c)を両手で構えた。" #else #define STR_WIELD_RARM "You are wielding %s (%c) in your right hand." #define STR_WIELD_LARM "You are wielding %s (%c) in your left hand." #define STR_WIELD_ARMS "You are wielding %s (%c) with both hands." #endif /* Where is the item now */ switch (slot) { case INVEN_RARM: if (object_allow_two_hands_wielding(o_ptr) && (empty_hands(FALSE) == EMPTY_HAND_LARM) && CAN_TWO_HANDS_WIELDING()) act = STR_WIELD_ARMS; else act = (left_hander ? STR_WIELD_LARM : STR_WIELD_RARM); break; case INVEN_LARM: if (object_allow_two_hands_wielding(o_ptr) && (empty_hands(FALSE) == EMPTY_HAND_RARM) && CAN_TWO_HANDS_WIELDING()) act = STR_WIELD_ARMS; else act = (left_hander ? STR_WIELD_RARM : STR_WIELD_LARM); break; case INVEN_BOW: #ifdef JP act = "%s(%c)を射撃用に装備した。"; #else act = "You are shooting with %s (%c)."; #endif break; case INVEN_LITE: #ifdef JP act = "%s(%c)を光源にした。"; #else act = "Your light source is %s (%c)."; #endif break; default: #ifdef JP act = "%s(%c)を装備した。"; #else act = "You are wearing %s (%c)."; #endif break; } /* Describe the result */ object_desc(o_name, o_ptr, 0); /* Message */ msg_format(act, o_name, index_to_label(slot)); /* Cursed! */ if (object_is_cursed(o_ptr)) { /* Warn the player */ #ifdef JP msg_print("うわ! すさまじく冷たい!"); #else msg_print("Oops! It feels deathly cold!"); #endif chg_virtue(V_HARMONY, -1); /* Note the curse */ o_ptr->ident |= (IDENT_SENSE); } if (o_ptr->name1 == ART_HAND_OF_VECNA) { msg_print("You chop off your own hand to wield the Hand of Vecna!"); set_cut(CUT_MORTAL_WOUND, FALSE); } if (o_ptr->name1 == ART_EYE_OF_VECNA) { msg_print("You pluck out your own eye to wield the Eye of Vecna!"); set_cut(CUT_MORTAL_WOUND, FALSE); } /* The Stone Mask make the player turn into a vampire! */ if ((o_ptr->name1 == ART_STONEMASK) && (p_ptr->prace != RACE_VAMPIRE) && (p_ptr->prace != RACE_ANDROID) && (p_ptr->pclass != CLASS_BLOOD_KNIGHT) && (p_ptr->pclass != CLASS_BLOOD_MAGE)) { /* Turn into a vampire */ change_race(RACE_VAMPIRE, ""); } /* Recalculate bonuses */ p_ptr->update |= (PU_BONUS); /* Recalculate torch */ p_ptr->update |= (PU_TORCH); /* Recalculate mana */ p_ptr->update |= (PU_MANA); p_ptr->redraw |= (PR_EQUIPPY); /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER); calc_android_exp(); }
/* * Describe combat advantages. */ static bool describe_combat(textblock *tb, const object_type *o_ptr, oinfo_detail_t mode) { bool full = mode & OINFO_FULL; const char *desc[SL_MAX] = { 0 }; int i; int mult[SL_MAX]; int cnt, dam, total_dam, plus = 0; int xtra_postcrit = 0, xtra_precrit = 0; int crit_mult, crit_div, crit_add; int str_plus, dex_plus, old_blows = 0, new_blows, extra_blows; int str_faster = -1, str_done = -1; object_type *bow = &p_ptr->inventory[INVEN_BOW]; bitflag f[OF_SIZE], tmp_f[OF_SIZE], mask[OF_SIZE]; bool weapon = (wield_slot(o_ptr) == INVEN_WIELD); bool ammo = (p_ptr->state.ammo_tval == o_ptr->tval) && (bow->kind); int multiplier = 1; /* Create the "all slays" mask */ create_mask(mask, FALSE, OFT_SLAY, OFT_KILL, OFT_BRAND, OFT_MAX); /* Abort if we've nothing to say */ if (mode & OINFO_DUMMY) return FALSE; if (!weapon && !ammo) { /* Potions can have special text */ if (o_ptr->tval != TV_POTION || o_ptr->dd == 0 || o_ptr->ds == 0 || !object_flavor_is_aware(o_ptr)) return FALSE; textblock_append(tb, "It can be thrown at creatures with damaging effect.\n"); return TRUE; } if (full) { object_flags(o_ptr, f); } else { object_flags_known(o_ptr, f); } textblock_append_c(tb, TERM_L_WHITE, "Combat info:\n"); if (weapon) { /* * Get the player's hypothetical state, were they to be * wielding this item. */ player_state state; int dex_plus_bound; int str_plus_bound; object_type inven[INVEN_TOTAL]; memcpy(inven, p_ptr->inventory, INVEN_TOTAL * sizeof(object_type)); inven[INVEN_WIELD] = *o_ptr; if (full) object_know_all_flags(&inven[INVEN_WIELD]); calc_bonuses(inven, &state, TRUE); dex_plus_bound = STAT_RANGE - state.stat_ind[A_DEX]; str_plus_bound = STAT_RANGE - state.stat_ind[A_STR]; dam = ((o_ptr->ds + 1) * o_ptr->dd * 5); xtra_postcrit = state.dis_to_d * 10; if (object_attack_plusses_are_visible(o_ptr)) { xtra_precrit += o_ptr->to_d * 10; plus += o_ptr->to_h; } calculate_melee_crits(&state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); /* Warn about heavy weapons */ if (adj_str_hold[state.stat_ind[A_STR]] < o_ptr->weight / 10) textblock_append_c(tb, TERM_L_RED, "You are too weak to use this weapon.\n"); textblock_append_c(tb, TERM_L_GREEN, "%d.%d ", state.num_blows / 100, (state.num_blows / 10) % 10); textblock_append(tb, "blow%s/round.\n", (state.num_blows > 100) ? "s" : ""); /* Check to see if extra STR or DEX would yield extra blows */ old_blows = state.num_blows; extra_blows = 0; /* First we need to look for extra blows on other items, as * state does not track these */ for (i = INVEN_BOW; i < INVEN_TOTAL; i++) { if (!p_ptr->inventory[i].kind) continue; object_flags_known(&p_ptr->inventory[i], tmp_f); if (of_has(tmp_f, OF_BLOWS)) extra_blows += p_ptr->inventory[i].pval[which_pval(&p_ptr->inventory[i], OF_BLOWS)]; } /* Then we add blows from the weapon being examined */ if (of_has(f, OF_BLOWS)) extra_blows += o_ptr->pval[which_pval(o_ptr, OF_BLOWS)]; /* Then we check for extra "real" blows */ for (dex_plus = 0; dex_plus < dex_plus_bound; dex_plus++) { for (str_plus = 0; str_plus < str_plus_bound; str_plus++) { state.stat_ind[A_STR] += str_plus; state.stat_ind[A_DEX] += dex_plus; new_blows = calc_blows(o_ptr, &state, extra_blows); /* Test to make sure that this extra blow is a * new str/dex combination, not a repeat */ if ((new_blows - new_blows % 10) > (old_blows - old_blows % 10) && (str_plus < str_done || str_done == -1)) { textblock_append(tb, "With +%d STR and +%d DEX you would get %d.%d blows\n", str_plus, dex_plus, (new_blows / 100), (new_blows / 10) % 10); state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; str_done = str_plus; break; } /* If the combination doesn't increment * the displayed blows number, it might still * take a little less energy */ if (new_blows > old_blows && (str_plus < str_faster || str_faster == -1) && (str_plus < str_done || str_done == -1)) { textblock_append(tb, "With +%d STR and +%d DEX you would attack a bit faster\n", str_plus, dex_plus); state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; str_faster = str_plus; continue; } state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; } } } else { int tdis = 6 + 2 * p_ptr->state.ammo_mult; if (object_attack_plusses_are_visible(o_ptr)) plus += o_ptr->to_h; calculate_missile_crits(&p_ptr->state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); /* Calculate damage */ dam = ((o_ptr->ds + 1) * o_ptr->dd * 5); if (object_attack_plusses_are_visible(o_ptr)) dam += (o_ptr->to_d * 10); if (object_attack_plusses_are_visible(bow)) dam += (bow->to_d * 10); /* Apply brands/slays from the shooter to the ammo, but only if known * Note that this is not dependent on mode, so that viewing shop-held * ammo (fully known) does not leak information about launcher */ object_flags_known(bow, tmp_f); of_union(f, tmp_f); textblock_append(tb, "Hits targets up to "); textblock_append_c(tb, TERM_L_GREEN, format("%d", tdis * 10)); textblock_append(tb, " feet away.\n"); } /* Collect slays */ /* Melee weapons get slays and brands from other items now */ if (weapon) { bool nonweap = FALSE; for (i = INVEN_LEFT; i < INVEN_TOTAL; i++) { if (!p_ptr->inventory[i].kind) continue; object_flags_known(&p_ptr->inventory[i], tmp_f); of_inter(tmp_f, mask); /* strip out non-slays */ if (of_union(f, tmp_f)) nonweap = TRUE; } if (nonweap) textblock_append(tb, "This weapon may benefit from one or more off-weapon brands or slays.\n"); } textblock_append(tb, "Average damage/round: "); if (ammo) multiplier = p_ptr->state.ammo_mult; cnt = list_slays(f, mask, desc, NULL, mult, TRUE); for (i = 0; i < cnt; i++) { int melee_adj_mult = ammo ? 0 : 1; /* ammo mult adds fully, melee mult is times 1, so adds 1 less */ /* Include bonus damage and slay in stated average */ total_dam = dam * (multiplier + mult[i] - melee_adj_mult) + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); textblock_append(tb, " vs. %s, ", desc[i]); } if (cnt) textblock_append(tb, "and "); /* Include bonus damage in stated average */ total_dam = dam * multiplier + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); if (cnt) textblock_append(tb, " vs. others"); textblock_append(tb, ".\n"); /* Note the impact flag */ if (of_has(f, OF_IMPACT)) textblock_append(tb, "Sometimes creates earthquakes on impact.\n"); /* Add breakage chance */ if (ammo) { int chance = breakage_chance(o_ptr, TRUE); textblock_append_c(tb, TERM_L_GREEN, "%d%%", chance); textblock_append(tb, " chance of breaking upon contact.\n"); } /* You always have something to say... */ return TRUE; }
/* * Describe objects that can be used for digging. */ static bool describe_digger(textblock *tb, const object_type *o_ptr, oinfo_detail_t mode) { bool full = mode & OINFO_FULL; player_state st; object_type inven[INVEN_TOTAL]; int sl = wield_slot(o_ptr); int i; bitflag f[OF_SIZE]; int chances[4]; /* These are out of 1600 */ static const char *names[4] = { "rubble", "magma veins", "quartz veins", "granite" }; /* abort if we are a dummy object */ if (mode & OINFO_DUMMY) return FALSE; if (full) object_flags(o_ptr, f); else object_flags_known(o_ptr, f); if (sl < 0 || (sl != INVEN_WIELD && !of_has(f, OF_TUNNEL))) return FALSE; memcpy(inven, p_ptr->inventory, INVEN_TOTAL * sizeof(object_type)); /* * Hack -- if we examine a ring that is worn on the right finger, * we shouldn't put a copy of it on the left finger before calculating * digging skills. */ if (o_ptr != &p_ptr->inventory[INVEN_RIGHT]) inven[sl] = *o_ptr; calc_bonuses(inven, &st, TRUE); chances[0] = st.skills[SKILL_DIGGING] * 8; chances[1] = (st.skills[SKILL_DIGGING] - 10) * 4; chances[2] = (st.skills[SKILL_DIGGING] - 20) * 2; chances[3] = (st.skills[SKILL_DIGGING] - 40) * 1; for (i = 0; i < 4; i++) { int chance = MAX(0, MIN(1600, chances[i])); int decis = chance ? (16000 / chance) : 0; if (i == 0 && chance > 0) { if (sl == INVEN_WIELD) textblock_append(tb, "Clears "); else textblock_append(tb, "With this item, your current weapon clears "); } if (i == 3 || (i != 0 && chance == 0)) textblock_append(tb, "and "); if (chance == 0) { textblock_append_c(tb, TERM_L_RED, "doesn't affect "); textblock_append(tb, "%s.\n", names[i]); break; } textblock_append(tb, "%s in ", names[i]); if (chance == 1600) { textblock_append_c(tb, TERM_L_GREEN, "1 "); } else if (decis < 100) { textblock_append_c(tb, TERM_GREEN, "%d.%d ", decis/10, decis%10); } else { textblock_append_c(tb, (decis < 1000) ? TERM_YELLOW : TERM_RED, "%d ", (decis+5)/10); } textblock_append(tb, "turn%s%s", decis == 10 ? "" : "s", (i == 3) ? ".\n" : ", "); } return TRUE; }
bool pickup_object(void) { object_type *o_ptr = &o_list[cave_o_idx[p_ptr->py][p_ptr->px]]; char commands[80]; int value = evaluate_object(o_ptr); if (value > 0) { int slot = wield_slot(o_ptr); // if it is a non-wieldable item if (slot == -1) { // create the commands strnfmt(commands, sizeof(commands), "g-"); // queue the commands automaton_keypresses(commands); } // special rules for arrows else if ((slot == INVEN_QUIVER1) || (slot == INVEN_QUIVER2)) { // if it is considered equal in value to existing arrows, then just get it to allow auto-merging if (value == 1) { // create the commands strnfmt(commands, sizeof(commands), "g-"); // queue the commands automaton_keypresses(commands); } // otherwise it is considered better than the existing arrows so wield it... else { // create the commands strnfmt(commands, sizeof(commands), "w-"); // queue the commands automaton_keypresses(commands); // if both slots are full, we need to tell the game to replace the inferior one if (inventory[INVEN_QUIVER1].k_idx && inventory[INVEN_QUIVER2].k_idx) { if (evaluate_arrow(&inventory[INVEN_QUIVER1]) > evaluate_arrow(&inventory[INVEN_QUIVER2])) { automaton_keypress(index_to_label(INVEN_QUIVER2)); } else { automaton_keypress(index_to_label(INVEN_QUIVER1)); } } } } // default for wieldable items else { // create the commands strnfmt(commands, sizeof(commands), "w-"); // queue the commands automaton_keypresses(commands); } return (TRUE); } return (FALSE); }
/* * Describe combat advantages. */ static bool describe_combat(textblock *tb, const object_type *o_ptr, oinfo_detail_t mode) { bool full = mode & OINFO_FULL; object_type *bow = &p_ptr->inventory[INVEN_BOW]; bitflag f[OF_SIZE]; bool weapon = (wield_slot(o_ptr) == INVEN_WIELD); bool ammo = (p_ptr->state.ammo_tval == o_ptr->tval) && (bow->kind); /* The player's hypothetical state, were they to wield this item */ player_state state; /* Abort if we've nothing to say */ if (mode & OINFO_DUMMY) return FALSE; if (!weapon && !ammo) { /* Potions can have special text */ if (o_ptr->tval != TV_POTION || o_ptr->dd == 0 || o_ptr->ds == 0 || !object_flavor_is_aware(o_ptr)) return FALSE; textblock_append(tb, "It can be thrown at creatures with damaging effect.\n"); return TRUE; } if (full) object_flags(o_ptr, f); else object_flags_known(o_ptr, f); textblock_append_c(tb, TERM_L_WHITE, "Combat info:\n"); if (weapon) { object_type inven[INVEN_TOTAL]; memcpy(inven, p_ptr->inventory, INVEN_TOTAL * sizeof(object_type)); inven[INVEN_WIELD] = *o_ptr; if (full) object_know_all_flags(&inven[INVEN_WIELD]); /* Calculate the player's hypothetical state */ calc_bonuses(inven, &state, TRUE); /* Warn about heavy weapons */ if (adj_str_hold[state.stat_ind[A_STR]] < o_ptr->weight / 10) textblock_append_c(tb, TERM_L_RED, "You are too weak to use this weapon.\n"); /* Describe blows */ describe_blows(tb, o_ptr, state, f); } else { /* Ammo */ /* Range of the weapon */ int tdis = 6 + 2 * p_ptr->state.ammo_mult; /* Output the range */ textblock_append(tb, "Hits targets up to "); textblock_append_c(tb, TERM_L_GREEN, format("%d", tdis * 10)); textblock_append(tb, " feet away.\n"); } /* Describe damage */ describe_damage(tb, o_ptr, state, f, mode); /* Note the impact flag */ if (of_has(f, OF_IMPACT)) textblock_append(tb, "Sometimes creates earthquakes on impact.\n"); /* Add breakage chance */ if (ammo) { int chance = breakage_chance(o_ptr, TRUE); textblock_append_c(tb, TERM_L_GREEN, "%d%%", chance); textblock_append(tb, " chance of breaking upon contact.\n"); } /* Something has been said */ return TRUE; }