Ejemplo n.º 1
0
/**
 * Determine if a grid contains a chest matching the query type, and
 * return a pointer to the first such chest
 */
struct object *chest_check(int y, int x, enum chest_query check_type)
{
	struct object *obj;

	/* Scan all objects in the grid */
	for (obj = square_object(cave, y, x); obj; obj = obj->next) {
		/* Check for chests */
		switch (check_type) {
		case CHEST_ANY:
			if (tval_is_chest(obj))
				return obj;
			break;
		case CHEST_OPENABLE:
			if (tval_is_chest(obj) && (obj->pval != 0))
				return obj;
			break;
		case CHEST_TRAPPED:
			if (is_trapped_chest(obj) && object_is_known(obj))
				return obj;
			break;
		}
	}

	/* No chest */
	return NULL;
}
Ejemplo n.º 2
0
/**
 * Allocate objects upon opening a chest
 *
 * Disperse treasures from the given chest, centered at (x,y).
 *
 * Small chests often contain "gold", while Large chests always contain
 * items.  Wooden chests contain 2 items, Iron chests contain 4 items,
 * and Steel chests contain 6 items.  The "value" of the items in a
 * chest is based on the level on which the chest is generated.
 *
 * Judgment of size and construction of chests is currently made from the name.
 */
static void chest_death(int y, int x, struct object *chest)
{
	int number, value;

	bool tiny;

	struct object *treasure;

	/* Small chests often hold "gold" */
	tiny = strstr(chest->kind->name, "Small") ? TRUE : FALSE;

	/* Determine how much to drop (see above) */
	if (strstr(chest->kind->name, "wooden"))
		number = 2;
	else if (strstr(chest->kind->name, "iron"))
		number = 4;
	else if (strstr(chest->kind->name, "steel"))
		number = 6;
	else
		number = 2 * (randint1(3));

	/* Zero pval means empty chest */
	if (!chest->pval) number = 0;

	/* Determine the "value" of the items */
	value = chest->origin_depth - 10 + 2 * chest->sval;
	if (value < 1)
		value = 1;

	/* Drop some objects (non-chests) */
	for (; number > 0; --number) {
		/* Small chests often drop gold */
		if (tiny && (randint0(100) < 75))
			treasure = make_gold(value, "any");

		/* Otherwise drop an item, as long as it isn't a chest */
		else {
			treasure = make_object(cave, value, FALSE, FALSE, FALSE, NULL, 0);
			if (!treasure) continue;
			if (tval_is_chest(treasure)) {
				mem_free(treasure);
				continue;
			}
		}

		/* Record origin */
		treasure->origin = ORIGIN_CHEST;
		treasure->origin_depth = chest->origin_depth;

		/* Drop it in the dungeon */
		drop_near(cave, treasure, 0, y, x, TRUE);
	}

	/* Empty */
	chest->pval = 0;

	/* Known */
	object_notice_everything(chest);
}
Ejemplo n.º 3
0
/**
 * Describes item `obj` into buffer `buf` of size `max`.
 *
 * ODESC_PREFIX prepends a 'the', 'a' or number
 * ODESC_BASE results in a base description.
 * ODESC_COMBAT will add to-hit, to-dam and AC info.
 * ODESC_EXTRA will add pval/charge/inscription/ignore info.
 * ODESC_PLURAL will pluralise regardless of the number in the stack.
 * ODESC_STORE turns off ignore markers, for in-store display.
 * ODESC_SPOIL treats the object as fully identified.
 *
 * Setting 'prefix' to TRUE prepends a 'the', 'a' or the number in the stack,
 * respectively.
 *
 * \returns The number of bytes used of the buffer.
 */
