/** * 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; }
/** * 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); }
/** * 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; }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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); }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }