Beispiel #1
0
/**
 * Describe things that look like lights.
 */
static bool describe_light(textblock *tb, const struct object *obj,
		oinfo_detail_t mode)
{
	int rad = 0;
	bool uses_fuel = false;
	int refuel_turns = 0;

	bool terse = mode & OINFO_TERSE ? true : false;

	if (!obj_known_light(obj, mode, &rad, &uses_fuel, &refuel_turns))
		return false;

	textblock_append(tb, "Radius ");
	textblock_append_c(tb, COLOUR_L_GREEN, format("%d", rad));
	textblock_append(tb, " light.");

	if (tval_is_light(obj)) {
		if (!obj->artifact && !uses_fuel)
			textblock_append(tb, "  No fuel required.");

		if (!terse) {
			if (refuel_turns)
				textblock_append(tb, "  Refills other lanterns up to %d turns of fuel.", refuel_turns);
			else
				textblock_append(tb, "  Cannot be refueled.");
		}
	}

	textblock_append(tb, "\n");

	return true;
}
Beispiel #2
0
/**
 * Describe blows.
 */
static bool describe_blows(textblock *tb, const struct object *obj)
{
	int i;
	struct blow_info blow_info[STAT_RANGE * 2]; /* (Very) theoretical max */
	int num_entries = 0;

	num_entries = obj_known_blows(obj, STAT_RANGE * 2, blow_info);
	if (num_entries == 0) return false;

	/* First entry is always current blows (+0, +0) */
	textblock_append_c(tb, COLOUR_L_GREEN, "%d.%d ",
			blow_info[0].centiblows / 100, 
			(blow_info[0].centiblows / 10) % 10);
	textblock_append(tb, "blow%s/round.\n",
			(blow_info[0].centiblows > 100) ? "s" : "");

	/* Then list combinations that give more blows / speed boost */
	for (i = 1; i < num_entries; i++) {
		struct blow_info entry = blow_info[i];

		if (entry.centiblows % 10 == 0) {
			textblock_append(tb, 
				"With +%d STR and +%d DEX you would get %d.%d blows\n",
				entry.str_plus, entry.dex_plus, 
				(entry.centiblows / 100),
				(entry.centiblows / 10) % 10);
		} else {
			textblock_append(tb, 
				"With +%d STR and +%d DEX you would attack a bit faster\n",
				entry.str_plus, entry.dex_plus);
		}
	}

	return true;
}
Beispiel #3
0
static bool describe_food(textblock *tb, const object_type *o_ptr,
		bool subjective, bool full)
{
	/* Describe boring bits */
	if ((o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION) &&
		o_ptr->pval[DEFAULT_PVAL])
	{
		/* Sometimes adjust for player speed */
		int multiplier = extract_energy[p_ptr->state.speed];
		if (!subjective) multiplier = 10;

		if (object_is_known(o_ptr) || full) {
			textblock_append(tb, "Nourishes for around ");
			textblock_append_c(tb, TERM_L_GREEN, "%d", (o_ptr->pval[DEFAULT_PVAL] / 2) *
				multiplier / 10);
			textblock_append(tb, " turns.\n");
		} else {
			textblock_append(tb, "Provides some nourishment.\n");
		}

		return TRUE;
	}

	return FALSE;
}
Beispiel #4
0
/*
 * Describe other bonuses.
 */
static bool describe_bonus(textblock *tb, const object_type *o_ptr,
		oinfo_detail_t mode)
{
    int j, count = 0;
    bool full = mode & OINFO_FULL;
    bool dummy = mode & OINFO_DUMMY;
    bool terse = mode & OINFO_TERSE;

    if (((o_ptr->ident) & IDENT_WORN) || dummy || full) {
	for (j = 0; j < MAX_P_BONUS; j++) {
	    if (o_ptr->bonus_other[j] != 0)
		count++;
	}
    }

    if (count > 0) {
	byte attr = (o_ptr->bonus_other[0] > 0 ? TERM_L_GREEN : TERM_ORANGE);

	if (!terse) {	
	    textblock_append(tb, "It gives ");
	    if (dummy) textblock_append(tb, "up to ");
	}

	/* Bonuses */
	for (j = 0; j < MAX_P_BONUS; j++) {
	    if (o_ptr->bonus_other[j] == 0)
		continue;
	    attr = (o_ptr->bonus_other[j] > 0 ? TERM_L_GREEN : TERM_ORANGE);
	    textblock_append_c(tb, attr, "%d ", o_ptr->bonus_other[j]);
	    if (!terse) textblock_append(tb, "to your ");
	    textblock_append_c(tb, attr, othername[j]);
	    if (count >= (terse ? 2 : 3))
		textblock_append(tb, ", ");
	    if ((count == 2) && !terse)
		textblock_append(tb, " and ");
	    if (count == 1)
		textblock_append(tb, ". ");
	    count--;
	}
	
	textblock_append(tb, "\n");
	return TRUE;
    }
	
    return FALSE;
}
Beispiel #5
0
/**
 * Describe combat advantages.
 */
static bool describe_combat(textblock *tb, const struct object *obj)
{
	struct object *bow = equipped_item_by_slot_name(player, "shooting");
	bool weapon = tval_is_melee_weapon(obj);
	bool ammo   = (player->state.ammo_tval == obj->tval) && (bow);

	int range, break_chance;
	bool impactful, thrown_effect, too_heavy;

	obj_known_misc_combat(obj, &thrown_effect, &range, &impactful,
						  &break_chance, &too_heavy);

	if (!weapon && !ammo) {
		if (thrown_effect) {
			textblock_append(tb, "It can be thrown at creatures with damaging effect.\n");
			return true;
		} else
			return false;
	}

	textblock_append_c(tb, COLOUR_L_WHITE, "Combat info:\n");

	if (too_heavy)
		textblock_append_c(tb, COLOUR_L_RED, "You are too weak to use this weapon.\n");

	describe_blows(tb, obj);

	if (!weapon) { /* Ammo */
		textblock_append(tb, "Hits targets up to ");
		textblock_append_c(tb, COLOUR_L_GREEN, format("%d", range));
		textblock_append(tb, " feet away.\n");
	}

	describe_damage(tb, obj);

	if (impactful)
		textblock_append(tb, "Sometimes creates earthquakes on impact.\n");

	if (ammo) {
		textblock_append_c(tb, COLOUR_L_GREEN, "%d%%", break_chance);
		textblock_append(tb, " chance of breaking upon contact.\n");
	}

	/* Something has been said */
	return true;
}
Beispiel #6
0
/**
 * Describe objects that can be used for digging.
 */
