Пример #1
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;
}
Пример #2
0
static size_t obj_desc_combat(const object_type *o_ptr, char *buf, size_t max, 
		size_t end, bool spoil)
{
	bitflag flags[OF_SIZE];
	bitflag flags_known[OF_SIZE];

	object_flags(o_ptr, flags);
	object_flags_known(o_ptr, flags_known);

	if (of_has(flags, OF_SHOW_DICE)) {
		/* Only display the real damage dice if the combat stats are known */
		if (spoil || object_attack_plusses_are_visible(o_ptr))
			strnfcat(buf, max, &end, " (%dd%d)", o_ptr->dd, o_ptr->ds);
		else
			strnfcat(buf, max, &end, " (%dd%d)", o_ptr->kind->dd, o_ptr->kind->ds);
	}

	if (of_has(flags, OF_SHOW_MULT)) {
		/* Display shooting power as part of the multiplier */
		if (of_has(flags, OF_MIGHT) &&
		    (spoil || object_flag_is_known(o_ptr, OF_MIGHT)))
			strnfcat(buf, max, &end, " (x%d)", (o_ptr->sval % 10) + o_ptr->pval[which_pval(o_ptr, OF_MIGHT)]);
		else
			strnfcat(buf, max, &end, " (x%d)", o_ptr->sval % 10);
	}

	/* Show weapon bonuses */
	if (spoil || object_attack_plusses_are_visible(o_ptr)) {
		if (wield_slot(o_ptr) == INVEN_WIELD || wield_slot(o_ptr) == INVEN_BOW
				|| obj_is_ammo(o_ptr) || o_ptr->to_d || o_ptr->to_h) {
			/* Make an exception for body armor with only a to-hit penalty */
			if (o_ptr->to_h < 0 && o_ptr->to_d == 0 &&
			    (o_ptr->tval == TV_SOFT_ARMOR ||
			     o_ptr->tval == TV_HARD_ARMOR ||
			     o_ptr->tval == TV_DRAG_ARMOR))
				strnfcat(buf, max, &end, " (%+d)", o_ptr->to_h);

			/* Otherwise, always use the full tuple */
			else
				strnfcat(buf, max, &end, " (%+d,%+d)", o_ptr->to_h, o_ptr->to_d);
		}
	}


	/* Show armor bonuses */
	if (spoil || object_defence_plusses_are_visible(o_ptr)) {
		if (obj_desc_show_armor(o_ptr))
			strnfcat(buf, max, &end, " [%d,%+d]", o_ptr->ac, o_ptr->to_a);
		else if (o_ptr->to_a)
			strnfcat(buf, max, &end, " [%+d]", o_ptr->to_a);
	}
	else if (obj_desc_show_armor(o_ptr))
		strnfcat(buf, max, &end, " [%d]", object_was_sensed(o_ptr) ? o_ptr->ac : o_ptr->kind->ac);

	return end;
}
Пример #3
0
/*
 * Describe things that look like lights.
 */
