Exemplo n.º 1
0
/**
 * Describe slays and brands on weapons
 */
static bool describe_brands(textblock *tb, const struct object *obj)
{
	struct brand *known_brands = brand_collect(obj, NULL, TRUE);
	struct brand *b;

	if (!known_brands) return FALSE;

	if (tval_is_weapon(obj) || tval_is_fuel(obj))
		textblock_append(tb, "Branded with ");
	else
		textblock_append(tb, "It brands your melee attacks with ");

	b = known_brands;
	while (b) {
		if (b->multiplier < 3)
			textblock_append(tb, "weak ");
		textblock_append(tb, b->name);
		if (b->next)
			textblock_append(tb, ", ");
		else
			textblock_append(tb, ".\n");
		b = b->next;
	}

	free_brand(known_brands);
	return TRUE;
}
Exemplo n.º 2
0
/**
 * Delete an object and free its memory, and set its pointer to NULL
 */
void object_delete(struct object **obj_address)
{
	struct object *obj = *obj_address;
	struct object *prev = obj->prev;
	struct object *next = obj->next;

	/* Free slays and brands */
	if (obj->slays)
		free_slay(obj->slays);
	if (obj->brands)
		free_brand(obj->brands);

	/* Check any next and previous objects */
	if (next) {
		if (prev) {
			prev->next = next;
			next->prev = prev;
		} else {
			next->prev = NULL;
		}
	} else if (prev) {
		prev->next = NULL;
	}

	/* If we're tracking the object, stop */
	if (player && player->upkeep && obj == player->upkeep->object)
		player->upkeep->object = NULL;

	mem_free(obj);
	*obj_address = NULL;
}
Exemplo n.º 3
0
/**
 * Delete an object and free its memory, and set its pointer to NULL
 */
void object_delete(struct object **obj_address)
{
	struct object *obj = *obj_address;
	struct object *prev = obj->prev;
	struct object *next = obj->next;

	/* Check any next and previous objects */
	if (next) {
		if (prev) {
			prev->next = next;
			next->prev = prev;
		} else {
			next->prev = NULL;
		}
	} else if (prev) {
		prev->next = NULL;
	}

	/* If we're tracking the object, stop */
	if (player && player->upkeep && obj == player->upkeep->object)
		player->upkeep->object = NULL;

	/* Orphan rather than actually delete if we still have a known object */
	if (cave && player && player->cave && obj->oidx &&
		(obj == cave->objects[obj->oidx]) &&
		player->cave->objects[obj->oidx]) {
		obj->iy = 0;
		obj->ix = 0;
		obj->held_m_idx = 0;
		obj->mimicking_m_idx = 0;

		/* Object is now purely imaginary to the player */
		obj->known->notice |= OBJ_NOTICE_IMAGINED;

		return;
	}

	/* Remove from any lists */
	if (player && player->cave && player->cave->objects && obj->oidx
		&& (obj == player->cave->objects[obj->oidx]))
		player->cave->objects[obj->oidx] = NULL;

	if (cave && cave->objects && obj->oidx
		&& (obj == cave->objects[obj->oidx]))
		cave->objects[obj->oidx] = NULL;

	if (obj->slays) {
		free_slay(obj->slays);
	}

	if (obj->brands) {
		free_brand(obj->brands);
	}

	mem_free(obj);
	*obj_address = NULL;
}
Exemplo n.º 4
0
/**
 * Wipe an object clean.
 */
void object_wipe(struct object *obj, bool free_curse_objects)
{
	/* Free slays and brands */
	free_slay(obj->slays);
	free_brand(obj->brands);
	free_curse(obj->curses, free_curse_objects, false);

	/* Wipe the structure */
	memset(obj, 0, sizeof(*obj));
}
Exemplo n.º 5
0
/**
 * Wipe an object clean.
 */
void object_wipe(struct object *obj)
{
	/* Free slays and brands */
	if (obj->slays)
		free_slay(obj->slays);
	if (obj->brands)
		free_brand(obj->brands);

	/* Wipe the structure */
	memset(obj, 0, sizeof(*obj));
}
Exemplo n.º 6
0
/**
 * Free up an object
 *
 * This doesn't affect any game state outside of the object itself
 */
void object_free(struct object *obj)
{
	if (obj->slays) {
		free_slay(obj->slays);
	}

	if (obj->brands) {
		free_brand(obj->brands);
	}

	if (obj->curses) {
		free_curse(obj->curses, true, true);
	}

	mem_free(obj);
}
Exemplo n.º 7
0
/**
 * Calculate the rating for a given slay combination
 */