static bool describe_digger(textblock *tb, const struct object *obj)
{
	int i;
	int deciturns[DIGGING_MAX];
	struct object *obj1 = (struct object *) obj;
	static const char *names[4] = { "rubble", "magma veins", "quartz veins",
									"granite" };

	/* Get useful info or print nothing */
	if (!obj_known_digging(obj1, deciturns)) return false;

	for (i = DIGGING_RUBBLE; i < DIGGING_DOORS; i++) {
		if (i == 0 && deciturns[0] > 0) {
			if (tval_is_melee_weapon(obj))
				textblock_append(tb, "Clears ");
			else
				textblock_append(tb, "With this item, your current weapon clears ");
		}

		if (i == 3 || (i != 0 && deciturns[i] == 0))
			textblock_append(tb, "and ");

		if (deciturns[i] == 0) {
			textblock_append_c(tb, COLOUR_L_RED, "doesn't affect ");
			textblock_append(tb, "%s.\n", names[i]);
			break;
		}

		textblock_append(tb, "%s in ", names[i]);

		if (deciturns[i] == 10) {
			textblock_append_c(tb, COLOUR_L_GREEN, "1 ");
		} else if (deciturns[i] < 100) {
			textblock_append_c(tb, COLOUR_GREEN, "%d.%d ", deciturns[i]/10,
							   deciturns[i]%10);
		} else {
			textblock_append_c(tb, (deciturns[i] < 1000) ? COLOUR_YELLOW :
							   COLOUR_RED, "%d ", (deciturns[i]+5)/10);
		}

		textblock_append(tb, "turn%s%s", deciturns[i] == 10 ? "" : "s",
				(i == 3) ? ".\n" : ", ");
	}

	return true;
}
Beispiel #7
0
/*
 * Describe stat modifications.
 */
static bool describe_stats(textblock *tb, const object_type *o_ptr,
		bitflag flags[MAX_PVALS][OF_SIZE], oinfo_detail_t mode)
{
	const char *descs[N_ELEMENTS(pval_flags)];
	size_t count, i;
	bool full = mode & OINFO_FULL;
	bool dummy = mode & OINFO_DUMMY;
	bool search = FALSE;

	if (!o_ptr->num_pvals && !dummy)
		return FALSE;

	for (i = 0; i < o_ptr->num_pvals; i++) {
		count = info_collect(tb, pval_flags, N_ELEMENTS(pval_flags), flags[i], descs);

		if (count)
		{
			if ((object_this_pval_is_visible(o_ptr, i) || full) && !dummy)
				textblock_append_c(tb, (o_ptr->pval[i] > 0) ? TERM_L_GREEN : TERM_RED,
					"%+i ", o_ptr->pval[i]);
			else
				textblock_append(tb, "Affects your ");

			info_out_list(tb, descs, count);
		}
		if (of_has(flags[i], OF_SEARCH))
			search = TRUE;
	}

	if (search)
	{
		if ((object_this_pval_is_visible(o_ptr, which_pval(o_ptr, OF_SEARCH)) || full) && !dummy)
		{
			textblock_append_c(tb, (o_ptr->pval[which_pval(o_ptr, OF_SEARCH)] > 0) ? TERM_L_GREEN : TERM_RED,
				"%+i%% ", o_ptr->pval[which_pval(o_ptr, OF_SEARCH)] * 5);
			textblock_append(tb, "to searching.\n");
		}
		else if (count)
			textblock_append(tb, "Also affects your searching skill.\n");
		else
			textblock_append(tb, "Affects your searching skill.\n");
	}

	return TRUE;
}
Beispiel #8
0
/*
 * Describe things that look like lights.
 */
static bool describe_light(textblock * tb, const object_type * o_ptr,
						   bool terse)
{
	int rad = 0;

	bool artifact = artifact_p(o_ptr);
	bool is_light = (o_ptr->tval == TV_LIGHT) ? TRUE : FALSE;

	if (o_ptr->tval != TV_LIGHT && !of_has(o_ptr->flags_obj, OF_LIGHT))
		return FALSE;

	/* Work out radius */
	if (artifact && is_light)
		rad = 3;
	else if (is_light)
		rad = 2;
	if (of_has(o_ptr->flags_obj, OF_LIGHT))
		rad++;

	/* Describe here */
	if (!terse)
		textblock_append(tb, "It provides radius ");
	else
		textblock_append(tb, "Radius ");
	textblock_append_c(tb, TERM_L_GREEN, format("%d", rad));
	if (artifact)
		textblock_append(tb, " light forever.");
	else
		textblock_append(tb, " light.");

	if (!terse && is_light && !artifact) {
		const char *name =
			(o_ptr->sval == SV_LIGHT_TORCH) ? "torches" : "lanterns";
		int turns =
			(o_ptr->sval == SV_LIGHT_TORCH) ? FUEL_TORCH : FUEL_LAMP;

		textblock_append(tb, "  Refills other %s up to %d turns of fuel. ",
						 name, turns);
	}

	textblock_append(tb, "\n");

	return TRUE;
}
Beispiel #9
0
/**
 * Describe stat modifications.
 */
static bool describe_stats(textblock *tb, const struct object *obj,
						   oinfo_detail_t mode)
{
	size_t count = 0, i;
	bool detail = false;

	/* Don't give exact plusses for faked ego items as each real one will
	 * be different */
	bool suppress_details = mode & (OINFO_EGO | OINFO_FAKE) ? true : false;

	/* Fact of but not size of mods is known for egos and flavoured items
	 * the player is aware of */
	bool known_effect = false;
	if (obj->known->ego)
		known_effect = true;
	if (tval_can_have_flavor_k(obj->kind) && object_flavor_is_aware(obj))
		known_effect = true;

	/* See what we've got */
	for (i = 0; i < OBJ_MOD_MAX; i++)
		if (obj->known->modifiers[i]) {
			count++;
			detail = true;
		}

	if (!count)
		return false;

	for (i = 0; i < OBJ_MOD_MAX; i++) {
		const char *desc = lookup_obj_property(OBJ_PROPERTY_MOD, i)->name;
		int val = obj->known->modifiers[i];
		if (!val) continue;

		/* Actual object */
		if (detail && !suppress_details) {
			int attr = (val > 0) ? COLOUR_L_GREEN : COLOUR_RED;
			textblock_append_c(tb, attr, "%+i %s.\n", val, desc);
		} else if (known_effect)
			/* Ego type or jewellery description */
			textblock_append(tb, "Affects your %s\n", desc);
	}

	return true;
}
Beispiel #10
0
/**
 * Describe stat modifications.
 */
static bool describe_stats(textblock *tb, const struct object *obj,
						   oinfo_detail_t mode)
{
	size_t count = 0, i;
	bool detail = false;

	/* Don't give exact plusses for faked ego items as each real one will
	 * be different */
	bool suppress_details = mode & OINFO_EGO ? true : false;

	/* Fact of but not size of mods is known for egos and flavoured items
	 * the player is aware of */
	bool known_effect = false;
	if (object_ego_is_visible(obj))
		known_effect = true;
	if (tval_can_have_flavor_k(obj->kind) && object_flavor_is_aware(obj))
		known_effect = true;

	/* See what we've got */
	for (i = 0; i < N_ELEMENTS(mod_flags); i++)
		if (obj->modifiers[mod_flags[i].flag] != 0 && mod_flags[i].name[0]) {
			count++;
			/* Either all mods are visible, or none are */
			if (object_this_mod_is_visible(obj, mod_flags[i].flag))
				detail = true;
		}

	if (!count)
		return false;

	for (i = 0; i < N_ELEMENTS(mod_flags); i++) {
		const char *desc = mod_flags[i].name;
		int val = obj->modifiers[mod_flags[i].flag];
		if (!val) continue;
		if (!mod_flags[i].name[0]) continue;
		if (detail && !suppress_details) {
			int attr = (val > 0) ? COLOUR_L_GREEN : COLOUR_RED;
			textblock_append_c(tb, attr, "%+i %s.\n", val, desc);
		} else if (known_effect)
			textblock_append(tb, "Affects your %s\n", desc);
	}

	return true;
}
Beispiel #11
0
/*
 * Describe things that look like lights.
 */