size_t object_desc(char *buf, size_t max, const struct object *obj, int mode)
{
	bool prefix = mode & ODESC_PREFIX ? TRUE : FALSE;
	bool spoil = mode & ODESC_SPOIL ? TRUE : FALSE;
	bool terse = mode & ODESC_TERSE ? TRUE : FALSE;

	size_t end = 0;

	/* Simple description for null item */
	if (!obj)
		return strnfmt(buf, max, "(nothing)");

	/* Egos whose name we know are seen */
	if (object_name_is_visible(obj) && obj->ego && !spoil)
		obj->ego->everseen = TRUE;


	/*** Some things get really simple descriptions ***/

	if (obj->marked == MARK_AWARE) {
		if (prefix)
			return strnfmt(buf, max, "an unknown item");
		return strnfmt(buf, max, "unknown item");
	}

	if (tval_is_money(obj))
		return strnfmt(buf, max, "%d gold pieces worth of %s%s",
				obj->pval, obj->kind->name,
				ignore_item_ok(obj) ? " {ignore}" : "");

	/** Construct the name **/

	/* Copy the base name to the buffer */
	end = obj_desc_name(buf, max, end, obj, prefix, mode, spoil, terse);

	if (mode & ODESC_COMBAT)
	{
		if (tval_is_chest(obj))
			end = obj_desc_chest(obj, buf, max, end);
		else if (tval_is_light(obj))
			end = obj_desc_light(obj, buf, max, end);

		end = obj_desc_combat(obj, buf, max, end, spoil);
	}

	if (mode & ODESC_EXTRA)
	{
		end = obj_desc_mods(obj, buf, max, end, spoil);

		end = obj_desc_charges(obj, buf, max, end, mode);

		if (mode & ODESC_STORE)
			end = obj_desc_aware(obj, buf, max, end);
		else
			end = obj_desc_inscrip(obj, buf, max, end);
	}

	return end;
}
Ejemplo n.º 4
0
/**
 * Determine if a chest is locked or trapped
 */
bool is_locked_chest(const struct object *o_ptr)
{
	if (!tval_is_chest(o_ptr))
		return FALSE;

	/* Disarmed or opened chests are not locked */
	return (o_ptr->pval > 0);
}
Ejemplo n.º 5
0
/**
 * Determine if a chest is trapped
 */
bool is_trapped_chest(const struct object *o_ptr)
{
	if (!tval_is_chest(o_ptr))
		return FALSE;

	/* Disarmed or opened chests are not trapped */
	if (o_ptr->pval <= 0)
		return FALSE;

	/* Some chests simply don't have traps */
	return (chest_traps[o_ptr->pval] != 0);
}
Ejemplo n.º 6
0
/**
 * Determine if a chest is locked or trapped
 */
bool is_locked_chest(const struct object *obj)
{
	if (!tval_is_chest(obj))
		return FALSE;

	/* Ignore if requested */
	if (ignore_item_ok(obj))
		return FALSE;

	/* Disarmed or opened chests are not locked */
	return (obj->pval > 0);
}
Ejemplo n.º 7
0
/**
 * Determine if a chest is trapped
 */
bool is_trapped_chest(const struct object *obj)
{
	if (!tval_is_chest(obj))
		return FALSE;

	/* Ignore if requested */
	if (ignore_item_ok(obj))
		return FALSE;

	/* Disarmed or opened chests are not trapped */
	if (obj->pval <= 0)
		return FALSE;

	/* Some chests simply don't have traps */
	return (chest_traps[obj->pval] != 0);
}
Ejemplo n.º 8
0
/**
 * Allocate objects upon opening a chest
 *
 * Disperse treasures from the given chest, centered at (x,y).
 *
 * Wooden chests contain 1 item, Iron chests contain 2 items,
 * and Steel chests contain 3 items.  Small chests now contain good items,
 * large chests great items, out of depth for the level on which the chest
 * is generated.
 *
 * Judgment of size and construction of chests is currently made from the name.
 */
