Beispiel #1
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 #2
0
/**
 * Gets miscellaneous combat information about the given object.
 *
 * Fills in whether there is a special effect when thrown in `thrown effect`,
 * the `range` in ft (or zero if not ammo), whether the weapon has the 
 * impact flag set, the percentage chance of breakage and whether it is
 * too heavy to be weilded effectively at the moment.
 */
static void obj_known_misc_combat(const struct object *obj, bool *thrown_effect, int *range, bool *impactful, int *break_chance, bool *too_heavy)
{
	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);
	bitflag f[OF_SIZE];

	*thrown_effect = *impactful = *too_heavy = false;
	*range = *break_chance = 0;

	get_known_flags(obj, 0, f);

	if (!weapon && !ammo) {
		/* Potions can have special text */
		if (tval_is_potion(obj) && obj->dd != 0 && obj->ds != 0 &&
			object_flavor_is_aware(obj))
			*thrown_effect = true;
	}

	if (ammo)
		*range = 10 * MIN(6 + 2 * player->state.ammo_mult, z_info->max_range);

	/* Note the impact flag */
	*impactful = of_has(f, OF_IMPACT);

	/* Add breakage chance */
	*break_chance = breakage_chance(obj, true);

	/* Is the weapon too heavy? */
	if (weapon) {
		struct player_state state;
		int weapon_slot = slot_by_name(player, "weapon");
		struct object *current = equipped_item_by_slot_name(player, "weapon");

		/* Pretend we're wielding the object */
		player->body.slots[weapon_slot].obj = (struct object *) obj;

		/* Calculate the player's hypothetical state */
		calc_bonuses(player, &state, true, false);

		/* Stop pretending */
		player->body.slots[weapon_slot].obj = current;

		/* Warn about heavy weapons */
		*too_heavy = state.heavy_wield;
	}
}
Beispiel #3
0
/**
 * Gets miscellaneous combat information about the given object.
 *
 * Fills in whether there is a special effect when thrown in `thrown effect`,
 * the `range` in ft (or zero if not ammo), the percentage chance of breakage
 * and whether it is too heavy to be wielded effectively at the moment.
 */
static void obj_known_misc_combat(const struct object *obj, bool *thrown_effect,
								  int *range, int *break_chance, bool *heavy)
{
	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);

	*thrown_effect = *heavy = false;
	*range = *break_chance = 0;

	if (!weapon && !ammo) {
		/* Potions can have special text */
		if (tval_is_potion(obj) && obj->dd != 0 && obj->ds != 0 &&
			object_flavor_is_aware(obj))
			*thrown_effect = true;
	}

	if (ammo)
		*range = 10 * MIN(6 + 2 * player->state.ammo_mult, z_info->max_range);

	/* Add breakage chance */
	*break_chance = breakage_chance(obj, true);

	/* Is the weapon too heavy? */
	if (weapon) {
		struct player_state state;
		int weapon_slot = slot_by_name(player, "weapon");
		struct object *current = equipped_item_by_slot_name(player, "weapon");

		/* Pretend we're wielding the object */
		player->body.slots[weapon_slot].obj = (struct object *) 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[weapon_slot].obj = current;

		/* Warn about heavy weapons */
		*heavy = state.heavy_wield;
	}
}
Beispiel #4
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 #5
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 #6
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 #7
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 #8
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 #9
0
/**
 * Gets information about the average damage/turn that can be inflicted if
 * the player wields the given weapon.
 *
 * Fills in the damage against normal adversaries in `normal_damage`, as well
 * as the slays on the weapon in slay_list[] and corresponding damages in 
 * slay_damage[].  These must both be at least SL_MAX long to be safe.
 * `nonweap_slay` is set to whether other items being worn could add to the
 * damage done by branding attacks.
 *
 * Returns the number of slays populated in slay_list[] and slay_damage[].
 *
 * Note that the results are meaningless if called on a fake ego object as
 * the actual ego may have different properties.
 */