static bool describe_light(textblock *tb, const object_type *o_ptr,
		const bitflag flags[OF_SIZE], bool terse)
{
	int rad = 0;

	bool artifact = o_ptr->artifact;
	bool no_fuel = of_has(flags, OF_NO_FUEL) ? TRUE : FALSE;
	bool is_light = (o_ptr->tval == TV_LIGHT) ? TRUE : FALSE;

	if (o_ptr->tval != TV_LIGHT && !of_has(flags, OF_LIGHT))
		return FALSE;

	/* Work out radius */
	if (artifact && is_light)
		rad = 3;
	else if (is_light)
		rad = 2;
	if (of_has(flags, OF_LIGHT))
		rad++;

	/* Describe here */
	textblock_append(tb, "Radius ");
	textblock_append_c(tb, TERM_L_GREEN, format("%d", rad));
	if (no_fuel && !artifact)
		textblock_append(tb, " light.  No fuel required.");
	else if (is_light && o_ptr->sval == SV_LIGHT_TORCH)
		textblock_append(tb, " light, reduced when running out of fuel.");
	else
		textblock_append(tb, " light.");

	if (!terse && is_light && !no_fuel)
	{
		const char *name = (o_ptr->sval == SV_LIGHT_TORCH) ? "torches" : "lanterns";
		int turns = (o_ptr->sval == SV_LIGHT_TORCH) ? FUEL_TORCH : FUEL_LAMP;

		textblock_append(tb, "  Refills other %s up to %d turns of fuel.", name, turns);
	}

	textblock_append(tb, "\n");

	return TRUE;
}
Beispiel #12
0
/**
 * Allow the standard list formatted to be bypassed for special cases.
 *
 * Returning TRUE will bypass any other formatteding in
 * monster_list_format_textblock().
 *
 * \param list is the monster list to format.
 * \param tb is the textblock to produce or NULL if only the dimensions need to
 * be calculated.
 * \param max_lines is the maximum number of lines that can be displayed.
 * \param max_width is the maximum line width that can be displayed.
 * \param max_height_result is returned with the number of lines needed to
 * format the list without truncation.
 * \param max_width_result is returned with the width needed to format the list
 * without truncation.
 * \return TRUE if further formatting should be bypassed.
 */
static bool monster_list_format_special(const monster_list_t *list, textblock *tb, int max_lines, int max_width, size_t *max_height_result, size_t *max_width_result)
{
	if (player->timed[TMD_IMAGE] > 0) {
		/* Hack - message needs newline to calculate width properly. */
		const char *message = "Your hallucinations are too wild to see things clearly.\n";

		if (max_height_result != NULL)
			*max_height_result = 1;

		if (max_width_result != NULL)
			*max_width_result = strlen(message);

		if (tb != NULL)
			textblock_append_c(tb, COLOUR_ORANGE, "%s", message);

		return TRUE;
	}

	return FALSE;
}
Beispiel #13
0
/**
 * Describe an item's curses.
 */
static bool describe_curses(textblock *tb, const struct object *obj,
		const bitflag flags[OF_SIZE])
{
	int i;
	struct curse_data *c = obj->known->curses;

	if (!c)
		return false;
	for (i = 1; i < z_info->curse_max; i++) {
		if (c[i].power) {
			textblock_append(tb, "It ");
			textblock_append_c(tb, COLOUR_L_RED, curses[i].desc);
			if (c[i].power == 100) {
				textblock_append(tb, "; this curse cannot be removed");
			}
			textblock_append(tb, ".\n");
		}
	}

	return true;
}
Beispiel #14
0
/*
 * Describe brands.
 */
static bool describe_brands(textblock * tb, const object_type * o_ptr,
							oinfo_detail_t mode)
{
	int j, brand = 0;
	bool full = mode & OINFO_FULL;
	bool terse = mode & OINFO_TERSE;
	byte attr = TERM_L_UMBER;

	for (j = 0; j < MAX_P_BRAND; j++)
		if (if_has(o_ptr->id_other, OBJECT_ID_BASE_BRAND + j) ||
			(full && (o_ptr->multiple_brand[j] > MULTIPLE_BASE)))
			brand++;

	if (brand > 0) {
		if (terse)
			textblock_append(tb, "Branded with ");
		else
			textblock_append(tb, "It does extra damage from ");

		/* Brands */
		for (j = 0; j < MAX_P_BRAND; j++) {
			if (!if_has(o_ptr->id_other, OBJECT_ID_BASE_BRAND + j) &&
				!(full && (o_ptr->multiple_brand[j] > MULTIPLE_BASE)))
				continue;
			textblock_append_c(tb, attr, brandee[j]);
			if (brand >= 3)
				textblock_append(tb, ", ");
			if (brand == 2)
				textblock_append(tb, " and ");
			if (brand == 1)
				textblock_append(tb, ". ");
			brand--;
		}

		textblock_append(tb, "\n");
		return TRUE;
	}

	return FALSE;
}
Beispiel #15
0
/**
 * Describe stat modifications.
 */
static bool describe_stats(textblock *tb, const struct object *obj,
						   oinfo_detail_t mode)
{
	size_t count = 0, i;
	bool detail = FALSE;

	/* Don't give exact pluses for faked ego items as each real one 
	   will be different */
	bool suppress_details = mode & OINFO_EGO ? TRUE : FALSE;

	/* See what we've got */
	for (i = 0; i < N_ELEMENTS(mod_flags); i++)
		if (obj->modifiers[mod_flags[i].flag] != 0 &&	mod_flags[i].name[0]) {
			count++;
			/* Either all mods are visible, or none are */
			if (object_this_mod_is_visible(obj, i))
				detail = TRUE;
		}
	
	if (!count)
		return FALSE;
	
	for (i = 0; i < N_ELEMENTS(mod_flags); i++) {
		const char *desc = mod_flags[i].name;
		int val = obj->modifiers[mod_flags[i].flag];
		if (!val) continue;
		if (!mod_flags[i].name[0]) continue;
		if (detail && !suppress_details) {
			int attr = (val > 0) ? COLOUR_L_GREEN : COLOUR_RED;
			textblock_append_c(tb, attr, "%+i %s.\n", val, desc);
		} 
		else
			textblock_append(tb, "Affects your %s\n", desc);
	}

	return TRUE;
}
Beispiel #16
0
/**
 * Describes a food item
 */