static s32b slay_power(const object_type *obj, int p, int verbose,
					   int dice_pwr, bool known)
{
	u32b sv = 0;
	int i, q, num_brands = 0, num_slays = 0, num_kills = 0;
	int mult;
	int tot_mon_power = 0;
	struct brand *brands = obj->brands;
	struct slay *slays = obj->slays;

	/* Count the known brands and slays */
	while (brands) {
		if (known || brands->known)
			num_brands++;
		brands = brands->next;
	}
	while (slays) {
		if (known || slays->known) {
			if (slays->multiplier <= 3)
				num_slays++;
			else
				num_kills++;
		}
		slays = slays->next;
	}

	/* If there are no slays or brands return */
	if ((num_slays + num_brands + num_kills) == 0)
		return p;

	/* Look in the cache to see if we know this one yet */
	sv = check_slay_cache(obj);

	/* If it's cached (or there are no slays), return the value */
	if (sv)	{
		log_obj("Slay cache hit\n");
	} else {

		/*
		 * Otherwise we need to calculate the expected average multiplier
		 * for this combination (multiplied by the total number of
		 * monsters, which we'll divide out later).
		 */
		for (i = 0; i < z_info->r_max; i++)	{
			monster_type *mon = mem_zalloc(sizeof(*mon));
			const struct brand *b = NULL;
			const struct slay *s = NULL;
			char verb[20];

			mult = 1;
			mon->race = &r_info[i];

			/* Find the best multiplier against this monster */
			improve_attack_modifier((object_type *)obj, mon, &b, &s, 
									verb, FALSE, FALSE, !known);
			if (s)
				mult = s->multiplier;
			else if (b)
				mult = b->multiplier;

			/* Add up totals */
			tot_mon_power += mon->race->scaled_power;
			sv += mult * mon->race->scaled_power;
			mem_free(mon);
		}

		/*
		 * To get the expected damage for this weapon, multiply the
		 * average damage from base dice by sv, and divide by the
		 * total number of monsters.
		 */
		if (verbose) {
			struct brand *b, *brands = NULL;
			struct slay *s, *slays = NULL;

			/* Write info about the slay combination and multiplier */
			log_obj("Slay multiplier for: ");

			brands = brand_collect(obj->brands, NULL, !known);
			slays = slay_collect(obj->slays, NULL, !known);

			for (b = brands; b; b = b->next) {
				log_obj(format("%sx%d ", b->name, b->multiplier));
			}
			for (s = slays; s; s = s->next) {
				log_obj(format("%sx%d ", s->name, s->multiplier));
			}
			log_obj(format("\nsv is: %d\n", sv));
			log_obj(format(" and t_m_p is: %d \n", tot_mon_power));
			log_obj(format("times 1000 is: %d\n", (1000 * sv) / tot_mon_power));
			free_brand(brands);
			free_slay(slays);
		}

		/* Add to the cache */
		if (fill_slay_cache(obj, sv))
			log_obj("Added to slay cache\n");
	}

	q = (dice_pwr * (sv / 100)) / (tot_mon_power / 100);
	p += q;
	log_obj(format("Add %d for slay power, total is %d\n", q, p));

	/* Bonuses for multiple brands and slays */
	if (num_slays > 1) {
		q = (num_slays * num_slays * dice_pwr) / (DAMAGE_POWER * 5);
		p += q;
		log_obj(format("Add %d power for multiple slays, total is %d\n", q, p));
	}
	if (num_brands > 1) {
		q = (2 * num_brands * num_brands * dice_pwr) / (DAMAGE_POWER * 5);
		p += q;
		log_obj(format("Add %d power for multiple brands, total is %d\n",q, p));
	}
	if (num_kills > 1) {
		q = (3 * num_kills * num_kills * dice_pwr) / (DAMAGE_POWER * 5);
		p += q;
		log_obj(format("Add %d power for multiple kills, total is %d\n", q, p));
	}
	if (num_slays == 8) {
		p += 10;
		log_obj(format("Add 10 power for full set of slays, total is %d\n", p));
	}
	if (num_brands == 5) {
		p += 20;
		log_obj(format("Add 20 power for full set of brands, total is %d\n",p));
	}
	if (num_kills == 3) {
		p += 20;
		log_obj(format("Add 20 power for full set of kills, total is %d\n", p));
	}

	return p;
}
Exemplo n.º 8
0
/**
 * Describe damage.
 */
static bool describe_damage(textblock *tb, const struct object *obj)
{
	bool nonweap_slay = false;
	int normal_damage;
	struct brand *brand, *brands = NULL;
	struct slay *slay, *slays = NULL;
	bool has_brands_or_slays;

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

	/* Mention slays and brands from other items */
	if (nonweap_slay)
		textblock_append(tb, "This weapon may benefit from one or more off-weapon brands or slays.\n");

	textblock_append(tb, "Average damage/round: ");

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

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

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

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

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

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

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

	free_brand(brands);
	free_slay(slays);
	return true;
}
Exemplo n.º 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);
}