static void chest_death(int y, int x, struct object *chest)
{
	int number, level;
	bool large = strstr(chest->kind->name, "Large") ? true : false;;

	/* Zero pval means empty chest */
	if (!chest->pval)
		return;

	/* Determine how much to drop (see above) */
	if (strstr(chest->kind->name, "wooden")) {
		number = 1;
	} else if (strstr(chest->kind->name, "iron")) {
		number = 2;
	} else if (strstr(chest->kind->name, "steel")) {
		number = 3;
	} else {
		number = randint1(3);
	}

	/* Drop some valuable objects (non-chests) */
	level = chest->origin_depth + 5;
	while (number > 0) {
		struct object *treasure;
		treasure = make_object(cave, level, true, large, false, NULL, 0);
		if (!treasure)
			continue;
		if (tval_is_chest(treasure)) {
			object_delete(&treasure);
			continue;
		}

		treasure->origin = ORIGIN_CHEST;
		treasure->origin_depth = chest->origin_depth;
		drop_near(cave, &treasure, 0, y, x, true);
		number--;
	}

	/* Chest is now empty */
	chest->pval = 0;
	chest->known->pval = 0;
}
Ejemplo n.º 9
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.
 */
int apply_magic(struct object *obj, 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(obj)) return 3;
	}

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

	/* Apply magic */
	if (tval_is_weapon(obj)) {
		apply_magic_weapon(obj, lev, power);
	} else if (tval_is_armor(obj)) {
		apply_magic_armour(obj, lev, power);
	} else if (tval_is_ring(obj)) {
		if (obj->sval == lookup_sval(obj->tval, "Speed")) {
			/* Super-charge the ring */
			while (one_in_(2))
				obj->modifiers[OBJ_MOD_SPEED]++;
		}
	} else if (tval_is_chest(obj)) {
		/* Hack -- skip ruined chests */
		if (obj->kind->level > 0) {
			/* Hack -- pick a "difficulty" */
			obj->pval = randint1(obj->kind->level);

			/* Never exceed "difficulty" of 55 to 59 */
			if (obj->pval > 55)
				obj->pval = (s16b)(55 + randint0(5));
		}
	}

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

	return power;
}
Ejemplo n.º 10
0
/**
 * Determine if an item can "absorb" a second item
 *
 * See "object_absorb()" for the actual "absorption" code.
 *
 * If permitted, we allow weapons/armor to stack, if "known".
 *
 * Missiles will combine if both stacks have the same "known" status.
 * This is done to make unidentified stacks of missiles useful.
 *
 * Food, potions, scrolls, and "easy know" items always stack.
 *
 * Chests, and activatable items, except rods, never stack (for various
 * reasons).
 */