static bool describe_food(textblock *tb, const struct object *obj,
		bool subjective)
{
	int nourishment = obj_known_food(obj);

	if (nourishment) {
		/* Sometimes adjust for player speed */
		int multiplier = turn_energy(player->state.speed);
		if (!subjective) multiplier = 10;

		if (nourishment == OBJ_KNOWN_PRESENT) {
			textblock_append(tb, "Provides some nourishment.\n");
		} else {
			textblock_append(tb, "Nourishes for around ");
			textblock_append_c(tb, COLOUR_L_GREEN, "%d", nourishment *
				multiplier / 10);
			textblock_append(tb, " turns.\n");
		}

		return TRUE;
	}

	return FALSE;
}
Beispiel #17
0
/*
 * Describe stat modifications.
 */
static bool describe_stats(textblock * tb, const object_type * o_ptr,
						   oinfo_detail_t mode)
{
	int j, min = 0, max = 0, count = 0;
	bool full = mode & OINFO_FULL;
	bool dummy = mode & OINFO_DUMMY;
	bool terse = mode & OINFO_TERSE;

	if (((o_ptr->ident) & IDENT_WORN) || dummy || full) {
		for (j = 0; j < A_MAX; j++) {
			if (o_ptr->bonus_stat[j] != 0)
				count++;
			if (o_ptr->bonus_stat[j] < min)
				min = o_ptr->bonus_stat[j];
			if (o_ptr->bonus_stat[j] > max)
				max = o_ptr->bonus_stat[j];
		}
	}

	if (count > 0) {
		byte attr =
			(o_ptr->bonus_stat[A_STR] > 0 ? TERM_L_GREEN : TERM_ORANGE);

		if (!terse) {
			textblock_append(tb, "It gives ");
			if (dummy)
				textblock_append(tb, "up to ");
		}

		/* Special case: all stats */
		if (min == max)
			textblock_append_c(tb, attr, "%d to all your stats. ", min);

		/* Some stats */
		else {
			for (j = 0; j < A_MAX; j++) {
				if (o_ptr->bonus_stat[j] == 0)
					continue;
				attr =
					(o_ptr->bonus_stat[j] >
					 0 ? TERM_L_GREEN : TERM_ORANGE);
				textblock_append_c(tb, attr, "%d ", o_ptr->bonus_stat[j]);
				if (!terse)
					textblock_append(tb, "to your ");
				textblock_append_c(tb, attr, statname[j]);
				if (count >= (terse ? 2 : 3))
					textblock_append(tb, ", ");
				if ((count == 2) && !terse)
					textblock_append(tb, " and ");
				if (count == 1)
					textblock_append(tb, ". ");
				count--;
			}
		}

		textblock_append(tb, "\n");
		return TRUE;
	}

	return FALSE;
}
Beispiel #18
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 #19
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 #20
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 #21
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;
}
Beispiel #22
0
/**
 * Format a section of the monster list: a header followed by monster list
 * entry rows.
 *
 * This function will process each entry for the given section. It will display:
 * - monster char;
 * - number of monsters;
 * - monster name (truncated, if needed to fit the line);
 * - whether or not the monster is asleep (and how many if in a group);
 * - monster distance from the player (aligned to the right side of the list).
 * By passing in a NULL textblock, the maximum line width of the section can be
 * found.
 *
 * \param list is the monster list to format.
 * \param tb is the textblock to produce or NULL if only the dimensions need to
 * be calculated.
 * \param section is the section of the monster list to format.
 * \param lines_to_display are the number of entries to display (not including
 * the header).
 * \param max_width is the maximum line width.
 * \param prefix is the beginning of the header; the remainder is appended with
 * the number of monsters.
 * \param show_others is used to append "other monsters" to the header,
 * after the number of monsters.
 * \param max_width_result is returned with the width needed to format the list
 * without truncation.
 */
static void monster_list_format_section(const monster_list_t *list, textblock *tb, monster_list_section_t section, int lines_to_display, int max_width, const char *prefix, bool show_others, size_t *max_width_result)
{
	int remaining_monster_total = 0;
	int line_count = 0;
	int index;
	int total;
	char line_buffer[200];
	const char *punctuation = (lines_to_display == 0) ? "." : ":";
	const char *others = (show_others) ? "other " : "";
	size_t max_line_length = 0;

	if (list == NULL || list->entries == NULL)
		return;

	total = list->distinct_entries;

	if (list->total_monsters[section] == 0) {
		max_line_length = strnfmt(line_buffer, sizeof(line_buffer),
								  "%s no monsters.\n", prefix);

		if (tb != NULL)
			textblock_append(tb, "%s", line_buffer);

		/* Force a minimum width so that the prompt doesn't get cut off. */
		if (max_width_result != NULL)
			*max_width_result = MAX(max_line_length, 40);

		return;
	}

	max_line_length = strnfmt(line_buffer, sizeof(line_buffer),
							  "%s %d %smonster%s%s\n",
							  prefix,
							  list->total_monsters[section],
							  others,
							  PLURAL(list->total_monsters[section]),
							  punctuation);

	if (tb != NULL)
		textblock_append(tb, "%s", line_buffer);

	for (index = 0; index < total && line_count < lines_to_display; index++) {
		char asleep[20] = { '\0' };
		char location[20] = { '\0' };
		byte line_attr;
		size_t full_width;
		size_t name_width;

		line_buffer[0] = '\0';

		if (list->entries[index].count[section] == 0)
			continue;

		/* Only display directions for the case of a single monster. */
		if (list->entries[index].count[section] == 1) {
			const char *direction1 = (list->entries[index].dy <= 0) ? "N" : "S";
			const char *direction2 = (list->entries[index].dx <= 0) ? "W" : "E";
			strnfmt(location, sizeof(location), " %d %s %d %s",
					abs(list->entries[index].dy), direction1,
					abs(list->entries[index].dx), direction2);
		}

		/* Get width available for monster name and sleep tag: 2 for char and
		 * space; location includes padding; last -1 for some reason? */
		full_width = max_width - 2 - utf8_strlen(location) - 1;

		if (list->entries[index].asleep[section] > 1)
			strnfmt(asleep, sizeof(asleep), " (%d asleep)",
					list->entries[index].asleep[section]);
		else if (list->entries[index].asleep[section] == 1)
			strnfmt(asleep, sizeof(asleep), " (asleep)");

		/* Clip the monster name to fit, and append the sleep tag. */
		name_width = MIN(full_width - utf8_strlen(asleep), sizeof(line_buffer));
		get_mon_name(line_buffer, sizeof(line_buffer),
					 list->entries[index].race,
					 list->entries[index].count[section]);
		utf8_clipto(line_buffer, name_width);
		my_strcat(line_buffer, asleep, sizeof(line_buffer));

		/* Calculate the width of the line for dynamic sizing; use a fixed max
		 * width for location and monster char. */
		max_line_length = MAX(max_line_length,
							  utf8_strlen(line_buffer) + 12 + 2);

		/* textblock_append_pict will safely add the monster symbol,
		 * regardless of ASCII/graphics mode. */
		if (tb != NULL && tile_width == 1 && tile_height == 1) {
			textblock_append_pict(tb, list->entries[index].attr, monster_x_char[list->entries[index].race->ridx]);
			textblock_append(tb, " ");
		}

		/* Add the left-aligned and padded monster name which will align the
		 * location to the right. */
		if (tb != NULL) {
			/* Hack - Because monster race strings are UTF8, we have to add
			 * additional padding for any raw bytes that might be consolidated
			 * into one displayed character. */
			full_width += strlen(line_buffer) - utf8_strlen(line_buffer);
			line_attr = monster_list_entry_line_color(&list->entries[index]);
			textblock_append_c(tb, line_attr, "%-*s%s\n",
							   full_width,
							   line_buffer, location);
		}

		line_count++;
	}

	/* Don't worry about the "...others" line, since it's probably shorter
	 * than what's already printed. */
	if (max_width_result != NULL)
		*max_width_result = max_line_length;

	/* Bail since we don't have enough room to display the remaining count or
	 * since we've displayed them all. */
	if (lines_to_display <= 0 ||
		lines_to_display >= list->total_entries[section])
		return;

	/* Sum the remaining monsters; start where we left off in the above loop. */
	while (index < total) {
		remaining_monster_total += list->entries[index].count[section];
		index++;
	}

	if (tb != NULL)
		textblock_append(tb, "%6s...and %d others.\n", " ",
						 remaining_monster_total);
}
Beispiel #23
0
/*
 * Describe blows.
 */