static bool obj_known_damage(const struct object *obj, int *normal_damage,
							struct brand **brand_list, struct slay **slay_list,
							bool *nonweap_slay)
{
	int i;
	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;
	struct brand *brand;
	struct slay *slay;

	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 multiplier = 1;

	struct player_state state;
	int weapon_slot = slot_by_name(player, "weapon");
	struct object *current_weapon = slot_object(player, weapon_slot);

	/* Pretend we're wielding the object if it's a weapon */
	if (weapon)
		player->body.slots[weapon_slot].obj = (struct object *) obj;

	/* Calculate the player's hypothetical state */
	calc_bonuses(player, &state, true, false);

	/* Stop pretending */
	player->body.slots[weapon_slot].obj = current_weapon;

	/* Use displayed dice if real dice not known */
	if (object_attack_plusses_are_visible(obj)) {
		dice = obj->dd;
		sides = obj->ds;
	} else {
		dice = obj->kind->dd;
		sides = obj->kind->ds;
	}

	/* Calculate damage */
	dam = ((sides + 1) * dice * 5);

	if (weapon)	{
		xtra_postcrit = state.to_d * 10;
		if (object_attack_plusses_are_visible(obj)) {
			xtra_precrit += obj->to_d * 10;
			plus += obj->to_h;
		}

		calculate_melee_crits(&state, obj->weight, plus,
				&crit_mult, &crit_add, &crit_div);

		old_blows = state.num_blows;
	} else { /* Ammo */
		if (object_attack_plusses_are_visible(obj))
			plus += obj->to_h;

		calculate_missile_crits(&player->state, obj->weight, plus,
				&crit_mult, &crit_add, &crit_div);

		if (object_attack_plusses_are_visible(obj))
			dam += (obj->to_d * 10);
		if (object_attack_plusses_are_visible(bow))
			dam += (bow->to_d * 10);
	}

	if (ammo) multiplier = player->state.ammo_mult;

	/* Get the brands */
	*brand_list = brand_collect(obj->known->brands, ammo ? bow->known : NULL);

	/* Get the slays */
	*slay_list = slay_collect(obj->known->slays, ammo ? bow->known : NULL);

	/* Melee weapons may get slays and brands from other items */
	*nonweap_slay = false;
	if (weapon)	{
		for (i = 2; i < player->body.count; i++) {
			struct object *slot_obj = slot_object(player, i);
			struct brand *new_brand;
			struct slay *new_slay;
			if (!slot_obj)
				continue;

			if (slot_obj->known->brands || slot_obj->known->slays)
				*nonweap_slay = true;
			else
				continue;

			/* Replace the old lists with new ones */
			new_brand = brand_collect(*brand_list, slot_obj->known);
			new_slay = slay_collect(*slay_list, slot_obj->known);
			free_brand(*brand_list);
			free_slay(*slay_list);
			*brand_list = new_brand;
			*slay_list = new_slay;
		}
	}

	/* Get damage for each brand on the objects */
	for (brand = *brand_list; brand; brand = brand->next) {
		/* 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 + brand->multiplier
						   - 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 *= player->state.num_shots;

		brand->damage = total_dam;
	}

	/* Get damage for each slay on the objects */
	for (slay = *slay_list; slay; slay = slay->next) {
		/* 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 + slay->multiplier
						   - 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 *= player->state.num_shots;

		slay->damage = total_dam;
	}

	/* 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 *= player->state.num_shots;

	*normal_damage = total_dam;

	return (*slay_list || *brand_list);
}
Beispiel #10
0
/**
 * Gets information about the number of blows possible for the player with
 * the given object.
 *
 * Fills in whether the object is too_heavy to wield effectively,
 * and the possible_blows[] information of .str_plus and .dex_plus needed
 * to achieve the approximate number of blows in centiblows. 
 *
 * `max_blows` must be at least 1 to hold the current number of blows
 * `possible_blows` must be at least [`max_blows`] in size, and will be limited
 * to that number of entries.  The theoretical maximum is STAT_RANGE * 2 if
 * an extra blow/speed boost was given for each combination of STR and DEX.
 *
 * Returns the number of entries made in the possible_blows[] table, or 0
 * if the object is not a weapon.
 *
 * Note that the results are meaningless if called on a fake ego object as
 * the actual ego may have different properties.
 */
static int obj_known_blows(const struct object *obj, int max_num,
						   struct blow_info possible_blows[])
{
	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;

	struct player_state state;

	int weapon_slot = slot_by_name(player, "weapon");
	struct object *current_weapon = slot_object(player, weapon_slot);
	int num = 0;

	/* Not a weapon - no blows! */
	if (!tval_is_melee_weapon(obj)) return 0;

	/* Pretend we're wielding the object */
	player->body.slots[weapon_slot].obj = (struct object *) obj;

	/* Calculate the player's hypothetical state */
	calc_bonuses(player, &state, true, false);

	/* Stop pretending */
	player->body.slots[weapon_slot].obj = current_weapon;

	/* First entry is always the current num of blows. */
	possible_blows[num].str_plus = 0;
	possible_blows[num].dex_plus = 0;
	possible_blows[num].centiblows = state.num_blows;
	num++;

	/* Check to see if extra STR or DEX would yield extra blows */
	old_blows = state.num_blows;
	extra_blows = 0;

	/* Start with blows from the weapon being examined */
	if (object_this_mod_is_visible(obj, OBJ_MOD_BLOWS))
		extra_blows += obj->modifiers[OBJ_MOD_BLOWS];

	/* Then we need to look for extra blows on other items, as
	 * state does not track these */
	for (i = 0; i < player->body.count; i++) {
		struct object *helper = slot_object(player, i);

		if ((i == slot_by_name(player, "weapon")) || !helper || !helper->kind)
			continue;

		if (object_this_mod_is_visible(helper, OBJ_MOD_BLOWS))
			extra_blows += helper->modifiers[OBJ_MOD_BLOWS];
	}

	dex_plus_bound = STAT_RANGE - state.stat_ind[STAT_DEX];
	str_plus_bound = STAT_RANGE - state.stat_ind[STAT_STR];

	/* 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++) {
			if (num == max_num)
				return num;

			state.stat_ind[STAT_STR] += str_plus;
			state.stat_ind[STAT_DEX] += dex_plus;
			new_blows = calc_blows(player, obj, &state, extra_blows);
			state.stat_ind[STAT_STR] -= str_plus;
			state.stat_ind[STAT_DEX] -= dex_plus;

			/* 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)) {
				possible_blows[num].str_plus = str_plus;
				possible_blows[num].dex_plus = dex_plus;
				possible_blows[num].centiblows = new_blows / 10;
				possible_blows[num].centiblows *= 10;
				num++;

				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)) {
				possible_blows[num].str_plus = str_plus;
				possible_blows[num].dex_plus = dex_plus;
				possible_blows[num].centiblows = new_blows;
				num++;

				str_faster = str_plus;
			}
		}
	}

	return num;
}
Beispiel #11
0
/*
 * Handle "p_ptr->update"
 */
void update_stuff(void)
{
	/* Update stuff */
	if (!p_ptr->update) return;


	if (p_ptr->update & (PU_BODY))
	{
		p_ptr->update &= ~(PU_BODY);
		calc_body();
	}

	if (p_ptr->update & (PU_BONUS))
	{
		p_ptr->update &= ~(PU_BONUS);
		calc_bonuses(FALSE);
	}

	if (p_ptr->update & (PU_TORCH))
	{
		p_ptr->update &= ~(PU_TORCH);
		calc_torch();
	}

	if (p_ptr->update & (PU_HP))
	{
		p_ptr->update &= ~(PU_HP);
		call_lua("player.calc_hitpoints", "()", "");
	}

	if (p_ptr->update & (PU_SANITY))
	{
		p_ptr->update &= ~(PU_SANITY);
		call_lua("player.calc_sanity", "()", "");
	}

	if (p_ptr->update & (PU_MANA))
	{
		p_ptr->update &= ~(PU_MANA);
		call_lua("player.calc_mana", "()", "");
	}

	/* Character is not ready yet, no screen updates */
	if (!character_generated) return;


	/* Character is in "icky" mode, no screen updates */
	if (character_icky) return;


	if (p_ptr->update & (PU_UN_VIEW))
	{
		p_ptr->update &= ~(PU_UN_VIEW);
		forget_view();
	}

	if (p_ptr->update & (PU_VIEW))
	{
		p_ptr->update &= ~(PU_VIEW);
		update_view();
	}

	if (p_ptr->update & (PU_DISTANCE))
	{
		p_ptr->update &= ~(PU_DISTANCE);
		p_ptr->update &= ~(PU_MONSTERS);
		update_monsters(TRUE);
	}

	if (p_ptr->update & (PU_MONSTERS))
	{
		p_ptr->update &= ~(PU_MONSTERS);
		update_monsters(FALSE);
	}

	if (p_ptr->update & (PU_MON_LITE))
	{
		p_ptr->update &= ~(PU_MON_LITE);
		if (monster_lite) update_mon_lite();
	}
}
Beispiel #12
0
/*
 * Calculate bonuses, and print various things on changes.
 */
static void update_bonuses(void)
{
	int i;

	player_state *state = &p_ptr->state;
	player_state old = p_ptr->state;


	/*** Calculate bonuses ***/

	calc_bonuses(inventory, &p_ptr->state, FALSE);


	/*** Notice changes ***/

	/* Analyze stats */
	for (i = 0; i < A_MAX; i++)
	{
		/* Notice changes */
		if (state->stat_top[i] != old.stat_top[i])
		{
			/* Redisplay the stats later */
			p_ptr->redraw |= (PR_STATS);
		}

		/* Notice changes */
		if (state->stat_use[i] != old.stat_use[i])
		{
			/* Redisplay the stats later */
			p_ptr->redraw |= (PR_STATS);
		}

		/* Notice changes */
		if (state->stat_ind[i] != old.stat_ind[i])
		{
			/* Change in CON affects Hitpoints */
			if (i == A_CON)
			{
				p_ptr->update |= (PU_HP);
			}

			/* Change in INT may affect Mana/Spells */
			else if (i == A_INT)
			{
				if (cp_ptr->spell_stat == A_INT)
				{
					p_ptr->update |= (PU_MANA | PU_SPELLS);
				}
			}

			/* Change in WIS may affect Mana/Spells */
			else if (i == A_WIS)
			{
				if (cp_ptr->spell_stat == A_WIS)
				{
					p_ptr->update |= (PU_MANA | PU_SPELLS);
				}
			}
		}
	}


	/* Hack -- Telepathy Change */
	if (state->telepathy != old.telepathy)
	{
		/* Update monster visibility */
		p_ptr->update |= (PU_MONSTERS);
	}

	/* Hack -- See Invis Change */
	if (state->see_inv != old.see_inv)
	{
		/* Update monster visibility */
		p_ptr->update |= (PU_MONSTERS);
	}

	/* Redraw speed (if needed) */
	if (state->speed != old.speed)
	{
		/* Redraw speed */
		p_ptr->redraw |= (PR_SPEED);
	}

	/* Redraw armor (if needed) */
	if ((state->dis_ac != old.dis_ac) || (state->dis_to_a != old.dis_to_a))
	{
		/* Redraw */
		p_ptr->redraw |= (PR_ARMOR);
	}

	/* Hack -- handle "xtra" mode */
	if (character_xtra) return;

	/* Take note when "heavy bow" changes */
	if (old.heavy_shoot != state->heavy_shoot)
	{
		/* Message */
		if (state->heavy_shoot)
		{
			msg_print("You have trouble wielding such a heavy bow.");
		}
		else if (inventory[INVEN_BOW].k_idx)
		{
			msg_print("You have no trouble wielding your bow.");
		}
		else
		{
			msg_print("You feel relieved to put down your heavy bow.");
		}
	}

	/* Take note when "heavy weapon" changes */
	if (old.heavy_wield != state->heavy_wield)
	{
		/* Message */
		if (state->heavy_wield)
		{
			msg_print("You have trouble wielding such a heavy weapon.");
		}
		else if (inventory[INVEN_WIELD].k_idx)
		{
			msg_print("You have no trouble wielding your weapon.");
		}
		else
		{
			msg_print("You feel relieved to put down your heavy weapon.");	
		}
	}

	/* Take note when "illegal weapon" changes */
	if (old.icky_wield != state->icky_wield)
	{
		/* Message */
		if (state->icky_wield)
		{
			msg_print("You do not feel comfortable with your weapon.");
		}
		else if (inventory[INVEN_WIELD].k_idx)
		{
			msg_print("You feel comfortable with your weapon.");
		}
		else
		{
			msg_print("You feel more comfortable after removing your weapon.");
		}
	}
}
Beispiel #13
0
/* Scrolls for the reading				-RAK-	*/
void read_scroll()
{
  int32u i;
  int j, k, item_val, y, x;
  int tmp[6], flag, used_up;
  bigvtype out_val, tmp_str;
  register int ident, l;
  register inven_type *i_ptr;
  register struct misc *m_ptr;

  free_turn_flag = TRUE;
  if (py.flags.blind > 0)
    msg_print("You can't see to read the scroll.");
  else if (no_light())
    msg_print("You have no light to read by.");
  else if (py.flags.confused > 0)
    msg_print("You are too confused to read a scroll.");
  else if (inven_ctr == 0)
    msg_print("You are not carrying anything!");
  else if (!find_range(TV_SCROLL1, TV_SCROLL2, &j, &k))
    msg_print ("You are not carrying any scrolls!");
  else if (get_item(&item_val, "Read which scroll?", j, k, 0))
    {
      i_ptr = &inventory[item_val];
      free_turn_flag = FALSE;
      used_up = TRUE;
      i = i_ptr->flags;
      ident = FALSE;

      while (i != 0)
	{
	  j = bit_pos(&i) + 1;
	  if (i_ptr->tval == TV_SCROLL2)
	    j += 32;

	  /* Scrolls.			*/
	  switch(j)
	    {
	    case 1:
	      i_ptr = &inventory[INVEN_WIELD];
	      if (i_ptr->tval != TV_NOTHING)
		{
		  objdes(tmp_str, i_ptr, FALSE);
		  (void) sprintf(out_val, "Your %s glows faintly!", tmp_str);
		  msg_print(out_val);
		  if (enchant(&i_ptr->tohit))
		    {
		      i_ptr->flags &= ~TR_CURSED;
		      calc_bonuses();
		    }
		  else
		    msg_print("The enchantment fails.");
		  ident = TRUE;
		}
	      break;
	    case 2:
	      i_ptr = &inventory[INVEN_WIELD];
	      if (i_ptr->tval != TV_NOTHING)
		{
		  objdes(tmp_str, i_ptr, FALSE);
		  (void) sprintf(out_val, "Your %s glows faintly!", tmp_str);
		  msg_print(out_val);
		  if (enchant(&i_ptr->todam))
		    {
		      i_ptr->flags &= ~TR_CURSED;
		      calc_bonuses ();
		    }
		  else
		    msg_print("The enchantment fails.");
		  ident = TRUE;
		}
	      break;
	    case 3:
	      k = 0;
	      l = 0;
	      if (inventory[INVEN_BODY].tval != TV_NOTHING)
		tmp[k++] = INVEN_BODY;
	      if (inventory[INVEN_ARM].tval != TV_NOTHING)
		tmp[k++] = INVEN_ARM;
	      if (inventory[INVEN_OUTER].tval != TV_NOTHING)
		tmp[k++] = INVEN_OUTER;
	      if (inventory[INVEN_HANDS].tval != TV_NOTHING)
		tmp[k++] = INVEN_HANDS;
	      if (inventory[INVEN_HEAD].tval != TV_NOTHING)
		tmp[k++] = INVEN_HEAD;
	      /* also enchant boots */
	      if (inventory[INVEN_FEET].tval != TV_NOTHING)
		tmp[k++] = INVEN_FEET;

	      if (k > 0)  l = tmp[randint(k)-1];
	      if (TR_CURSED & inventory[INVEN_BODY].flags)
		l = INVEN_BODY;
	      else if (TR_CURSED & inventory[INVEN_ARM].flags)
		l = INVEN_ARM;
	      else if (TR_CURSED & inventory[INVEN_OUTER].flags)
		l = INVEN_OUTER;
	      else if (TR_CURSED & inventory[INVEN_HEAD].flags)
		l = INVEN_HEAD;
	      else if (TR_CURSED & inventory[INVEN_HANDS].flags)
		l = INVEN_HANDS;
	      else if (TR_CURSED & inventory[INVEN_FEET].flags)
		l = INVEN_FEET;

	      if (l > 0)
		{
		  i_ptr = &inventory[l];
		  objdes(tmp_str, i_ptr, FALSE);
		  (void) sprintf(out_val, "Your %s glows faintly!", tmp_str);
		  msg_print(out_val);
		  if (enchant(&i_ptr->toac))
		    {
		      i_ptr->flags &= ~TR_CURSED;
		      calc_bonuses ();
		    }
		  else
		    msg_print("The enchantment fails.");
		  ident = TRUE;
		}
	      break;
	    case 4:
	      msg_print("This is an identify scroll.");
	      ident = TRUE;
	      used_up = ident_spell();

	      /* the identify may merge objects, causing the identify scroll
		 to move to a different place.	Check for that here. */
	      if (i_ptr->tval != TV_SCROLL1 || i_ptr->flags != 0x00000008)
		{
		  item_val--;
		  i_ptr = &inventory[item_val];
		  if (i_ptr->tval != TV_SCROLL1 || i_ptr->flags != 0x00000008)
		    {
		      msg_print("internal error with identify spell.");
		      msg_print("Please tell the wizard!");
		      return;
		    }
		}
	      break;
	    case 5:
	      if (remove_curse())
		{
		  msg_print("You feel as if someone is watching over you.");
		  ident = TRUE;
		}
	      break;
	    case 6:
	      ident = light_area(char_row, char_col);
	      break;
	    case 7:
	      for (k = 0; k < randint(3); k++)
		{
		  y = char_row;
		  x = char_col;
		  ident |= summon_monster(&y, &x, FALSE);
		}
	      break;
	    case 8:
	      teleport(10);
	      ident = TRUE;
	      break;
	    case 9:
	      teleport(100);
	      ident = TRUE;
	      break;
	    case 10:
	      (void) tele_level();
	      ident = TRUE;
	      break;
	    case 11:
	      if (py.flags.confuse_monster == 0)
		{
		  msg_print("Your hands begin to glow.");
		  py.flags.confuse_monster = TRUE;
		  ident = TRUE;
		}
	      break;
	    case 12:
	      ident = TRUE;
	      map_area();
	      break;
	    case 13:
	      ident = sleep_monsters1(char_row, char_col);
	      break;
	    case 14:
	      ident = TRUE;
	      warding_glyph();
	      break;
	    case 15:
	      ident = detect_treasure();
	      break;
	    case 16:
	      ident = detect_object();
	      break;
	    case 17:
	      ident = detect_trap();
	      break;
	    case 18:
	      ident = detect_sdoor();
	      break;
	    case 19:
	      msg_print("This is a mass genocide scroll.");
	      ident = mass_genocide(TRUE);
	      break;
	    case 20:
	      ident = detect_invisible();
	      break;
	    case 21:
	      ident = aggravate_monster(20);
	      if (ident)
		msg_print("There is a high pitched humming noise.");
	      break;
	    case 22:
	      ident = trap_creation();
	      break;
	    case 23:
	      ident = td_destroy();
	      break;
	    case 24:  /* Not Used , used to be door creation */
	      break;
	    case 25:
	      msg_print("This is a Recharge-Item scroll.");
	      ident = TRUE;
	      used_up = recharge(60);
	      break;
	    case 26:
	      msg_print("This is a genocide scroll.");
	      ident = genocide(TRUE);
	      break;
	    case 27:
	      ident = unlight_area(char_row, char_col);
	      break;
	    case 28:
	      ident = protect_evil();
	      break;
	    case 29:
	      ident = TRUE;
	      create_food();
	      break;
	    case 30:
	      ident = dispel_creature(UNDEAD, 60);
	      break;
	    case 31:
	      remove_all_curse();
	      ident = TRUE;
	      break;
	    case 33:
	      i_ptr = &inventory[INVEN_WIELD];
	      if (i_ptr->tval != TV_NOTHING)
		{
		  objdes(tmp_str, i_ptr, FALSE);
		  (void) sprintf(out_val, "Your %s glows brightly!", tmp_str);
		  msg_print(out_val);
		  flag = FALSE;
		  for (k = 0; k < randint(2); k++)
		    if (enchant(&i_ptr->tohit))
		      flag = TRUE;
		  for (k = 0; k < randint(2); k++)
		    if (enchant(&i_ptr->todam))
		      flag = TRUE;
		  if (flag)
		    {
		      i_ptr->flags &= ~TR_CURSED;
		      calc_bonuses ();
		    }
		  else
		    msg_print("The enchantment fails.");
		  ident = TRUE;
		}
	      break;
	    case 34:
	      i_ptr = &inventory[INVEN_WIELD];
	      if (i_ptr->tval != TV_NOTHING)
		{
		  objdes(tmp_str, i_ptr, FALSE);
		  (void)sprintf(out_val,"Your %s glows black, fades.",tmp_str);
		  msg_print(out_val);
		  unmagic_name(i_ptr);
		  i_ptr->tohit = -randint(5) - randint(5);
		  i_ptr->todam = -randint(5) - randint(5);
		  i_ptr->flags = TR_CURSED;
		  py_bonuses(i_ptr, -1);
		  calc_bonuses ();
		  ident = TRUE;
		}
	      break;
	    case 35:
	      k = 0;
	      l = 0;
	      if (inventory[INVEN_BODY].tval != TV_NOTHING)
		tmp[k++] = INVEN_BODY;
	      if (inventory[INVEN_ARM].tval != TV_NOTHING)
		tmp[k++] = INVEN_ARM;
	      if (inventory[INVEN_OUTER].tval != TV_NOTHING)
		tmp[k++] = INVEN_OUTER;
	      if (inventory[INVEN_HANDS].tval != TV_NOTHING)
		tmp[k++] = INVEN_HANDS;
	      if (inventory[INVEN_HEAD].tval != TV_NOTHING)
		tmp[k++] = INVEN_HEAD;
	      /* also enchant boots */
	      if (inventory[INVEN_FEET].tval != TV_NOTHING)
		tmp[k++] = INVEN_FEET;

	      if (k > 0)  l = tmp[randint(k)-1];
	      if (TR_CURSED & inventory[INVEN_BODY].flags)
		l = INVEN_BODY;
	      else if (TR_CURSED & inventory[INVEN_ARM].flags)
		l = INVEN_ARM;
	      else if (TR_CURSED & inventory[INVEN_OUTER].flags)
		l = INVEN_OUTER;
	      else if (TR_CURSED & inventory[INVEN_HEAD].flags)
		l = INVEN_HEAD;
	      else if (TR_CURSED & inventory[INVEN_HANDS].flags)
		l = INVEN_HANDS;
	      else if (TR_CURSED & inventory[INVEN_FEET].flags)
		l = INVEN_FEET;

	      if (l > 0)
		{
		  i_ptr = &inventory[l];
		  objdes(tmp_str, i_ptr, FALSE);
		  (void) sprintf(out_val,"Your %s glows brightly!", tmp_str);
		  msg_print(out_val);
		  flag = FALSE;
		  for (k = 0; k < randint(2) + 1; k++)
		    if (enchant(&i_ptr->toac))
		      flag = TRUE;
		  if (flag)
		    {
		      i_ptr->flags &= ~TR_CURSED;
		      calc_bonuses ();
		    }
		  else
		    msg_print("The enchantment fails.");
		  ident = TRUE;
		}
	      break;
	    case 36:
	      if ((inventory[INVEN_BODY].tval != TV_NOTHING)
		  && (randint(4) == 1))
		k = INVEN_BODY;
	      else if ((inventory[INVEN_ARM].tval != TV_NOTHING)
		       && (randint(3) ==1))
		k = INVEN_ARM;
	      else if ((inventory[INVEN_OUTER].tval != TV_NOTHING)
		       && (randint(3) ==1))
		k = INVEN_OUTER;
	      else if ((inventory[INVEN_HEAD].tval != TV_NOTHING)
		       && (randint(3) ==1))
		k = INVEN_HEAD;
	      else if ((inventory[INVEN_HANDS].tval != TV_NOTHING)
		       && (randint(3) ==1))
		k = INVEN_HANDS;
	      else if ((inventory[INVEN_FEET].tval != TV_NOTHING)
		       && (randint(3) ==1))
		k = INVEN_FEET;
	      else if (inventory[INVEN_BODY].tval != TV_NOTHING)
		k = INVEN_BODY;
	      else if (inventory[INVEN_ARM].tval != TV_NOTHING)
		k = INVEN_ARM;
	      else if (inventory[INVEN_OUTER].tval != TV_NOTHING)
		k = INVEN_OUTER;
	      else if (inventory[INVEN_HEAD].tval != TV_NOTHING)
		k = INVEN_HEAD;
	      else if (inventory[INVEN_HANDS].tval != TV_NOTHING)
		k = INVEN_HANDS;
	      else if (inventory[INVEN_FEET].tval != TV_NOTHING)
		k = INVEN_FEET;
	      else
		k = 0;

	      if (k > 0)
		{
		  i_ptr = &inventory[k];
		  objdes(tmp_str, i_ptr, FALSE);
		  (void)sprintf(out_val,"Your %s glows black, fades.",tmp_str);
		  msg_print(out_val);
		  unmagic_name(i_ptr);
		  i_ptr->flags = TR_CURSED;
		  i_ptr->toac = -randint(5) - randint(5);
		  calc_bonuses ();
		  ident = TRUE;
		}
	      break;
	    case 37:
	      ident = FALSE;
	      for (k = 0; k < randint(3); k++)
		{
		  y = char_row;
		  x = char_col;
		  ident |= summon_undead(&y, &x);
		}
	      break;
	    case 38:
	      ident = TRUE;
	      bless(randint(12)+6);
	      break;
	    case 39:
	      ident = TRUE;
	      bless(randint(24)+12);
	      break;
	    case 40:
	      ident = TRUE;
	      bless(randint(48)+24);
	      break;
	    case 41:
	      ident = TRUE;
	      if (py.flags.word_recall == 0)
		py.flags.word_recall = 25 + randint(30);
	      msg_print("The air about you becomes charged.");
	      break;
	    case 42:
	      destroy_area(char_row, char_col);
	      ident = TRUE;
	      break;
	    case 43:
	      place_special(char_row, char_col, SPECIAL);
	      prt_map();
	      break;
	    case 44:
	      special_random_object(char_row, char_col, 1);
	      prt_map();
	      break;
	    default:
	      msg_print("Internal error in scroll()");
	      break;
	    }
	  /* End of Scrolls.			       */
	}
      i_ptr = &inventory[item_val];
      if (ident)
	{
	  if (!known1_p(i_ptr))
	    {
	      m_ptr = &py.misc;
	      /* round half-way case up */
	      m_ptr->exp += (i_ptr->level +(m_ptr->lev >> 1)) / m_ptr->lev;
	      prt_experience();

	      identify(&item_val);
	      i_ptr = &inventory[item_val];
	    }
	}
Beispiel #14
0
/**
 * Gets information about the average damage/turn that can be inflicted if
 * the player wields the given weapon.
 *
 * Fills in the damage against normal adversaries in `normal_damage`, as well
 * as the slays on the weapon in slay_list[] and corresponding damages in 
 * slay_damage[].  These must both be at least SL_MAX long to be safe.
 * `nonweap_slay` is set to whether other items being worn could add to the
 * damage done by branding attacks.
 *
 * Returns the number of slays populated in slay_list[] and slay_damage[].
 *
 * Note that the results are meaningless if called on a fake ego object as
 * the actual ego may have different properties.
 */
static bool obj_known_damage(const struct object *obj, int *normal_damage,
							 int *brand_damage, int *slay_damage,
							 bool *nonweap_slay)
{
	int i;
	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;
	bool *total_brands;
	bool *total_slays;
	bool has_brands_or_slays = false;

	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 melee_adj_mult = ammo ? 0 : 1;
	int multiplier = 1;

	struct player_state state;
	int weapon_slot = slot_by_name(player, "weapon");
	struct object *current_weapon = slot_object(player, weapon_slot);

	/* Pretend we're wielding the object if it's a weapon */
	if (weapon)
		player->body.slots[weapon_slot].obj = (struct object *) 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[weapon_slot].obj = current_weapon;

	/* Finish if dice not known */
	dice = obj->known->dd;
	sides = obj->known->ds;
	if (!dice || !sides) return false;

	/* Calculate damage */
	dam = ((sides + 1) * dice * 5);

	if (weapon)	{
		xtra_postcrit = state.to_d * 10;
		xtra_precrit += obj->known->to_d * 10;
		plus += obj->known->to_h;

		calculate_melee_crits(&state, obj->weight, plus, &crit_mult, &crit_add,
							  &crit_div);

		old_blows = state.num_blows;
	} else { /* Ammo */
		plus += obj->known->to_h;

		calculate_missile_crits(&player->state, obj->weight, plus, &crit_mult,
								&crit_add, &crit_div);

		dam += (obj->known->to_d * 10);
		dam += (bow->known->to_d * 10);
	}

	if (ammo) multiplier = player->state.ammo_mult;

	/* Get the brands */
	total_brands = mem_zalloc(z_info->brand_max * sizeof(bool));
	copy_brands(&total_brands, obj->known->brands);
	if (ammo && bow->known)
		copy_brands(&total_brands, bow->known->brands);

	/* Get the slays */
	total_slays = mem_zalloc(z_info->slay_max * sizeof(bool));
	copy_slays(&total_slays, obj->known->slays);
	if (ammo && bow->known)
		copy_slays(&total_slays, bow->known->slays);

	/* Melee weapons may get slays and brands from other items */
	*nonweap_slay = false;
	if (weapon)	{
		for (i = 2; i < player->body.count; i++) {
			struct object *slot_obj = slot_object(player, i);
			if (!slot_obj)
				continue;

			if (slot_obj->known->brands || slot_obj->known->slays)
				*nonweap_slay = true;
			else
				continue;

			/* Replace the old lists with new ones */
			copy_brands(&total_brands, slot_obj->known->brands);
			copy_slays(&total_slays, slot_obj->known->slays);
		}
	}

	/* Get damage for each brand on the objects */
	for (i = 1; i < z_info->brand_max; i++) {
		/* Must have the brand */
		if (total_brands[i])
			has_brands_or_slays = true;
		else
			continue;

		/* Include bonus damage and brand in stated average */
		total_dam = dam * (multiplier + brands[i].multiplier - 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 *= player->state.num_shots;

		brand_damage[i] = total_dam;
	}

	/* Get damage for each slay on the objects */
	for (i = 1; i < z_info->slay_max; i++) {
		/* Must have the slay */
		if (total_slays[i])
			has_brands_or_slays = true;
		else
			continue;

		/* Include bonus damage and slay in stated average */
		total_dam = dam * (multiplier + slays[i].multiplier - 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 *= player->state.num_shots;

		slay_damage[i] = total_dam;
	}

	/* 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 *= player->state.num_shots;

	*normal_damage = total_dam;

	mem_free(total_brands);
	mem_free(total_slays);
	return has_brands_or_slays;
}
Beispiel #15
0
/**
 * Gets information about the number of blows possible for the player with
 * the given object.
 *
 * Fills in whether the object is too heavy to wield effectively,
 * and the possible_blows[] information of .str_plus and .dex_plus needed
 * to achieve the approximate number of blows in centiblows. 
 *
 * `max_blows` must be at least 1 to hold the current number of blows
 * `possible_blows` must be at least [`max_blows`] in size, and will be limited
 * to that number of entries.  The theoretical maximum is STAT_RANGE * 2 if
 * an extra blow/speed boost was given for each combination of STR and DEX.
 *
 * Returns the number of entries made in the possible_blows[] table, or 0
 * if the object is not a weapon.
 *
 * Note that the results are meaningless if called on a fake ego object as
 * the actual ego may have different properties.
 */
static int obj_known_blows(const struct object *obj, int max_num,
						   struct blow_info possible_blows[])
{
	int str_plus, dex_plus, old_blows = 0;
	int str_faster = -1, str_done = -1;
	int dex_plus_bound;
	int str_plus_bound;

	struct player_state state;

	int weapon_slot = slot_by_name(player, "weapon");
	struct object *current_weapon = slot_object(player, weapon_slot);
	int num = 0;

	/* Not a weapon - no blows! */
	if (!tval_is_melee_weapon(obj)) return 0;

	/* Pretend we're wielding the object */
	player->body.slots[weapon_slot].obj = (struct object *) 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);

	/* First entry is always the current num of blows. */
	possible_blows[num].str_plus = 0;
	possible_blows[num].dex_plus = 0;
	possible_blows[num].centiblows = state.num_blows;
	num++;

	/* Check to see if extra STR or DEX would yield extra blows */
	old_blows = state.num_blows;
	dex_plus_bound = STAT_RANGE - state.stat_ind[STAT_DEX];
	str_plus_bound = STAT_RANGE - state.stat_ind[STAT_STR];

	/* Re-calculate with increased stats */
	for (dex_plus = 0; dex_plus < dex_plus_bound; dex_plus++) {
		for (str_plus = 0; str_plus < str_plus_bound; str_plus++) {
			int new_blows = 0;

			/* Unlikely */
			if (num == max_num) {
				player->body.slots[weapon_slot].obj = current_weapon;
				return num;
			}

			state.stat_ind[STAT_STR] = str_plus; //Hack - NRM
			state.stat_ind[STAT_DEX] = dex_plus; //Hack - NRM
			calc_bonuses(player, &state, true, false);
			new_blows = state.num_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)) {
				possible_blows[num].str_plus = str_plus;
				possible_blows[num].dex_plus = dex_plus;
				possible_blows[num].centiblows = new_blows / 10;
				possible_blows[num].centiblows *= 10;
				num++;

				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)) {
				possible_blows[num].str_plus = str_plus;
				possible_blows[num].dex_plus = dex_plus;
				possible_blows[num].centiblows = new_blows;
				num++;

				str_faster = str_plus;
			}
		}
	}

	/* Stop pretending */
	player->body.slots[weapon_slot].obj = current_weapon;

	return num;
}