Beispiel #1
0
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;
}
Beispiel #2
0
/**
 * 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;
		}
	}
}
Beispiel #3
0
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;
}
Beispiel #4
0
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);
}
Beispiel #5
0
/**
 * 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;
}
Beispiel #6
0
/**
 * 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;
}
Beispiel #7
0
/**
 * 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;
}
Beispiel #8
0
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);
}
Beispiel #9
0
/*
 * 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);
}
Beispiel #10
0
/**
 * 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;
}
Beispiel #11
0
/**
 * 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;
}
Beispiel #12
0
/*
 * 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);
}
Beispiel #13
0
/*
 * 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);
}
Beispiel #14
0
/**
 * 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;
}
Beispiel #15
0
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);
}
Beispiel #16
0
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;
}
Beispiel #17
0
/**
 * 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;
}
Beispiel #18
0
/**
 * 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;
}
Beispiel #19
0
/**
 * 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;
}
Beispiel #20
0
/**
 * 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;
}
Beispiel #21
0
/**
 * 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;
}
Beispiel #22
0
/*
 * 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;
		}
	}
}
Beispiel #23
0
/*
 * 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;
}
Beispiel #24
0
/**
 * 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);
}
Beispiel #25
0
/*
 * 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);
}
Beispiel #26
0
/*
 * 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();
}
Beispiel #27
0
/*
 * 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;
}
Beispiel #28
0
/*
 * 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;
}
Beispiel #29
0
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);
}
Beispiel #30
0
/*
 * 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;
}