static bool describe_blows(textblock *tb, const object_type *o_ptr,
		player_state state, bitflag f[OF_SIZE])
{
	int str_plus, dex_plus, old_blows = 0, new_blows, extra_blows;
	int str_faster = -1, str_done = -1;
	int dex_plus_bound;
	int str_plus_bound;
	int i;

	bitflag tmp_f[OF_SIZE];

	dex_plus_bound = STAT_RANGE - state.stat_ind[A_DEX];
	str_plus_bound = STAT_RANGE - state.stat_ind[A_STR];

	/* Write to the text block */
	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;
		}
	}

	return TRUE;
}
Beispiel #24
0
/**
 * Describe damage.
 */
static bool describe_damage(textblock *tb, const struct object *obj)
{
	bool nonweap_slay = false;
	int normal_damage;
	struct brand *brand, *brands = NULL;
	struct slay *slay, *slays = NULL;
	bool has_brands_or_slays;

	/* Collect brands and slays */
	has_brands_or_slays = obj_known_damage(obj, &normal_damage, &brands, &slays,
										   &nonweap_slay);

	/* Mention slays and brands from other items */
	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: ");

	/* Output damage for creatures effected by the brands */
	brand = brands;
	while (brand) {
		if (brand->damage <= 0)
			textblock_append_c(tb, COLOUR_L_RED, "%d", 0);
		else if (brand->damage % 10)
			textblock_append_c(tb, COLOUR_L_GREEN, "%d.%d",
							   brand->damage / 10, brand->damage % 10);
		else
			textblock_append_c(tb, COLOUR_L_GREEN, "%d",brand->damage / 10);

		textblock_append(tb, " vs. creatures not resistant to %s, ",
						 brand->name);
		brand = brand->next;
	}

	/* Output damage for creatures effected by the slays */
	slay = slays;
	while (slay) {
		if (slay->damage <= 0)
			textblock_append_c(tb, COLOUR_L_RED, "%d", 0);
		else if (slay->damage % 10)
			textblock_append_c(tb, COLOUR_L_GREEN, "%d.%d",
							   slay->damage / 10, slay->damage % 10);
		else
			textblock_append_c(tb, COLOUR_L_GREEN, "%d", slay->damage / 10);

		textblock_append(tb, " vs. %s, ", slay->name);
		slay = slay->next;
	}

	if (has_brands_or_slays) textblock_append(tb, "and ");

	if (normal_damage <= 0)
		textblock_append_c(tb, COLOUR_L_RED, "%d", 0);
	else if (normal_damage % 10)
		textblock_append_c(tb, COLOUR_L_GREEN, "%d.%d",
			   normal_damage / 10, normal_damage % 10);
	else
		textblock_append_c(tb, COLOUR_L_GREEN, "%d", normal_damage / 10);

	if (has_brands_or_slays) textblock_append(tb, " vs. others");
	textblock_append(tb, ".\n");

	free_brand(brands);
	free_slay(slays);
	return true;
}
Beispiel #25
0
/**
 * Outputs the damage we do/would do with the weapon
 */