static bool describe_light(textblock *tb, const object_type *o_ptr,
		const bitflag flags[OF_SIZE], oinfo_detail_t mode)
{
	int rad = 0;

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

	if (!is_light && !of_has(flags, OF_LIGHT))
		return FALSE;

	/* Work out radius */
	if (of_has(flags, OF_LIGHT))
		rad = o_ptr->pval[which_pval(o_ptr, OF_LIGHT)];

	/* 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 && o_ptr->sval != SV_LIGHT_TORCH)
	{
		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;
}
Пример #4
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;
}
Пример #5
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;
}
Пример #6
0
/**
 * Applying magic to an object, which includes creating ego-items, and applying
 * random bonuses,
 *
 * The `good` argument forces the item to be at least `good`, and the `great`
 * argument does likewise.  Setting `allow_artifacts` to TRUE allows artifacts
 * to be created here.
 *
 * If `good` or `great` are not set, then the `lev` argument controls the
 * quality of item.
 *
 * Returns 0 if a normal object, 1 if a good object, 2 if an ego item, 3 if an
 * artifact.
 */
s16b apply_magic(object_type *o_ptr, int lev, bool allow_artifacts,
		bool good, bool great, bool extra_roll)
{
	int i;
	s16b power = 0;

	/* Chance of being `good` and `great` */
	/* This has changed over the years:
	 * 3.0.0:   good = MIN(75, lev + 10);      great = MIN(20, lev / 2); 
	 * 3.3.0:	good = (lev + 2) * 3;          great = MIN(lev / 4 + lev, 50);
     * 3.4.0:   good = (2 * lev) + 5
     * 3.4 was in between 3.0 and 3.3, 3.5 attempts to keep the same
     * area under the curve as 3.4, but make the generation chances
     * flatter.  This depresses good items overall since more items
     * are created deeper. 
     * This change is meant to go in conjunction with the changes
     * to ego item allocation levels. (-fizzix)
	 */
	int good_chance = (33 + lev);
	int great_chance = 30;

	/* Roll for "good" */
	if (good || (randint0(100) < good_chance)) {
		power = 1;

		/* Roll for "great" */
		if (great || (randint0(100) < great_chance))
			power = 2;
	}

	/* Roll for artifact creation */
	if (allow_artifacts) {
		int rolls = 0;

		/* Get one roll if excellent */
		if (power >= 2) rolls = 1;

		/* Get two rolls if forced great */
		if (great) rolls = 2;
        
        /* Give some extra rolls for uniques and acq scrolls */
        if (extra_roll) rolls += 2;

		/* Roll for artifacts if allowed */
		for (i = 0; i < rolls; i++)
			if (make_artifact(o_ptr)) return 3;
	}

	/* Try to make an ego item */
	if (power == 2)
		make_ego_item(o_ptr, lev);

	/* Apply magic */
	switch (o_ptr->tval)
	{
		case TV_DIGGING:
		case TV_HAFTED:
		case TV_POLEARM:
		case TV_SWORD:
		case TV_BOW:
		case TV_SHOT:
		case TV_ARROW:
		case TV_BOLT:
			apply_magic_weapon(o_ptr, lev, power);
			break;

		case TV_DRAG_ARMOR:
		case TV_HARD_ARMOR:
		case TV_SOFT_ARMOR:
		case TV_SHIELD:
		case TV_HELM:
		case TV_CROWN:
		case TV_CLOAK:
		case TV_GLOVES:
		case TV_BOOTS:
			apply_magic_armour(o_ptr, lev, power);
			break;

		case TV_RING:
			if (o_ptr->sval == SV_RING_SPEED) {
				/* Super-charge the ring */
				while (one_in_(2))
					o_ptr->pval[which_pval(o_ptr, OF_SPEED)]++;
			}
			break;

		case TV_CHEST:
			/* Hack -- skip ruined chests */
			if (o_ptr->kind->level <= 0) break;

			/* Hack -- pick a "difficulty" */
			o_ptr->pval[DEFAULT_PVAL] = randint1(o_ptr->kind->level);

			/* Never exceed "difficulty" of 55 to 59 */
			if (o_ptr->pval[DEFAULT_PVAL] > 55)
				o_ptr->pval[DEFAULT_PVAL] = (s16b)(55 + randint0(5));

			break;
	}

	/* Apply minima from ego items if necessary */
	ego_apply_minima(o_ptr);

	return power;
}
Пример #7
0
/**
 * Applying magic to an object, which includes creating ego-items, and applying
 * random bonuses,
 *
 * The `good` argument forces the item to be at least `good`, and the `great`
 * argument does likewise.  Setting `allow_artifacts` to TRUE allows artifacts
 * to be created here.
 *
 * If `good` or `great` are not set, then the `lev` argument controls the
 * quality of item.
 *
 * Returns 0 if a normal object, 1 if a good object, 2 if an ego item, 3 if an
 * artifact.
 */
s16b apply_magic(object_type *o_ptr, int lev, bool allow_artifacts,
		bool good, bool great)
{
	int i;
	s16b power = 0;

	/* Chance of being `good` and `great` */
	/* This has changed over the years:
	 * 3.0.0:   good = MIN(75, lev + 10);      great = MIN(20, lev / 2); 
	 * 3.3.0:	good = (lev + 2) * 3;          great = MIN(lev / 4 + lev, 50);
	 * The calculations below are somewhere between the two.		-AS-
	 */
	int good_chance = (2 * lev) + 5;
	int great_chance = MIN(40, (lev * 3) / 4);

	/* Roll for "good" */
	if (good || (randint0(100) < good_chance)) {
		power = 1;

		/* Roll for "great" */
		if (great || (randint0(100) < great_chance))
			power = 2;
	}

	/* Roll for artifact creation */
	if (allow_artifacts) {
		int rolls = 0;

		/* Get one roll if excellent */
		if (power >= 2) rolls = 1;

		/* Get four rolls if forced great */
		if (great) rolls = 4;

		/* Roll for artifacts if allowed */
		for (i = 0; i < rolls; i++)
			if (make_artifact(o_ptr)) return 3;
	}

	/* Try to make an ego item */
	if (power == 2)
		make_ego_item(o_ptr, lev);

	/* Apply magic */
	switch (o_ptr->tval)
	{
		case TV_DIGGING:
		case TV_HAFTED:
		case TV_POLEARM:
		case TV_SWORD:
		case TV_BOW:
		case TV_SHOT:
		case TV_ARROW:
		case TV_BOLT:
			apply_magic_weapon(o_ptr, lev, power);
			break;

		case TV_DRAG_ARMOR:
		case TV_HARD_ARMOR:
		case TV_SOFT_ARMOR:
		case TV_SHIELD:
		case TV_HELM:
		case TV_CROWN:
		case TV_CLOAK:
		case TV_GLOVES:
		case TV_BOOTS:
			apply_magic_armour(o_ptr, lev, power);
			break;

		case TV_RING:
			if (o_ptr->sval == SV_RING_SPEED) {
				/* Super-charge the ring */
				while (one_in_(2))
					o_ptr->pval[which_pval(o_ptr, OF_SPEED)]++;
			}
			break;

		case TV_CHEST:
			/* Hack -- skip ruined chests */
			if (o_ptr->kind->level <= 0) break;

			/* Hack -- pick a "difficulty" */
			o_ptr->pval[DEFAULT_PVAL] = randint1(o_ptr->kind->level);

			/* Never exceed "difficulty" of 55 to 59 */
			if (o_ptr->pval[DEFAULT_PVAL] > 55)
				o_ptr->pval[DEFAULT_PVAL] = (s16b)(55 + randint0(5));

			break;
	}

	/* Apply minima from ego items if necessary */
	ego_apply_minima(o_ptr);

	return power;
}
Пример #8
0
/*
 * Special display, part 2c
 *
 * How to print out the modifications and sustains.
 * Positive mods with no sustain will be light green.
 * Positive mods with a sustain will be dark green.
 * Sustains (with no modification) will be a dark green 's'.
 * Negative mods (from a curse) will be red.
 * Huge mods (>9), like from MICoMorgoth, will be a '*'
 * No mod, no sustain, will be a slate '.'
 */
static void display_player_sust_info(void)
{
	int i, j, row, col, stat;

	object_type *o_ptr;
	bitflag f[OF_SIZE];

	int stat_flags[A_MAX];
	int sustain_flags[A_MAX];

	byte a;
	char c;


	/* Row */
	row = 2;

	/* Column */
	col = 26;

	/* Build the stat flags tables */
	stat_flags[A_STR] = OF_STR;
	stat_flags[A_INT] = OF_INT;
	stat_flags[A_WIS] = OF_WIS;
	stat_flags[A_DEX] = OF_DEX;
	stat_flags[A_CON] = OF_CON;
	sustain_flags[A_STR] = OF_SUST_STR;
	sustain_flags[A_INT] = OF_SUST_INT;
	sustain_flags[A_WIS] = OF_SUST_WIS;
	sustain_flags[A_DEX] = OF_SUST_DEX;
	sustain_flags[A_CON] = OF_SUST_CON;

	/* Header */
	c_put_str(TERM_WHITE, "abcdefghijkl@", row-1, col);

	/* Process equipment */
	for (i = INVEN_WIELD; i < INVEN_TOTAL; ++i)
	{
		/* Get the object */
		o_ptr = &p_ptr->inventory[i];

		if (!o_ptr->kind) {
			col++;
			continue;
		}

		/* Get the "known" flags */
		object_flags_known(o_ptr, f);

		/* Initialize color based of sign of pval. */
		for (stat = 0; stat < A_MAX; stat++)
		{
			/* Default */
			a = TERM_SLATE;
			c = '.';

			/* Boost */
			if (of_has(f, stat_flags[stat]))
			{
				/* Default */
				c = '*';

				/* Work out which pval we're talking about */
				j = which_pval(o_ptr, stat_flags[stat]);

				/* Good */
				if (o_ptr->pval[j] > 0)
				{
					/* Good */
					a = TERM_L_GREEN;

					/* Label boost */
					if (o_ptr->pval[j] < 10)
						c = I2D(o_ptr->pval[j]);
				}

				/* Bad */
				if (o_ptr->pval[j] < 0)
				{
					/* Bad */
					a = TERM_RED;

					/* Label boost */
					if (o_ptr->pval[j] > -10)
						c = I2D(-(o_ptr->pval[j]));
				}
			}

			/* Sustain */
			if (of_has(f, sustain_flags[stat]))
			{
				/* Dark green */
				a = TERM_GREEN;

				/* Convert '.' to 's' */
				if (c == '.') c = 's';
			}

			if ((c == '.') && o_ptr->kind && !object_flag_is_known(o_ptr, sustain_flags[stat]))
				c = '?';

			/* Dump proper character */
			Term_putch(col, row+stat, a, c);
		}

		/* Advance */
		col++;
	}

	/* Player flags */
	player_flags(f);

	/* Check stats */
	for (stat = 0; stat < A_MAX; ++stat)
	{
		/* Default */
		a = TERM_SLATE;
		c = '.';

		/* Sustain */
		if (of_has(f, sustain_flags[stat]))
		{
			/* Dark green "s" */
			a = TERM_GREEN;
			c = 's';
		}

		/* Dump */
		Term_putch(col, row+stat, a, c);
	}

	/* Column */
	col = 26;

	/* Footer */
	c_put_str(TERM_WHITE, "abcdefghijkl@", row+6, col);

	/* Equippy */
	display_player_equippy(row+7, col);
}
Пример #9
0
/*
 * Evaluate the object's overall power level.
 */
s32b object_power(const object_type* o_ptr, int verbose, ang_file *log_file,
	bool known)
{
	s32b p = 0, q = 0, slay_pwr = 0;
	unsigned int i, j;
	int extra_stat_bonus = 0, mult = 1, num_slays = 0, k = 1;
	bitflag flags[OF_SIZE], mask[OF_SIZE];

	/* Zero the flag counts */
	for (i = 0; i < N_ELEMENTS(sets); i++)
		sets[i].count = 0;

	/* Extract the flags */
	if (known) {
		file_putf(log_file, "Object is deemed known\n");
		object_flags(o_ptr, flags);
	} else {
		file_putf(log_file, "Object may not be fully known\n");
		object_flags_known(o_ptr, flags);
	}

	/* Log the flags in human-readable form */
	if (verbose)
		log_flags(flags, log_file);

	/* Get the slay power and number of slay/brand types */
	create_mask(mask, FALSE, OFT_SLAY, OFT_KILL, OFT_BRAND, OFT_MAX);
	num_slays = list_slays(flags, mask, NULL, NULL, NULL, TRUE);
	if (num_slays)
		slay_pwr = slay_power(o_ptr, verbose, log_file, known);

	/* Start with any damage boost from the item itself */
	p += (o_ptr->to_d * DAMAGE_POWER / 2);
	file_putf(log_file, "Adding power from to_dam, total is %d\n", p);

	/* Add damage from dice for any wieldable weapon or ammo */
	if (wield_slot(o_ptr) == INVEN_WIELD || obj_is_ammo(o_ptr)) {
		p += (o_ptr->dd * (o_ptr->ds + 1) * DAMAGE_POWER / 4);
		file_putf(log_file, "Adding power for dam dice, total is %d\n", p);
	/* Add 2nd lot of damage power for nonweapons */
	} else if (wield_slot(o_ptr) != INVEN_BOW) {
		p += (o_ptr->to_d * DAMAGE_POWER);
		file_putf(log_file, "Adding power from nonweap to_dam, total is %d\n", p);
		/* Add power boost for nonweapons with combat flags */
		if (num_slays || of_has(flags, OF_BLOWS) || of_has(flags, OF_SHOTS) ||
				of_has(flags, OF_MIGHT)) {
			p += (WEAP_DAMAGE * DAMAGE_POWER);
			file_putf(log_file, "Adding power for nonweap combat flags, total is %d\n", p);
		}
	}

	/* Add ammo damage for launchers, get multiplier and rescale */
	if (wield_slot(o_ptr) == INVEN_BOW) {
		p += (archery[o_ptr->sval / 10].ammo_dam * DAMAGE_POWER / 2);
		file_putf(log_file, "Adding power from ammo, total is %d\n", p);

		mult = bow_multiplier(o_ptr->sval);
		file_putf(log_file, "Base mult for this weapon is %d\n", mult);
	}

	/* Add launcher bonus for ego ammo, multiply for launcher and rescale */
	if (obj_is_ammo(o_ptr)) {
		if (o_ptr->ego)
			p += (archery[o_ptr->tval - TV_SHOT].launch_dam * DAMAGE_POWER / 2);
		p = p * archery[o_ptr->tval - TV_SHOT].launch_mult / (2 * MAX_BLOWS);
		file_putf(log_file, "After multiplying ammo and rescaling, power is %d\n", p);
	}

	/* Add power for extra blows */
	if (of_has(flags, OF_BLOWS)) {
		j = which_pval(o_ptr, OF_BLOWS);
		if (known || object_this_pval_is_visible(o_ptr, j)) {
			if (o_ptr->pval[j] >= INHIBIT_BLOWS) {
				p += INHIBIT_POWER;
				file_putf(log_file, "INHIBITING - too many extra blows\n");
			} else {
				p = p * (MAX_BLOWS + o_ptr->pval[j]) / MAX_BLOWS;
				/* Add boost for assumed off-weapon damage */
				p += (NONWEAP_DAMAGE * o_ptr->pval[j] * DAMAGE_POWER / 2);
				file_putf(log_file, "Adding power for extra blows, total is %d\n", p);
			}
		}
	}

	/* Add power for extra shots - note that we cannot handle negative shots */
	if (of_has(flags, OF_SHOTS)) {
		j = which_pval(o_ptr, OF_SHOTS);
		if (known || object_this_pval_is_visible(o_ptr, j)) {
			if (o_ptr->pval[j] >= INHIBIT_SHOTS) {
				p += INHIBIT_POWER;
				file_putf(log_file, "INHIBITING - too many extra shots\n");
			} else if (o_ptr->pval[j] > 0) {
				p = (p * (1 + o_ptr->pval[j]));
				file_putf(log_file, "Extra shots: multiplying power by 1 + %d, total is %d\n", o_ptr->pval[j], p);
			}
		}
	}

	/* Add power for extra might */
	if (of_has(flags, OF_MIGHT)) {
		j = which_pval(o_ptr, OF_MIGHT);
		if (known || object_this_pval_is_visible(o_ptr, j)) {
			if (o_ptr->pval[j] >= INHIBIT_MIGHT) {
				p += INHIBIT_POWER;
				mult = 1;	/* don't overflow */
				file_putf(log_file, "INHIBITING - too much extra might\n");
			} else
				mult += o_ptr->pval[j];
			file_putf(log_file, "Mult after extra might is %d\n", mult);
		}
	}
	p *= mult;
	file_putf(log_file, "After multiplying power for might, total is %d\n", p);

	/* Apply the correct slay multiplier */
	if (slay_pwr) {
		p = (p * (slay_pwr / 10)) / (tot_mon_power / 10);
		file_putf(log_file, "Adjusted for slay power, total is %d\n", p);
	}

	/* Melee weapons assume MAX_BLOWS per turn, so we must divide by MAX_BLOWS
     * to get equal ratings for launchers. */
	if (wield_slot(o_ptr) == INVEN_BOW) {
		p /= MAX_BLOWS;
		file_putf(log_file, "Rescaling bow power, total is %d\n", p);
	}

	/* Add power for +to_hit */
	p += (o_ptr->to_h * TO_HIT_POWER / 2);
	file_putf(log_file, "Adding power for to hit, total is %d\n", p);

	/* Add power for base AC and adjust for weight */
	if (o_ptr->ac) {
		q += BASE_ARMOUR_POWER;
		q += (o_ptr->ac * BASE_AC_POWER / 2);
		file_putf(log_file, "Adding %d power for base AC value\n", q);

		/* Add power for AC per unit weight */
		if (o_ptr->weight > 0) {
			i = 800 * (o_ptr->ac + o_ptr->to_a) / o_ptr->weight;

			/* Avoid overpricing Elven Cloaks */
			if (i > 450) i = 450;

			q *= i;
			q /= 100;

		/* Weightless (ethereal) armour items get fixed boost */
		} else
			q *= 5;
		p += q;
		file_putf(log_file, "Adding power for AC per unit weight, now %d\n", p);
	}
	/* Add power for +to_ac */
	p += (o_ptr->to_a * TO_AC_POWER / 2);
	file_putf(log_file, "Adding power for to_ac of %d, total is %d\n", o_ptr->to_a, p);
	if (o_ptr->to_a > HIGH_TO_AC) {
		p += ((o_ptr->to_a - (HIGH_TO_AC - 1)) * TO_AC_POWER);
		file_putf(log_file, "Adding power for high to_ac value, total is %d\n", p);
	}
	if (o_ptr->to_a > VERYHIGH_TO_AC) {
		p += ((o_ptr->to_a - (VERYHIGH_TO_AC -1)) * TO_AC_POWER * 2);
		file_putf(log_file, "Adding power for very high to_ac value, total is %d\n", p);
	}
	if (o_ptr->to_a >= INHIBIT_AC) {
		p += INHIBIT_POWER;
		file_putf(log_file, "INHIBITING: AC bonus too high\n");
	}


	/* Add power for light sources by radius XXX Hack - rewrite calc_torch! */
	if (wield_slot(o_ptr) == INVEN_LIGHT) {
		p += BASE_LIGHT_POWER;

		/* Artifact lights have larger radius so add more */
		if (o_ptr->artifact)
			p += BASE_LIGHT_POWER;

		file_putf(log_file, "Adding power for light radius, total is %d\n", p);
	}

	/* Add base power for jewelry */
	if (object_is_jewelry(o_ptr)) {
		p += BASE_JEWELRY_POWER;
		file_putf(log_file, "Adding power for jewelry, total is %d\n", p);
	}

	/* Add power for non-derived flags (derived flags have flag_power 0) */
	for (i = 0; i < OF_MAX; i++) {
		if (of_has(flags, i)) {
			if (flag_uses_pval(i)) {
				j = which_pval(o_ptr, i);
				if (known || object_this_pval_is_visible(o_ptr, j)) {
					k = o_ptr->pval[j];
					extra_stat_bonus += (k * pval_mult(i));
				}
			} else
				k = 1;

			if (flag_power(i)) {
				p += (k * flag_power(i) * slot_mult(i, wield_slot(o_ptr)));
				file_putf(log_file, "Adding power for %s, total is %d\n", flag_name(i), p);
			}

			/* Track combinations of flag types - note we ignore SUST_CHR */
			for (j = 0; j < N_ELEMENTS(sets); j++)
				if ((sets[j].type == obj_flag_type(i)) && (i != OF_SUST_CHR))
					sets[j].count++;
		}
	}

	/* Add extra power term if there are a lot of ability bonuses */
	if (extra_stat_bonus > 249) {
		file_putf(log_file, "Inhibiting!  (Total ability bonus of %d is too high)\n", extra_stat_bonus);
		p += INHIBIT_POWER;
	} else {
		p += ability_power[extra_stat_bonus / 10];
		file_putf(log_file, "Adding power for pval total of %d, total is %d\n", extra_stat_bonus, p);
	}

	/* Add extra power for multiple flags of the same type */
	for (i = 0; i < N_ELEMENTS(sets); i++) {
		if (sets[i].count > 1) {
			p += (sets[i].factor * sets[i].count * sets[i].count);
			file_putf(log_file, "Adding power for multiple flags of type %d, total is %d\n", i, p);
		}

		/* Add bonus if item has a full set of these flags */
		if (sets[i].count == sets[i].size) {
			p += sets[i].bonus;
			file_putf(log_file, "Adding power for full set of type %d, total is %d\n", i, p);
		}
	}

	/* add power for effect */
	if (known || object_effect_is_known(o_ptr))	{
		if (o_ptr->artifact && o_ptr->artifact->effect) {
			p += effect_power(o_ptr->artifact->effect);
			file_putf(log_file, "Adding power for artifact activation, total is %d\n", p);
		} else {
			p += effect_power(o_ptr->kind->effect);
			file_putf(log_file, "Adding power for item activation, total is %d\n", p);
		}
	}

	file_putf(log_file, "FINAL POWER IS %d\n", p);

	return p;
}
Пример #10
0
/**
 * Applying magic to an object, which includes creating ego-items, and applying
 * random bonuses,
 *
 * The `good` and `great` arguments affect the number of affixes on the item.
 * Setting `allow_artifacts` to TRUE allows artifacts to be created here -
 * this is used if we call directly with a pre-specified object kind; it is
 * not used if we come via make_object.
 *
 * If `good` or `great` are not set, then the `lev` argument controls the
 * number of affixes on the item.
 *
 * Returns the number of affixes on the object: 0 for a normal object,
 * MAX_AFFIXES+1 for an artifact.
 */
s16b apply_magic(object_type *o_ptr, int lev, bool allow_artifacts,
		bool good, bool great)
{
	int i, max_lev = 3, min_lev = 1, affixes;
	bool art = FALSE;

	/* Set the number and quality of affixes this item will have */
	if (randint0(100) < 20 + lev)
		max_lev++;
	if (great || (good && one_in_(4)))
		max_lev++;
	if (great || good || randint0(100) < 10 + lev)
		min_lev++;
	if (great)
		min_lev++;

	affixes = randint0(3 + lev / 25);
	if (great)
		affixes += 2 + randint1(2);
	else if (good)
		affixes += randint1(2);
	if (of_has(o_ptr->flags, OF_GOOD))
		affixes--;
	if (affixes > MAX_AFFIXES)
		affixes = MAX_AFFIXES;

	/* Roll for artifact creation - n.b. this is now only used if we were
	   called directly and not via make_object */
	if (allow_artifacts) {
		if (great && one_in_(ART_GREAT))
			art = TRUE;
		else if (max_lev > 3 && one_in_(ART_GOOD))
			art = TRUE;
		else if (one_in_(ART_NORMAL))
			art = TRUE;

		if (art && make_artifact(o_ptr, lev))
			return MAX_AFFIXES + 1;
	}

	/* Generate and apply affixes, stopping if we acquire a theme */
	for (i = 0; i < affixes && !o_ptr->theme; i++)
		obj_add_affix(o_ptr, lev, max_lev, min_lev);

	/* Apply special-case magic */
	switch (o_ptr->tval) {
		case TV_RING:
			if (o_ptr->sval == SV_RING_SPEED) {
				/* Super-charge the ring */
				while (one_in_(2))
					o_ptr->pval[which_pval(o_ptr, OF_SPEED)]++;
			}
			break;

		case TV_CHEST:
			/* Skip ruined chests */
			if (o_ptr->kind->level <= 0) break;

			/* Pick a difficulty */
			o_ptr->extent = randint1(o_ptr->kind->level);

			/* Never exceed difficulty of 55 to 59 */
			if (o_ptr->extent > 55)
				o_ptr->extent = (s16b)(55 + randint0(5));

			break;
	}

	return affixes;
}
Пример #11
0
/**
 * Apply an affix to an ego-item, checking minima as we go.
 *
 * \param o_ptr is the object we're modifying
 * \param level is the generation level
 * \param affix is the affix we're applying
 */
void ego_apply_magic(object_type *o_ptr, int level, int affix)
{
	int i, j, flag, pval, amt;
	bitflag flags[OF_SIZE], f2[OF_SIZE];
	ego_item_type *ego;

	ego = &e_info[affix];

	/* Random powers */
	for (i = 0; i < ego->num_randlines; i++)
		for (j = 0; j < ego->num_randflags[i]; j++)
			of_on(o_ptr->flags,	get_new_attr(o_ptr->flags, ego->randmask[i]));

	/* Apply extra combat bonuses */
	amt = randcalc(ego->to_h, level, RANDOMISE);
	o_ptr->to_h += amt;
	if (ego->min_to_h != NO_MINIMUM) {
		if (amt < ego->min_to_h)
			o_ptr->to_h += ego->min_to_h - amt;
		if (o_ptr->to_h < ego->min_to_h)
			o_ptr->to_h = ego->min_to_h;
	}

	amt = randcalc(ego->to_d, level, RANDOMISE);
	o_ptr->to_d += amt;
	if (ego->min_to_d != NO_MINIMUM) {
		if (amt < ego->min_to_d)
			o_ptr->to_d += ego->min_to_d - amt;
		if (o_ptr->to_d < ego->min_to_d)
			o_ptr->to_d = ego->min_to_d;
	}

	amt = randcalc(ego->to_a, level, RANDOMISE);
	o_ptr->to_a += amt;
	if (ego->min_to_a != NO_MINIMUM) {
		if (amt < ego->min_to_a)
			o_ptr->to_a += ego->min_to_a - amt;
		if (o_ptr->to_a < ego->min_to_a)
			o_ptr->to_a = ego->min_to_a;
	}

	/* Apply pvals */
	of_copy(f2, ego->flags);
	for (i = 0; i < ego->num_pvals; i++) {
		of_copy(flags, ego->pval_flags[i]);
		pval = randcalc(ego->pval[i], level, RANDOMISE);
		if (ego->min_pval[i] != NO_MINIMUM && pval < ego->min_pval[i])
			pval = ego->min_pval[i];
		for (flag = of_next(flags, FLAG_START); flag != FLAG_END;
				flag = of_next(flags, flag + 1))
			/* Prevent phantom flags, and check minima after adding */
			if (pval) {
				object_add_pval(o_ptr, pval, flag);
				if (ego->min_pval[i] != NO_MINIMUM && of_has(o_ptr->flags,
						flag))
					if (o_ptr->pval[which_pval(o_ptr, flag)] < ego->min_pval[i])
						object_add_pval(o_ptr, ego->min_pval[i] -
							o_ptr->pval[which_pval(o_ptr, flag)], flag);
			} else
				of_off(f2, flag);
	}

	/* Apply remaining flags */
	of_union(o_ptr->flags, f2);

	/* Adjust AC, weight, dice and sides */
	if (o_ptr->ac && ego->ac_mod)
		o_ptr->ac = ((100 + ego->ac_mod) * o_ptr->ac) / 100;

	o_ptr->weight = ((100 + ego->wgt_mod) * o_ptr->weight) / 100;

	o_ptr->dd += ego->dd;
	if (o_ptr->dd < 1)
		o_ptr->dd = 1;

	o_ptr->ds += ego->ds;
	if (o_ptr->ds < 1)
		o_ptr->ds = 1;

	/* Tidy up and de-duplicate flags, and set the correct prefix/suffix */
	check_flags(o_ptr);
	obj_affix_names(o_ptr);

	return;
}