bool object_stackable(const struct object *obj1, const struct object *obj2,
					  object_stack_t mode)
{
	int i;

	/* Equipment items don't stack */
	if (object_is_equipped(player->body, obj1))
		return false;
	if (object_is_equipped(player->body, obj2))
		return false;

	/* If either item is unknown, do not stack */
	if (mode & OSTACK_LIST && obj1->kind != obj1->known->kind) return false;
	if (mode & OSTACK_LIST && obj2->kind != obj2->known->kind) return false;

	/* Hack -- identical items cannot be stacked */
	if (obj1 == obj2) return false;

	/* Require identical object kinds */
	if (obj1->kind != obj2->kind) return false;

	/* Different flags don't stack */
	if (!of_is_equal(obj1->flags, obj2->flags)) return false;

	/* Different elements don't stack */
	for (i = 0; i < ELEM_MAX; i++) {
		if (obj1->el_info[i].res_level != obj2->el_info[i].res_level)
			return false;
		if ((obj1->el_info[i].flags & (EL_INFO_HATES | EL_INFO_IGNORE)) !=
			(obj2->el_info[i].flags & (EL_INFO_HATES | EL_INFO_IGNORE)))
			return false;
	}

	/* Artifacts never stack */
	if (obj1->artifact || obj2->artifact) return false;

	/* Analyze the items */
	if (tval_is_chest(obj1)) {
		/* Chests never stack */
		return false;
	}
	else if (tval_is_edible(obj1) || tval_is_potion(obj1) ||
		tval_is_scroll(obj1) || tval_is_rod(obj1)) {
		/* Food, potions, scrolls and rods all stack nicely,
		   since the kinds are identical, either both will be
		   aware or both will be unaware */
	} else if (tval_can_have_charges(obj1) || tval_is_money(obj1)) {
		/* Gold, staves and wands stack most of the time */
		/* Too much gold or too many charges */
		if (obj1->pval + obj2->pval > MAX_PVAL)
			return false;

		/* ... otherwise ok */
	} else if (tval_is_weapon(obj1) || tval_is_armor(obj1) ||
		tval_is_jewelry(obj1) || tval_is_light(obj1)) {
		bool obj1_is_known = object_fully_known((struct object *)obj1);
		bool obj2_is_known = object_fully_known((struct object *)obj2);

		/* Require identical values */
		if (obj1->ac != obj2->ac) return false;
		if (obj1->dd != obj2->dd) return false;
		if (obj1->ds != obj2->ds) return false;

		/* Require identical bonuses */
		if (obj1->to_h != obj2->to_h) return false;
		if (obj1->to_d != obj2->to_d) return false;
		if (obj1->to_a != obj2->to_a) return false;

		/* Require all identical modifiers */
		for (i = 0; i < OBJ_MOD_MAX; i++)
			if (obj1->modifiers[i] != obj2->modifiers[i])
				return (false);

		/* Require identical ego-item types */
		if (obj1->ego != obj2->ego) return false;

		/* Require identical curses */
		if (!curses_are_equal(obj1->curses, obj2->curses)) return false;

		/* Hack - Never stack recharging wearables ... */
		if ((obj1->timeout || obj2->timeout) &&
			!tval_is_light(obj1)) return false;

		/* ... and lights must have same amount of fuel */
		else if ((obj1->timeout != obj2->timeout) &&
				 tval_is_light(obj1)) return false;

		/* Prevent unIDd items stacking with IDd items in the object list */
		if (mode & OSTACK_LIST && (obj1_is_known != obj2_is_known))
			return false;
	} else {
		/* Anything else probably okay */
	}

	/* Require compatible inscriptions */
	if (obj1->note && obj2->note && (obj1->note != obj2->note))
		return false;

	/* They must be similar enough */
	return true;
}
Ejemplo n.º 11
0
/**
 * Special descriptions for types of chest traps
 */
static size_t obj_desc_chest(const struct object *obj, char *buf, size_t max,
							 size_t end)
{
	bool known = object_is_known(obj);

	if (!tval_is_chest(obj)) return end;
	if (!known) return end;

	/* May be "empty" */
	if (!obj->pval)
		strnfcat(buf, max, &end, " (empty)");

	/* May be "disarmed" */
	else if (!is_locked_chest(obj))
	{
		if (chest_trap_type(obj) != 0)
			strnfcat(buf, max, &end, " (disarmed)");
		else
			strnfcat(buf, max, &end, " (unlocked)");
	}

	/* Describe the traps, if any */
	else
	{
		/* Describe the traps */
		switch (chest_trap_type(obj))
		{
			case 0:
				strnfcat(buf, max, &end, " (Locked)");
				break;

			case CHEST_LOSE_STR:
				strnfcat(buf, max, &end, " (Poison Needle)");
				break;

			case CHEST_LOSE_CON:
				strnfcat(buf, max, &end, " (Poison Needle)");
				break;

			case CHEST_POISON:
				strnfcat(buf, max, &end, " (Gas Trap)");
				break;

			case CHEST_PARALYZE:
				strnfcat(buf, max, &end, " (Gas Trap)");
				break;

			case CHEST_EXPLODE:
				strnfcat(buf, max, &end, " (Explosion Device)");
				break;

			case CHEST_SUMMON:
				strnfcat(buf, max, &end, " (Summoning Runes)");
				break;

			default:
				strnfcat(buf, max, &end, " (Multiple Traps)");
				break;
		}
	}

	return end;
}