static bool describe_weapon_damage(textblock * tb,
								   const object_type * o_ptr,
								   oinfo_detail_t mode)
{
	object_type *i_ptr;
	int i, j;

	bool full = mode & OINFO_FULL;
	bool terse = mode & OINFO_TERSE;
	bool first = TRUE;
	int show_m_tohit;
	int brand[MAX_P_BRAND], slay[MAX_P_SLAY];

	player_state state;
	object_type inven[INVEN_TOTAL];

	/* Abort if we've nothing to say */
	if (mode & OINFO_DUMMY)
		return FALSE;

	/* Extract the slays and brands */
	for (j = 0; j < MAX_P_SLAY; j++)
		slay[j] = (if_has(o_ptr->id_other, OBJECT_ID_BASE_SLAY + j)
				   || full)
			? o_ptr->multiple_slay[j] : MULTIPLE_BASE;
	for (j = 0; j < MAX_P_BRAND; j++)
		brand[j] = (if_has(o_ptr->id_other, OBJECT_ID_BASE_BRAND + j)
					|| full)
			? o_ptr->multiple_brand[j] : MULTIPLE_BASE;

	/* Check rings for additional brands (slays) */
	for (i = 0; i < 2; i++) {
		i_ptr = &p_ptr->inventory[INVEN_LEFT + i];

		/* If wearing a ring */
		if (i_ptr->k_idx) {
			/* Pick up any brands (and slays!) */
			for (j = 0; j < MAX_P_SLAY; j++)
				slay[j] =
					MAX(slay[j],
						((if_has(i_ptr->id_other, OBJECT_ID_BASE_SLAY + j)
						  || full)
						 ? i_ptr->multiple_slay[j] : MULTIPLE_BASE));
			for (j = 0; j < MAX_P_BRAND; j++)
				brand[j] =
					MAX(brand[j],
						((if_has(i_ptr->id_other, OBJECT_ID_BASE_BRAND + j)
						  || full)
						 ? i_ptr->multiple_brand[j] : MULTIPLE_BASE));

		}
	}

	/* temporary elemental brands */
	if (p_ptr->special_attack & (ATTACK_ACID))
		brand[P_BRAND_ACID] = MAX(brand[P_BRAND_ACID], BRAND_BOOST_NORMAL);
	if (p_ptr->special_attack & (ATTACK_ELEC))
		brand[P_BRAND_ELEC] = MAX(brand[P_BRAND_ELEC], BRAND_BOOST_NORMAL);
	if (p_ptr->special_attack & (ATTACK_FIRE))
		brand[P_BRAND_FIRE] = MAX(brand[P_BRAND_FIRE], BRAND_BOOST_NORMAL);
	if (p_ptr->special_attack & (ATTACK_COLD))
		brand[P_BRAND_COLD] = MAX(brand[P_BRAND_COLD], BRAND_BOOST_NORMAL);
	if (p_ptr->special_attack & (ATTACK_POIS))
		brand[P_BRAND_POIS] = MAX(brand[P_BRAND_POIS], BRAND_BOOST_NORMAL);
	if (p_ptr->special_attack & (ATTACK_HOLY))
		slay[P_SLAY_EVIL] = MAX(slay[P_SLAY_EVIL], SLAY_BOOST_SMALL);

	/*
	 * Get the player's hypothetical state, were they to be
	 * wielding this item (setting irrelevant shield state).
	 */
	memcpy(inven, p_ptr->inventory, INVEN_TOTAL * sizeof(object_type));
	inven[INVEN_WIELD] = *o_ptr;
	state.shield_on_back = FALSE;

	calc_bonuses(inven, &state, TRUE);

	show_m_tohit = state.dis_to_h;
	if (if_has(o_ptr->id_other, IF_TO_H) || full)
		show_m_tohit += o_ptr->to_h;

	if (terse) {
		textblock_append_c(tb, TERM_L_GREEN, "%d ", state.num_blow);
		textblock_append(tb, "blow%s av. dam. ",
						 (state.num_blow) ? "s" : "");
	} else {
		textblock_append(tb, "\nWielding it you would have ");
		textblock_append_c(tb, TERM_L_GREEN, "%d ", state.num_blow);
		textblock_append(tb,
						 "blow%s and do an average damage per blow of ",
						 (state.num_blow) ? "s" : "");
	}

	for (i = 0; i < MAX_P_SLAY; i++) {
		if (slay[i] > MULTIPLE_BASE)
			output_dam(tb, &state, o_ptr, slay[i], slayee[i], &first,
					   mode);
	}

	for (i = 0; i < MAX_P_BRAND; i++) {
		if (brand[i] > MULTIPLE_BASE) {
			char buf[40];

			strnfmt(buf, sizeof(buf), "non %s resistant creatures",
					brandee[i]);
			output_dam(tb, &state, o_ptr, brand[i], buf, &first, mode);
		}
	}

	output_dam(tb, &state, o_ptr, MULTIPLE_BASE,
			   (first) ? "all monsters" : "other monsters", &first, mode);

	if (terse) {
		textblock_append(tb, ".  + ");
		textblock_append_c(tb, TERM_L_GREEN, "%d", show_m_tohit);
		textblock_append(tb, " to skill. ");
	} else {
		textblock_append(tb, ".  Your + to Skill would be ");
		textblock_append_c(tb, TERM_L_GREEN, "%d", show_m_tohit);
		textblock_append(tb, ". ");
	}

	return TRUE;
}
Beispiel #26
0
/*
 * Describe immunities granted by an object.
 */
static bool describe_immune(textblock * tb, const object_type * o_ptr,
							oinfo_detail_t mode)
{
	int res = 0, imm = 0, vul = 0, j;

	bool full = mode & OINFO_FULL;
	bool dummy = mode & OINFO_DUMMY;
	bool terse = mode & OINFO_TERSE;
	bool prev = FALSE;

	/* Check for resists and vulnerabilities */
	for (j = 0; j < MAX_P_RES; j++) {
		if (!if_has(o_ptr->id_other, OBJECT_ID_BASE_RESIST + j) && !full)
			continue;
		if (o_ptr->percent_res[j] == RES_BOOST_IMMUNE)
			imm++;
		else if (o_ptr->percent_res[j] < RES_LEVEL_BASE) {
			res++;
		} else if (o_ptr->percent_res[j] > RES_LEVEL_BASE)
			vul++;
	}

	/* Immunities */
	if (imm) {
		textblock_append(tb, "Provides ");
		textblock_append_c(tb, TERM_BLUE, "immunity ");
		textblock_append(tb, "to ");

		/* Loop for number of attributes in this group. */
		for (j = 0; j < 4; j++) {
			if (o_ptr->percent_res[j] > RES_BOOST_IMMUNE)
				continue;
			if (!if_has(o_ptr->id_other, OBJECT_ID_BASE_RESIST + j)
				&& !full)
				continue;

			/* List the attribute description, in its proper place. */
			if (terse)
				textblock_append(tb, resists[j].name);
			else
				textblock_append_c(tb, resists[j].attr, resists[j].name);
			if (imm >= (terse ? 2 : 3))
				textblock_append(tb, ", ");
			if ((imm == 2) && !terse)
				textblock_append(tb, " and ");
			imm--;
		}

		/* End sentence. */
		textblock_append(tb, ". ");
		prev = TRUE;
	}

	/* Resistances */
	if (res) {
		textblock_append(tb, "Provides ");
		textblock_append_c(tb, TERM_L_BLUE, "resistance ");
		textblock_append(tb, "to ");

		/* Loop for number of attributes in this group. */
		for (j = 0; j < MAX_P_RES; j++) {
			if (o_ptr->percent_res[j] >= RES_LEVEL_BASE)
				continue;
			if (o_ptr->percent_res[j] == RES_BOOST_IMMUNE)
				continue;
			if (!if_has(o_ptr->id_other, OBJECT_ID_BASE_RESIST + j)
				&& !full)
				continue;

			/* List the attribute description, in its proper place. */
			if (terse)
				textblock_append(tb, resists[j].name);
			else
				textblock_append_c(tb, resists[j].attr, resists[j].name);
			textblock_append(tb, "(");
			if (dummy)
				textblock_append(tb, "about ");
			textblock_append(tb, "%d%%)",
							 RES_LEVEL_BASE - o_ptr->percent_res[j]);
			if (res >= (terse ? 2 : 3))
				textblock_append(tb, ", ");
			if ((res == 2) && !terse)
				textblock_append(tb, " and ");
			res--;
		}

		/* End sentence. */
		textblock_append(tb, ". ");
		prev = TRUE;
	}

	/* Vulnerabilities */
	if (vul) {
		textblock_append(tb, "Makes you ");
		textblock_append_c(tb, TERM_ORANGE, "vulnerable ");
		textblock_append(tb, "to ");

		/* Loop for number of attributes in this group. */
		for (j = 0; j < MAX_P_RES; j++) {
			if (o_ptr->percent_res[j] <= RES_LEVEL_BASE)
				continue;
			if (!if_has(o_ptr->id_other, OBJECT_ID_BASE_RESIST + j))
				continue;

			/* List the attribute description, in its proper place. */
			if (terse)
				textblock_append(tb, resists[j].name);
			else
				textblock_append_c(tb, resists[j].attr, resists[j].name);
			textblock_append(tb, "(");
			if (dummy)
				textblock_append(tb, "about ");
			textblock_append(tb, "%d%%)",
							 o_ptr->percent_res[j] - RES_LEVEL_BASE);
			if (vul >= (terse ? 2 : 3))
				textblock_append(tb, ", ");
			if ((vul == 2) && !terse)
				textblock_append(tb, " and ");
			vul--;
		}

		/* End sentence. */
		textblock_append(tb, ". ");
		prev = TRUE;
	}

	return prev;
}
Beispiel #27
0
/**
 * Display the ammo damage done with a multiplier
 */
static void output_ammo_dam(textblock * tb, player_state * state,
							const object_type * o_ptr, int mult,
							const char *against, bool * first,
							bool perfect, oinfo_detail_t mode)
{
	object_type *b_ptr = &p_ptr->inventory[INVEN_BOW];

	int dam, die_average, add = 0, i, deadliness, crit, chance, dice =
		o_ptr->dd;

	/* Throwing weapon, or launched missile? */
	bool thrown = !is_missile(o_ptr);
	bool full = mode & OINFO_FULL;

	/* Average damage for one standard side (x10) */
	die_average = (10 * (o_ptr->ds + 1)) / 2;

	/* Apply the launcher multiplier. */
	if (!thrown)
		die_average *= p_ptr->state.ammo_mult;

	/* Multiply by slay or brand (x10) */
	die_average *= mult;

	/* Record the addend */
	if (mult > 10)
		add = (mult - 10);

	/* Multiply by deadliness (x100) */
	deadliness = state->dis_to_d;
	if (if_has(o_ptr->id_other, IF_TO_D) || full)
		deadliness += o_ptr->to_d;
	if (if_has(b_ptr->id_other, IF_TO_D) || full)
		deadliness += b_ptr->to_d;
	if (deadliness > 150)
		deadliness = 150;
	if (deadliness < -150)
		deadliness = -150;
	if (deadliness >= 0)
		die_average *= (100 + deadliness_conversion[deadliness]);
	else {
		i = deadliness_conversion[ABS(deadliness)];
		if (i >= 100)
			die_average = 0;
		else
			die_average *= (100 - i);
	}

	/* Get critical chance (x 10) */
	chance = state->skills[SKILL_TO_HIT_BOW] + state->dis_to_h;
	if (if_has(o_ptr->id_other, IF_TO_H) || full)
		chance += o_ptr->to_h;
	if ((!thrown) && (if_has(b_ptr->id_other, IF_TO_H) || full))
		chance += b_ptr->to_h;
	if (thrown)
		chance = chance * 3 / 2;
	chance = (100 * chance) / (chance + 360);
	if (player_has(PF_MARKSMAN))
		chance = 100 - (83 * (100 - chance)) / 100;
	crit = 116 * chance;
	crit /= 1000;

	/* Increase dice */
	if (thrown && perfect)
		dice *= 2;
	dice = dice * 10 + crit;
	if (thrown)
		dice *= 2 + p_ptr->lev / 12;

	/* Multiply by number of sides */
	dam = die_average * dice;

	CHECK_FIRST("", *first);
	if ((dam > 50000) || (add > 0))
		textblock_append_c(tb, TERM_L_GREEN, "%d", add + dam / 100000);
	else
		textblock_append_c(tb, TERM_L_RED, "0");
	textblock_append(tb, " against %s", against);
}
Beispiel #28
0
/*
 * Describe an object's effect, if any.
 */
static bool describe_effect(textblock * tb, const object_type * o_ptr,
							oinfo_detail_t mode)
{
	const object_kind *k_ptr = &k_info[o_ptr->k_idx];
	const char *desc;
	random_value timeout = { 0, 0, 0, 0 };
	bool full = mode & OINFO_FULL;
	bool subjective = mode & OINFO_SUBJ;
	bool terse = mode & OINFO_TERSE;

	int effect = 0, fail;

	if (wearable_p(o_ptr)) {
		/* Wearable + effect <=> activates */
		if ((o_ptr->ident & IDENT_WORN) || full) {
			effect = o_ptr->effect;
			timeout = o_ptr->time;
		} else if (object_effect(o_ptr)) {
			textblock_append(tb, "It can be activated.\n");
			return TRUE;
		}
	} else {
		/* Sometimes only print activation info */
		if (terse)
			return FALSE;

		if ((object_aware_p(o_ptr)
			 && kf_has(k_ptr->flags_kind, KF_EASY_KNOW))
			|| full) {
			effect = o_ptr->effect;
			timeout = o_ptr->time;
		} else if (object_effect(o_ptr)) {
			if (effect_aim(k_ptr->effect))
				textblock_append(tb, "It can be aimed.\n");
			else if (o_ptr->tval == TV_FOOD)
				textblock_append(tb, "It can be eaten.\n");
			else if (o_ptr->tval == TV_POTION)
				textblock_append(tb, "It can be drunk.\n");
			else if (o_ptr->tval == TV_SCROLL)
				textblock_append(tb, "It can be read.\n");
			else
				textblock_append(tb, "It can be activated.\n");

			return TRUE;
		}
	}

	/* Forget it without an effect */
	if (!effect)
		return FALSE;

	/* Obtain the description */
	desc = effect_desc(effect);
	if (!desc)
		return FALSE;

	if (effect_aim(effect))
		textblock_append(tb, "When aimed, it ");
	else if (o_ptr->tval == TV_FOOD)
		textblock_append(tb, "When eaten, it ");
	else if (o_ptr->tval == TV_POTION)
		textblock_append(tb, "When drunk, it ");
	else if (o_ptr->tval == TV_SCROLL)
		textblock_append(tb, "When read, it ");
	else
		textblock_append(tb, "When activated, it ");

	/* Print a colourised description */
	do {
		if (isdigit((unsigned char) *desc))
			textblock_append_c(tb, TERM_L_GREEN, "%c", *desc);
		else
			textblock_append(tb, "%c", *desc);
	} while (*desc++);

	textblock_append(tb, ".\n");

	if (randcalc(timeout, 0, MAXIMISE) > 0) {
		int min_time, max_time;

		/* Sometimes adjust for player speed */
		int multiplier = extract_energy[p_ptr->state.pspeed];
		if (!subjective)
			multiplier = 10;

		textblock_append(tb, "Takes ");

		/* Correct for player speed */
		min_time = randcalc(timeout, 0, MINIMISE) * multiplier / 10;
		max_time = randcalc(timeout, 0, MAXIMISE) * multiplier / 10;

		textblock_append_c(tb, TERM_L_GREEN, "%d", min_time);

		if (min_time != max_time) {
			textblock_append(tb, " to ");
			textblock_append_c(tb, TERM_L_GREEN, "%d", max_time);
		}

		textblock_append(tb, " turns to recharge");
		if (subjective && p_ptr->state.pspeed != 110)
			textblock_append(tb, " at your current speed");

		textblock_append(tb, ".\n");
	}

	if (!subjective || o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION
		|| o_ptr->tval == TV_SCROLL) {
		return TRUE;
	} else {
		fail = get_use_device_chance(o_ptr);
		textblock_append(tb, "Your chance of success is %d.%d%%\n",
						 (1000 - fail) / 10, (1000 - fail) % 10);
	}

	return TRUE;
}
Beispiel #29
0
/*
 * Describe an object's effect, if any.
 */
static bool describe_effect(textblock *tb, const object_type *o_ptr, bool full,
		bool only_artifacts, bool subjective)
{
	const char *desc;
	random_value timeout = {0, 0, 0, 0};

	int effect = 0, fail;

	if (o_ptr->artifact)
	{
		if (object_effect_is_known(o_ptr) || full)
		{
			effect = o_ptr->artifact->effect;
			timeout = o_ptr->artifact->time;
		}
		else if (object_effect(o_ptr))
		{
			textblock_append(tb, "It can be activated.\n");
			return TRUE;
		}
	}
	else
	{
		/* Sometimes only print artifact activation info */
		if (only_artifacts == TRUE) return FALSE;

		if (object_effect_is_known(o_ptr) || full)
		{
			effect = o_ptr->kind->effect;
			timeout = o_ptr->kind->time;
		}
		else if (object_effect(o_ptr) != 0)
		{
			if (effect_aim(o_ptr->kind->effect))
				textblock_append(tb, "It can be aimed.\n");
			else if (o_ptr->tval == TV_FOOD)
				textblock_append(tb, "It can be eaten.\n");
			else if (o_ptr->tval == TV_POTION)
				textblock_append(tb, "It can be drunk.\n");
			else if (o_ptr->tval == TV_SCROLL)
				textblock_append(tb, "It can be read.\n");
			else textblock_append(tb, "It can be activated.\n");

			return TRUE;
		}
	}

	/* Forget it without an effect */
	if (!effect) return FALSE;

	/* Obtain the description */
	desc = effect_desc(effect);
	if (!desc) return FALSE;

	if (effect_aim(effect))
		textblock_append(tb, "When aimed, it ");
	else if (o_ptr->tval == TV_FOOD)
		textblock_append(tb, "When eaten, it ");
	else if (o_ptr->tval == TV_POTION)
		textblock_append(tb, "When drunk, it ");
	else if (o_ptr->tval == TV_SCROLL)
	    textblock_append(tb, "When read, it ");
	else
	    textblock_append(tb, "When activated, it ");

	/* Print a colourised description */
	do
	{
		if (isdigit((unsigned char) *desc))
			textblock_append_c(tb, TERM_L_GREEN, "%c", *desc);
		else
			textblock_append(tb, "%c", *desc);
	} while (*desc++);

	textblock_append(tb, ".\n");

	if (randcalc(timeout, 0, MAXIMISE) > 0)
	{
		int min_time, max_time;

		/* Sometimes adjust for player speed */
		int multiplier = extract_energy[p_ptr->state.speed];
		if (!subjective) multiplier = 10;

		textblock_append(tb, "Takes ");

		/* Correct for player speed */
		min_time = randcalc(timeout, 0, MINIMISE) * multiplier / 10;
		max_time = randcalc(timeout, 0, MAXIMISE) * multiplier / 10;

		textblock_append_c(tb, TERM_L_GREEN, "%d", min_time);

		if (min_time != max_time)
		{
			textblock_append(tb, " to ");
			textblock_append_c(tb, TERM_L_GREEN, "%d", max_time);
		}

		textblock_append(tb, " turns to recharge");
		if (subjective && p_ptr->state.speed != 110)
			textblock_append(tb, " at your current speed");

		textblock_append(tb, ".\n");
	}

	if (!subjective || o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION ||
		o_ptr->tval == TV_SCROLL)
	{
		return TRUE;
	}
	else
	{
		fail = get_use_device_chance(o_ptr);
		textblock_append(tb, "Your chance of success is %d.%d%%\n", (1000 - fail) /
			10, (1000 - fail) % 10);
	}

	return TRUE;
}
Beispiel #30
0
/*
 * Describe slays.
 */
static bool describe_slays(textblock * tb, const object_type * o_ptr,
						   oinfo_detail_t mode)
{
	int j, slay = 0, kill = 0;
	bool full = mode & OINFO_FULL;
	bool terse = mode & OINFO_TERSE;
	byte attr = TERM_RED;

	for (j = 0; j < MAX_P_SLAY; j++)
		if (if_has(o_ptr->id_other, OBJECT_ID_BASE_SLAY + j) ||
			(full && (o_ptr->multiple_slay[j] > MULTIPLE_BASE))) {
			slay++;

			/* Hack for great banes */
			if ((j == P_SLAY_ANIMAL)
				&& (o_ptr->multiple_slay[j] > SLAY_BOOST_MINOR)) {
				slay--;
				kill++;
			}
			if ((j == P_SLAY_EVIL)
				&& (o_ptr->multiple_slay[j] > SLAY_BOOST_SMALL)) {
				slay--;
				kill++;
			}
			if ((j > P_SLAY_EVIL)
				&& (o_ptr->multiple_slay[j] > SLAY_BOOST_NORMAL)) {
				slay--;
				kill++;
			}
		}

	if (!slay && !kill)
		return FALSE;

	if (slay > 0) {
		textblock_append(tb, "It slays ");

		/* Slays */
		for (j = 0; j < MAX_P_SLAY; j++) {
			if (!if_has(o_ptr->id_other, OBJECT_ID_BASE_SLAY + j) &&
				!(full && (o_ptr->multiple_slay[j] > MULTIPLE_BASE)))
				continue;
			if ((j == P_SLAY_ANIMAL) &&
				(o_ptr->multiple_slay[j] > SLAY_BOOST_MINOR))
				continue;
			if ((j == P_SLAY_EVIL) &&
				(o_ptr->multiple_slay[j] > SLAY_BOOST_SMALL))
				continue;
			if ((j > P_SLAY_EVIL) &&
				(o_ptr->multiple_slay[j] > SLAY_BOOST_NORMAL))
				continue;
			textblock_append_c(tb, attr, slayee[j]);
			if (slay >= 3)
				textblock_append(tb, ", ");
			if (slay == 2)
				textblock_append(tb, " and ");
			if (slay == 1)
				textblock_append(tb, ". ");
			slay--;
		}
	}

	if (kill > 0) {
		if (terse)
			textblock_append(tb, "Great bane of ");
		else
			textblock_append(tb, "It is a great bane of ");

		/* Great banes */
		for (j = 0; j < MAX_P_SLAY; j++) {
			if (!if_has(o_ptr->id_other, OBJECT_ID_BASE_SLAY + j) &&
				!(full && (o_ptr->multiple_slay[j] > MULTIPLE_BASE)))
				continue;
			if ((j == P_SLAY_ANIMAL) &&
				(o_ptr->multiple_slay[j] <= SLAY_BOOST_MINOR))
				continue;
			if ((j == P_SLAY_EVIL) &&
				(o_ptr->multiple_slay[j] <= SLAY_BOOST_SMALL))
				continue;
			if ((j > P_SLAY_EVIL) &&
				(o_ptr->multiple_slay[j] <= SLAY_BOOST_NORMAL))
				continue;
			textblock_append_c(tb, attr, slayee[j]);
			if (slay >= 3)
				textblock_append(tb, ", ");
			if (slay == 2)
				textblock_append(tb, " and ");
			if (slay == 1)
				textblock_append(tb, ". ");
			slay--;
		}
	}

	textblock_append(tb, "\n");
	return TRUE;
}