From cbef37bd5bfb938a2303ee3887520c08be85d8e8 Mon Sep 17 00:00:00 2001 From: Bardur Arantsson Date: Tue, 26 Mar 2013 17:10:10 +0100 Subject: Switch almost everything over to C++ --- src/object2.cc | 6695 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 6695 insertions(+) create mode 100644 src/object2.cc (limited to 'src/object2.cc') diff --git a/src/object2.cc b/src/object2.cc new file mode 100644 index 00000000..59037ab1 --- /dev/null +++ b/src/object2.cc @@ -0,0 +1,6695 @@ +/* File: object2.c */ + +/* Purpose: Object code, part 2 */ + +/* + * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke + * + * This software may be copied and distributed for educational, research, and + * not for profit purposes provided that this copyright and statement are + * included in all such copies. + */ + +#include "angband.h" + +#include "spell_type.h" +#include "device_allocation.h" +#include "hooks.h" + +#include + +/* + * Calculate the player's total inventory weight. + */ +s32b calc_total_weight(void) +{ + int i; + s32b total; + for (i = total = 0; i < INVEN_TOTAL; i++) + { + object_type *o_ptr = &p_ptr->inventory[i]; + + if (o_ptr->k_idx) total += o_ptr->weight * o_ptr->number; + } + return total; +} + +/* + * Excise a dungeon object from any stacks + */ +void excise_object_idx(int o_idx) +{ + object_type *j_ptr; + + s16b this_o_idx, next_o_idx = 0; + + s16b prev_o_idx = 0; + + + /* Object */ + j_ptr = &o_list[o_idx]; + + /* Monster */ + if (j_ptr->held_m_idx) + { + monster_type *m_ptr; + + /* Monster */ + m_ptr = &m_list[j_ptr->held_m_idx]; + + /* Scan all objects in the grid */ + for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) + { + object_type * o_ptr; + + /* Acquire object */ + o_ptr = &o_list[this_o_idx]; + + /* Acquire next object */ + next_o_idx = o_ptr->next_o_idx; + + /* Done */ + if (this_o_idx == o_idx) + { + /* No previous */ + if (prev_o_idx == 0) + { + /* Remove from list */ + m_ptr->hold_o_idx = next_o_idx; + } + + /* Real previous */ + else + { + object_type *k_ptr; + + /* Previous object */ + k_ptr = &o_list[prev_o_idx]; + + /* Remove from list */ + k_ptr->next_o_idx = next_o_idx; + } + + /* Forget next pointer */ + o_ptr->next_o_idx = 0; + + /* Done */ + break; + } + + /* Save prev_o_idx */ + prev_o_idx = this_o_idx; + } + } + + /* Dungeon */ + else + { + cave_type *c_ptr; + + int y = j_ptr->iy; + int x = j_ptr->ix; + + /* Grid */ + c_ptr = &cave[y][x]; + + /* Scan all objects in the grid */ + for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) + { + object_type * o_ptr; + + /* Acquire object */ + o_ptr = &o_list[this_o_idx]; + + /* Acquire next object */ + next_o_idx = o_ptr->next_o_idx; + + /* Done */ + if (this_o_idx == o_idx) + { + /* No previous */ + if (prev_o_idx == 0) + { + /* Remove from list */ + c_ptr->o_idx = next_o_idx; + } + + /* Real previous */ + else + { + object_type *k_ptr; + + /* Previous object */ + k_ptr = &o_list[prev_o_idx]; + + /* Remove from list */ + k_ptr->next_o_idx = next_o_idx; + } + + /* Forget next pointer */ + o_ptr->next_o_idx = 0; + + /* Done */ + break; + } + + /* Save prev_o_idx */ + prev_o_idx = this_o_idx; + } + } +} + + +/* + * Delete a dungeon object + * + * Handle "stacks" of objects correctly. + */ +void delete_object_idx(int o_idx) +{ + object_type *j_ptr; + + /* Excise */ + excise_object_idx(o_idx); + + /* Object */ + j_ptr = &o_list[o_idx]; + + /* Dungeon floor */ + if (!(j_ptr->held_m_idx)) + { + int y, x; + + /* Location */ + y = j_ptr->iy; + x = j_ptr->ix; + + /* Visual update */ + lite_spot(y, x); + } + + /* Wipe the object */ + object_wipe(j_ptr); + + /* Count objects */ + o_cnt--; +} + + +/* + * Deletes all objects at given location + */ +void delete_object(int y, int x) +{ + cave_type *c_ptr; + + s16b this_o_idx, next_o_idx = 0; + + + /* Refuse "illegal" locations */ + if (!in_bounds(y, x)) return; + + + /* Grid */ + c_ptr = &cave[y][x]; + + /* Scan all objects in the grid */ + for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) + { + object_type * o_ptr; + + /* Acquire object */ + o_ptr = &o_list[this_o_idx]; + + /* Acquire next object */ + next_o_idx = o_ptr->next_o_idx; + + /* Wipe the object */ + object_wipe(o_ptr); + + /* Count objects */ + o_cnt--; + } + + /* Objects are gone */ + c_ptr->o_idx = 0; + + /* Visual update */ + lite_spot(y, x); +} + + +/* + * Move an object from index i1 to index i2 in the object list + */ +static void compact_objects_aux(int i1, int i2) +{ + int i; + + cave_type *c_ptr; + + object_type *o_ptr; + + + /* Do nothing */ + if (i1 == i2) return; + + + /* Repair objects */ + for (i = 1; i < o_max; i++) + { + /* Acquire object */ + o_ptr = &o_list[i]; + + /* Skip "dead" objects */ + if (!o_ptr->k_idx) continue; + + /* Repair "next" pointers */ + if (o_ptr->next_o_idx == i1) + { + /* Repair */ + o_ptr->next_o_idx = i2; + } + } + + + /* Acquire object */ + o_ptr = &o_list[i1]; + + + /* Monster */ + if (o_ptr->held_m_idx) + { + monster_type *m_ptr; + + /* Acquire monster */ + m_ptr = &m_list[o_ptr->held_m_idx]; + + /* Repair monster */ + if (m_ptr->hold_o_idx == i1) + { + /* Repair */ + m_ptr->hold_o_idx = i2; + } + } + + /* Dungeon */ + else + { + int y, x; + + /* Acquire location */ + y = o_ptr->iy; + x = o_ptr->ix; + + /* Acquire grid */ + c_ptr = &cave[y][x]; + + /* Repair grid */ + if (c_ptr->o_idx == i1) + { + /* Repair */ + c_ptr->o_idx = i2; + } + } + + + /* Structure copy */ + o_list[i2] = o_list[i1]; + + /* Wipe the hole */ + object_wipe(o_ptr); +} + + +/* + * Compact and Reorder the object list + * + * This function can be very dangerous, use with caution! + * + * When actually "compacting" objects, we base the saving throw on a + * combination of object level, distance from player, and current + * "desperation". + * + * After "compacting" (if needed), we "reorder" the objects into a more + * compact order, and we reset the allocation info, and the "live" array. + */ +void compact_objects(int size) +{ + int i, y, x, num; + + int cur_lev, cur_dis, chance; + + /* Compact */ + if (size) + { + /* Message */ + msg_print("Compacting objects..."); + + /* Redraw map */ + p_ptr->redraw |= (PR_MAP); + + /* Window stuff */ + p_ptr->window |= (PW_OVERHEAD); + } + + + /* Compact at least 'size' objects */ + for (num = 0, cur_lev = 1; num < size; cur_lev++) + { + /* Get closer each iteration (start at distance 12). Around level 100 distance-protect nothing. */ + cur_dis = 12 * (101 - cur_lev) / 100; + + /* Examine the objects */ + for (i = 1; i < o_max; i++) + { + object_type *o_ptr = &o_list[i]; + + object_kind *k_ptr = &k_info[o_ptr->k_idx]; + + /* Skip dead objects */ + if (!o_ptr->k_idx) continue; + + /* High level objects are "immune" as long as we're not desperate enough */ + if (k_ptr->level > cur_lev) continue; + + /* Monster owned objects */ + if (o_ptr->held_m_idx) + { + monster_type *m_ptr; + + /* Acquire monster */ + m_ptr = &m_list[o_ptr->held_m_idx]; + + /* Monsters start with protecting objects well */ + chance = 100; + + /* Get the location */ + y = m_ptr->fy; + x = m_ptr->fx; + } + /* Dungeon floor objects */ + else + { + /* Floor objects start with lower protection */ + chance = 90; + + /* Get the location */ + y = o_ptr->iy; + x = o_ptr->ix; + } + + /* Near enough objects are "immune", even if low level */ + /* (like, importantly, food rations after hitting a trap of drop items) */ + if ((cur_dis > 0) && (distance(p_ptr->py, p_ptr->px, y, x) < cur_dis)) continue; + + /* object protection goes down as we get vicious */ + /* around level 200 only artifacts have protection */ + chance = chance - cur_lev / 2; + + /* Artifacts */ + if ( artifact_p(o_ptr) || o_ptr->art_name ) + { + /* Artifacts are "immune if the level is lower */ + /* than 300 + artifact level */ + if ( cur_lev < 300 + k_ptr->level ) + continue; + + /* That's 400 + level for fixed artifacts */ + if ( (k_ptr->flags3 & TR3_NORM_ART) && cur_lev < 400 + k_ptr->level ) + continue; + + /* Never protect if level is high enough; so we don't wipe a better artifact */ + chance = -1; + + /* rewind the level so we never wipe many */ + /* artifacts of same level if one will do!!! */ + cur_lev--; + } + + /* Maybe some code to spare the God relic here. But I'd rather raise its level to 150 */ + + /* Apply the saving throw */ + if (rand_int(100) < chance) continue; + + /* Delete the object */ + delete_object_idx(i); + + /* Count it */ + num++; + } + } + + + /* Excise dead objects (backwards!) */ + for (i = o_max - 1; i >= 1; i--) + { + object_type *o_ptr = &o_list[i]; + + /* Skip real objects */ + if (o_ptr->k_idx) continue; + + /* Move last object into open hole */ + compact_objects_aux(o_max - 1, i); + + /* Compress "o_max" */ + o_max--; + } +} + + + + +/* + * Delete all the items when player leaves the level + * + * Note -- we do NOT visually reflect these (irrelevant) changes + * + * Hack -- we clear the "c_ptr->o_idx" field for every grid, + * and the "m_ptr->next_o_idx" field for every monster, since + * we know we are clearing every object. Technically, we only + * clear those fields for grids/monsters containing objects, + * and we clear it once for every such object. + */ +void wipe_o_list(void) +{ + int i; + + /* Delete the existing objects */ + for (i = 1; i < o_max; i++) + { + object_type *o_ptr = &o_list[i]; + + /* Skip dead objects */ + if (!o_ptr->k_idx) continue; + + /* Mega-Hack -- preserve artifacts */ + if (!character_dungeon || p_ptr->preserve) + { + /* Hack -- Preserve unknown artifacts */ + if (artifact_p(o_ptr) && !object_known_p(o_ptr)) + { + /* Mega-Hack -- Preserve the artifact */ + if (o_ptr->tval == TV_RANDART) + { + random_artifacts[o_ptr->sval].generated = FALSE; + } + else if (k_info[o_ptr->k_idx].flags3 & TR3_NORM_ART) + { + k_info[o_ptr->k_idx].artifact = FALSE; + } + else + { + a_info[o_ptr->name1].cur_num = 0; + } + } + } + + /* Monster */ + if (o_ptr->held_m_idx) + { + monster_type *m_ptr; + + /* Monster */ + m_ptr = &m_list[o_ptr->held_m_idx]; + + /* Hack -- see above */ + m_ptr->hold_o_idx = 0; + } + + /* Dungeon */ + else + { + cave_type *c_ptr; + + /* Access location */ + int y = o_ptr->iy; + int x = o_ptr->ix; + + /* Access grid */ + c_ptr = &cave[y][x]; + + /* Hack -- see above */ + c_ptr->o_idx = 0; + } + + /* Wipe the object */ + WIPE(o_ptr, object_type); + } + + /* Reset "o_max" */ + o_max = 1; + + /* Reset "o_cnt" */ + o_cnt = 0; +} + + +/* + * Acquires and returns the index of a "free" object. + * + * This routine should almost never fail, but in case it does, + * we must be sure to handle "failure" of this routine. + */ +s16b o_pop(void) +{ + int i; + + + /* Initial allocation */ + if (o_max < max_o_idx) + { + /* Get next space */ + i = o_max; + + /* Expand object array */ + o_max++; + + /* Count objects */ + o_cnt++; + + /* Use this object */ + return (i); + } + + + /* Recycle dead objects */ + for (i = 1; i < o_max; i++) + { + object_type *o_ptr; + + /* Acquire object */ + o_ptr = &o_list[i]; + + /* Skip live objects */ + if (o_ptr->k_idx) continue; + + /* Count objects */ + o_cnt++; + + /* Use this object */ + return (i); + } + + + /* Warn the player (except during dungeon creation) */ + if (character_dungeon) msg_print("Too many objects!"); + + /* Oops */ + return (0); +} + + + +/* + * Apply a "object restriction function" to the "object allocation table" + */ +errr get_obj_num_prep(void) +{ + int i; + + /* Get the entry */ + alloc_entry *table = alloc_kind_table; + + /* Scan the allocation table */ + for (i = 0; i < alloc_kind_size; i++) + { + /* Accept objects which pass the restriction, if any */ + if (!get_obj_num_hook || (*get_obj_num_hook)(table[i].index)) + { + /* Accept this object */ + table[i].prob2 = table[i].prob1; + } + + /* Do not use this object */ + else + { + /* Decline this object */ + table[i].prob2 = 0; + } + } + + /* Success */ + return (0); +} + + + +/* + * Choose an object kind that seems "appropriate" to the given level + * + * This function uses the "prob2" field of the "object allocation table", + * and various local information, to calculate the "prob3" field of the + * same table, which is then used to choose an "appropriate" object, in + * a relatively efficient manner. + * + * It is (slightly) more likely to acquire an object of the given level + * than one of a lower level. This is done by choosing several objects + * appropriate to the given level and keeping the "hardest" one. + * + * Note that if no objects are "appropriate", then this function will + * fail, and return zero, but this should *almost* never happen. + */ +s16b get_obj_num(int level) +{ + int i, j, p; + int k_idx; + long value, total; + object_kind *k_ptr; + alloc_entry *table = alloc_kind_table; + + + /* Boost level */ + if (level > 0) + { + /* Occasional "boost" */ + if (rand_int(GREAT_OBJ) == 0) + { + /* What a bizarre calculation */ + level = 1 + (level * MAX_DEPTH / randint(MAX_DEPTH)); + } + } + + + /* Reset total */ + total = 0L; + + /* Process probabilities */ + for (i = 0; i < alloc_kind_size; i++) + { + /* Objects are sorted by depth */ + if (table[i].level > level) break; + + /* Default */ + table[i].prob3 = 0; + + /* Access the index */ + k_idx = table[i].index; + + /* Access the actual kind */ + k_ptr = &k_info[k_idx]; + + /* Hack -- prevent embedded chests */ + if (opening_chest && (k_ptr->tval == TV_CHEST)) continue; + + /* Accept */ + table[i].prob3 = table[i].prob2; + + /* Total */ + total += table[i].prob3; + } + + /* No legal objects */ + if (total <= 0) return (0); + + + /* Pick an object */ + value = rand_int(total); + + /* Find the object */ + for (i = 0; i < alloc_kind_size; i++) + { + /* Found the entry */ + if (value < table[i].prob3) break; + + /* Decrement */ + value = value - table[i].prob3; + } + + + /* Power boost */ + p = rand_int(100); + + /* Try for a "better" object once (50%) or twice (10%) */ + if (p < 60) + { + /* Save old */ + j = i; + + /* Pick a object */ + value = rand_int(total); + + /* Find the monster */ + for (i = 0; i < alloc_kind_size; i++) + { + /* Found the entry */ + if (value < table[i].prob3) break; + + /* Decrement */ + value = value - table[i].prob3; + } + + /* Keep the "best" one */ + if (table[i].level < table[j].level) i = j; + } + + /* Try for a "better" object twice (10%) */ + if (p < 10) + { + /* Save old */ + j = i; + + /* Pick a object */ + value = rand_int(total); + + /* Find the object */ + for (i = 0; i < alloc_kind_size; i++) + { + /* Found the entry */ + if (value < table[i].prob3) break; + + /* Decrement */ + value = value - table[i].prob3; + } + + /* Keep the "best" one */ + if (table[i].level < table[j].level) i = j; + } + + + /* Result */ + return (table[i].index); +} + + + + + + + + +/* + * Known is true when the "attributes" of an object are "known". + * These include tohit, todam, toac, cost, and pval (charges). + * + * Note that "knowing" an object gives you everything that an "awareness" + * gives you, and much more. In fact, the player is always "aware" of any + * item of which he has full "knowledge". + * + * But having full knowledge of, say, one "wand of wonder", does not, by + * itself, give you knowledge, or even awareness, of other "wands of wonder". + * It happens that most "identify" routines (including "buying from a shop") + * will make the player "aware" of the object as well as fully "know" it. + * + * This routine also removes any inscriptions generated by "feelings". + */ +void object_known(object_type *o_ptr) +{ + + /* No Sensing */ + o_ptr->sense = SENSE_NONE; + + /* Clear the "Felt" info */ + o_ptr->ident &= ~(IDENT_SENSE); + + /* Clear the "Empty" info */ + o_ptr->ident &= ~(IDENT_EMPTY); + + /* Now we know about the item */ + o_ptr->ident |= (IDENT_KNOWN); +} + + + + + +/* + * The player is now aware of the effects of the given object. + */ +void object_aware(object_type *o_ptr) +{ + /* Fully aware of the effects */ + k_info[o_ptr->k_idx].aware = TRUE; +} + + + +/* + * Something has been "sampled" + */ +void object_tried(object_type *o_ptr) +{ + /* Mark it as tried (even if "aware") */ + k_info[o_ptr->k_idx].tried = TRUE; +} + + + +/* + * Return the "value" of an "unknown" item + * Make a guess at the value of non-aware items + */ +static s32b object_value_base(object_type *o_ptr) +{ + object_kind *k_ptr = &k_info[o_ptr->k_idx]; + + /* Aware item -- use template cost */ + if ((object_aware_p(o_ptr)) && (o_ptr->tval != TV_EGG)) return (k_ptr->cost); + + /* Analyze the type */ + switch (o_ptr->tval) + { + /* Un-aware Food */ + case TV_FOOD: + return (5L); + + /* Un-aware Potions */ + case TV_POTION2: + return (20L); + + /* Un-aware Potions */ + case TV_POTION: + return (20L); + + /* Un-aware Scrolls */ + case TV_SCROLL: + return (20L); + + /* Un-aware Staffs */ + case TV_STAFF: + return (70L); + + /* Un-aware Wands */ + case TV_WAND: + return (50L); + + /* Un-aware Rods */ + case TV_ROD: + return (90L); + + /* Un-aware Rings */ + case TV_RING: + return (45L); + + /* Un-aware Amulets */ + case TV_AMULET: + return (45L); + + /* Eggs */ + case TV_EGG: + { + monster_race *r_ptr = &r_info[o_ptr->pval2]; + + /* Pay the monster level */ + return (r_ptr->level * 100) + 100; + + /* Done */ + break; + } + } + + /* Paranoia -- Oops */ + return (0L); +} + +/* Return the value of the flags the object has... */ +s32b flag_cost(object_type * o_ptr, int plusses) +{ + s32b total = 0; + u32b f1, f2, f3, f4, f5, esp; + + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + if (f5 & TR5_TEMPORARY) + { + return 0; + } + if (f4 & TR4_CURSE_NO_DROP) + { + return 0; + } + if (f1 & TR1_STR) total += (1000 * plusses); + if (f1 & TR1_INT) total += (1000 * plusses); + if (f1 & TR1_WIS) total += (1000 * plusses); + if (f1 & TR1_DEX) total += (1000 * plusses); + if (f1 & TR1_CON) total += (1000 * plusses); + if (f1 & TR1_CHR) total += (250 * plusses); + if (f1 & TR1_CHAOTIC) total += 10000; + if (f1 & TR1_VAMPIRIC) total += 13000; + if (f1 & TR1_STEALTH) total += (250 * plusses); + if (f1 & TR1_SEARCH) total += (100 * plusses); + if (f1 & TR1_INFRA) total += (150 * plusses); + if (f1 & TR1_TUNNEL) total += (175 * plusses); + if ((f1 & TR1_SPEED) && (plusses > 0)) + total += (10000 + (2500 * plusses)); + if ((f1 & TR1_BLOWS) && (plusses > 0)) + total += (10000 + (2500 * plusses)); + if (f1 & TR1_MANA) total += (1000 * plusses); + if (f1 & TR1_SPELL) total += (2000 * plusses); + if (f1 & TR1_SLAY_ANIMAL) total += 3500; + if (f1 & TR1_SLAY_EVIL) total += 4500; + if (f1 & TR1_SLAY_UNDEAD) total += 3500; + if (f1 & TR1_SLAY_DEMON) total += 3500; + if (f1 & TR1_SLAY_ORC) total += 3000; + if (f1 & TR1_SLAY_TROLL) total += 3500; + if (f1 & TR1_SLAY_GIANT) total += 3500; + if (f1 & TR1_SLAY_DRAGON) total += 3500; + if (f5 & TR5_KILL_DEMON) total += 5500; + if (f5 & TR5_KILL_UNDEAD) total += 5500; + if (f1 & TR1_KILL_DRAGON) total += 5500; + if (f1 & TR1_VORPAL) total += 5000; + if (f1 & TR1_IMPACT) total += 5000; + if (f1 & TR1_BRAND_POIS) total += 7500; + if (f1 & TR1_BRAND_ACID) total += 7500; + if (f1 & TR1_BRAND_ELEC) total += 7500; + if (f1 & TR1_BRAND_FIRE) total += 5000; + if (f1 & TR1_BRAND_COLD) total += 5000; + if (f2 & TR2_SUST_STR) total += 850; + if (f2 & TR2_SUST_INT) total += 850; + if (f2 & TR2_SUST_WIS) total += 850; + if (f2 & TR2_SUST_DEX) total += 850; + if (f2 & TR2_SUST_CON) total += 850; + if (f2 & TR2_SUST_CHR) total += 250; + if (f2 & TR2_INVIS) total += 3000; + if (f2 & TR2_LIFE) total += (5000 * plusses); + if (f2 & TR2_IM_ACID) total += 10000; + if (f2 & TR2_IM_ELEC) total += 10000; + if (f2 & TR2_IM_FIRE) total += 10000; + if (f2 & TR2_IM_COLD) total += 10000; + if (f2 & TR2_SENS_FIRE) total -= 100; + if (f2 & TR2_REFLECT) total += 10000; + if (f2 & TR2_FREE_ACT) total += 4500; + if (f2 & TR2_HOLD_LIFE) total += 8500; + if (f2 & TR2_RES_ACID) total += 1250; + if (f2 & TR2_RES_ELEC) total += 1250; + if (f2 & TR2_RES_FIRE) total += 1250; + if (f2 & TR2_RES_COLD) total += 1250; + if (f2 & TR2_RES_POIS) total += 2500; + if (f2 & TR2_RES_FEAR) total += 2500; + if (f2 & TR2_RES_LITE) total += 1750; + if (f2 & TR2_RES_DARK) total += 1750; + if (f2 & TR2_RES_BLIND) total += 2000; + if (f2 & TR2_RES_CONF) total += 2000; + if (f2 & TR2_RES_SOUND) total += 2000; + if (f2 & TR2_RES_SHARDS) total += 2000; + if (f2 & TR2_RES_NETHER) total += 2000; + if (f2 & TR2_RES_NEXUS) total += 2000; + if (f2 & TR2_RES_CHAOS) total += 2000; + if (f2 & TR2_RES_DISEN) total += 10000; + if (f3 & TR3_SH_FIRE) total += 5000; + if (f3 & TR3_SH_ELEC) total += 5000; + if (f3 & TR3_DECAY) total += 0; + if (f3 & TR3_NO_TELE) total += 2500; + if (f3 & TR3_NO_MAGIC) total += 2500; + if (f3 & TR3_WRAITH) total += 250000; + if (f3 & TR3_TY_CURSE) total -= 15000; + if (f3 & TR3_EASY_KNOW) total += 0; + if (f3 & TR3_HIDE_TYPE) total += 0; + if (f3 & TR3_SHOW_MODS) total += 0; + if (f3 & TR3_INSTA_ART) total += 0; + if (f3 & TR3_LITE1) total += 750; + if (f4 & TR4_LITE2) total += 1250; + if (f4 & TR4_LITE3) total += 2750; + if (f3 & TR3_SEE_INVIS) total += 2000; + if (esp) total += (12500 * count_bits(esp)); + if (f3 & TR3_SLOW_DIGEST) total += 750; + if (f3 & TR3_REGEN) total += 2500; + if (f3 & TR3_XTRA_MIGHT) total += 2250; + if (f3 & TR3_XTRA_SHOTS) total += 10000; + if (f3 & TR3_IGNORE_ACID) total += 100; + if (f3 & TR3_IGNORE_ELEC) total += 100; + if (f3 & TR3_IGNORE_FIRE) total += 100; + if (f3 & TR3_IGNORE_COLD) total += 100; + if (f3 & TR3_ACTIVATE) total += 100; + if (f3 & TR3_DRAIN_EXP) total -= 12500; + if (f3 & TR3_TELEPORT) + { + if (o_ptr->ident & IDENT_CURSED) + total -= 7500; + else + total += 250; + } + if (f3 & TR3_AGGRAVATE) total -= 10000; + if (f3 & TR3_BLESSED) total += 750; + if ((f3 & TR3_CURSED) && (o_ptr->ident & IDENT_CURSED)) total -= 5000; + if ((f3 & TR3_HEAVY_CURSE) && (o_ptr->ident & IDENT_CURSED)) total -= 12500; + if (f3 & TR3_PERMA_CURSE) total -= 15000; + if (f3 & TR3_FEATHER) total += 1250; + if (f4 & TR4_FLY) total += 10000; + if (f4 & TR4_NEVER_BLOW) total -= 15000; + if (f4 & TR4_PRECOGNITION) total += 250000; + if (f4 & TR4_BLACK_BREATH) total -= 12500; + if (f4 & TR4_DG_CURSE) total -= 25000; + if (f4 & TR4_CLONE) total -= 10000; + if (f4 & TR4_LEVELS) total += o_ptr->elevel * 2000; + + /* Also, give some extra for activatable powers... */ + + if ((o_ptr->art_name) && (o_ptr->art_flags3 & (TR3_ACTIVATE))) + { + int type = o_ptr->xtra2; + + if (type == ACT_SUNLIGHT) total += 250; + else if (type == ACT_BO_MISS_1) total += 250; + else if (type == ACT_BA_POIS_1) total += 300; + else if (type == ACT_BO_ELEC_1) total += 250; + else if (type == ACT_BO_ACID_1) total += 250; + else if (type == ACT_BO_COLD_1) total += 250; + else if (type == ACT_BO_FIRE_1) total += 250; + else if (type == ACT_BA_COLD_1) total += 750; + else if (type == ACT_BA_FIRE_1) total += 1000; + else if (type == ACT_DRAIN_1) total += 500; + else if (type == ACT_BA_COLD_2) total += 1250; + else if (type == ACT_BA_ELEC_2) total += 1500; + else if (type == ACT_DRAIN_2) total += 750; + else if (type == ACT_VAMPIRE_1) total += 1000; + else if (type == ACT_BO_MISS_2) total += 1000; + else if (type == ACT_BA_FIRE_2) total += 1750; + else if (type == ACT_BA_COLD_3) total += 2500; + else if (type == ACT_BA_ELEC_3) total += 2500; + else if (type == ACT_WHIRLWIND) total += 7500; + else if (type == ACT_VAMPIRE_2) total += 2500; + else if (type == ACT_CALL_CHAOS) total += 5000; + else if (type == ACT_ROCKET) total += 5000; + else if (type == ACT_DISP_EVIL) total += 4000; + else if (type == ACT_DISP_GOOD) total += 3500; + else if (type == ACT_BA_MISS_3) total += 5000; + else if (type == ACT_CONFUSE) total += 500; + else if (type == ACT_SLEEP) total += 750; + else if (type == ACT_QUAKE) total += 600; + else if (type == ACT_TERROR) total += 2500; + else if (type == ACT_TELE_AWAY) total += 2000; + else if (type == ACT_GENOCIDE) total += 10000; + else if (type == ACT_MASS_GENO) total += 10000; + else if (type == ACT_CHARM_ANIMAL) total += 7500; + else if (type == ACT_CHARM_UNDEAD) total += 10000; + else if (type == ACT_CHARM_OTHER) total += 10000; + else if (type == ACT_CHARM_ANIMALS) total += 12500; + else if (type == ACT_CHARM_OTHERS) total += 17500; + else if (type == ACT_SUMMON_ANIMAL) total += 10000; + else if (type == ACT_SUMMON_PHANTOM) total += 12000; + else if (type == ACT_SUMMON_ELEMENTAL) total += 15000; + else if (type == ACT_SUMMON_DEMON) total += 20000; + else if (type == ACT_SUMMON_UNDEAD) total += 20000; + else if (type == ACT_CURE_LW) total += 500; + else if (type == ACT_CURE_MW) total += 750; + else if (type == ACT_REST_LIFE) total += 7500; + else if (type == ACT_REST_ALL) total += 15000; + else if (type == ACT_CURE_700) total += 10000; + else if (type == ACT_CURE_1000) total += 15000; + else if (type == ACT_ESP) total += 1500; + else if (type == ACT_BERSERK) total += 800; + else if (type == ACT_PROT_EVIL) total += 5000; + else if (type == ACT_RESIST_ALL) total += 5000; + else if (type == ACT_SPEED) total += 15000; + else if (type == ACT_XTRA_SPEED) total += 25000; + else if (type == ACT_WRAITH) total += 25000; + else if (type == ACT_INVULN) total += 25000; + else if (type == ACT_LIGHT) total += 150; + else if (type == ACT_MAP_LIGHT) total += 500; + else if (type == ACT_DETECT_ALL) total += 1000; + else if (type == ACT_DETECT_XTRA) total += 12500; + else if (type == ACT_ID_FULL) total += 10000; + else if (type == ACT_ID_PLAIN) total += 1250; + else if (type == ACT_RUNE_EXPLO) total += 4000; + else if (type == ACT_RUNE_PROT) total += 10000; + else if (type == ACT_SATIATE) total += 2000; + else if (type == ACT_DEST_DOOR) total += 100; + else if (type == ACT_STONE_MUD) total += 1000; + else if (type == ACT_RECHARGE) total += 1000; + else if (type == ACT_ALCHEMY) total += 10000; + else if (type == ACT_DIM_DOOR) total += 10000; + else if (type == ACT_TELEPORT) total += 2000; + else if (type == ACT_RECALL) total += 7500; + } + + return total; +} + + + +/* + * Return the "real" price of a "known" item, not including discounts + * + * Wand and staffs get cost for each charge + * + * Armor is worth an extra 100 gold per bonus point to armor class. + * + * Weapons are worth an extra 100 gold per bonus point (AC,TH,TD). + * + * Missiles are only worth 5 gold per bonus point, since they + * usually appear in groups of 20, and we want the player to get + * the same amount of cash for any "equivalent" item. Note that + * missiles never have any of the "pval" flags, and in fact, they + * only have a few of the available flags, primarily of the "slay" + * and "brand" and "ignore" variety. + * + * Armor with a negative armor bonus is worthless. + * Weapons with negative hit+damage bonuses are worthless. + * + * Every wearable item with a "pval" bonus is worth extra (see below). + */ +s32b object_value_real(object_type *o_ptr) +{ + s32b value; + + u32b f1, f2, f3, f4, f5, esp; + + object_kind *k_ptr = &k_info[o_ptr->k_idx]; + + if (o_ptr->tval == TV_RANDART) + { + return random_artifacts[o_ptr->sval].cost; + } + + /* Hack -- "worthless" items */ + if (!k_ptr->cost) return (0L); + + /* Base cost */ + value = k_ptr->cost; + + /* Extract some flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + if (f5 & TR5_TEMPORARY) return (0L); + + if (o_ptr->art_flags1 || o_ptr->art_flags2 || o_ptr->art_flags3) + { + value += flag_cost (o_ptr, o_ptr->pval); + } + /* Artifact */ + else if (o_ptr->name1) + { + artifact_type *a_ptr = &a_info[o_ptr->name1]; + + /* Hack -- "worthless" artifacts */ + if (!a_ptr->cost) return (0L); + + /* Hack -- Use the artifact cost instead */ + value = a_ptr->cost; + } + + /* Ego-Item */ + else if (o_ptr->name2) + { + ego_item_type *e_ptr = &e_info[o_ptr->name2]; + + /* Hack -- "worthless" ego-items */ + if (!e_ptr->cost) return (0L); + + /* Hack -- Reward the ego-item with a bonus */ + value += e_ptr->cost; + + if (o_ptr->name2b) + { + ego_item_type *e_ptr = &e_info[o_ptr->name2b]; + + /* Hack -- "worthless" ego-items */ + if (!e_ptr->cost) return (0L); + + /* Hack -- Reward the ego-item with a bonus */ + value += e_ptr->cost; + } + } + + /* Pay the spell */ + if (f5 & TR5_SPELL_CONTAIN) + { + if (o_ptr->pval2 != -1) + value += 5000 + 500 * spell_type_skill_level(spell_at(o_ptr->pval2)); + else + value += 5000; + } + + /* Analyze pval bonus */ + switch (o_ptr->tval) + { + case TV_BOW: + case TV_BOOMERANG: + case TV_DIGGING: + case TV_HAFTED: + case TV_POLEARM: + case TV_SWORD: + case TV_AXE: + case TV_BOOTS: + case TV_GLOVES: + case TV_HELM: + case TV_CROWN: + case TV_SHIELD: + case TV_CLOAK: + case TV_SOFT_ARMOR: + case TV_HARD_ARMOR: + case TV_DRAG_ARMOR: + case TV_LITE: + case TV_AMULET: + case TV_RING: + case TV_MSTAFF: + case TV_TRAPKIT: + case TV_INSTRUMENT: + { + /* No pval */ + if (!o_ptr->pval) break; + + /* Give credit for stat bonuses */ + if (f1 & (TR1_STR)) value += (o_ptr->pval * 200L); + if (f1 & (TR1_INT)) value += (o_ptr->pval * 200L); + if (f1 & (TR1_WIS)) value += (o_ptr->pval * 200L); + if (f1 & (TR1_DEX)) value += (o_ptr->pval * 200L); + if (f1 & (TR1_CON)) value += (o_ptr->pval * 200L); + if (f1 & (TR1_CHR)) value += (o_ptr->pval * 200L); + + if (f5 & (TR5_CRIT)) value += (o_ptr->pval * 500L); + + /* Give credit for stealth and searching */ + if (f1 & (TR1_STEALTH)) value += (o_ptr->pval * 100L); + if (f1 & (TR1_SEARCH)) value += (o_ptr->pval * 100L); + + /* Give credit for infra-vision and tunneling */ + if (f1 & (TR1_INFRA)) value += (o_ptr->pval * 50L); + if (f1 & (TR1_TUNNEL)) value += (o_ptr->pval * 50L); + + /* Give credit for extra attacks */ + if (f1 & (TR1_BLOWS)) value += (o_ptr->pval * 2000L); + + /* Give credit for speed bonus */ + if (f1 & (TR1_SPEED)) value += (o_ptr->pval * 30000L); + + break; + } + } + + + /* Analyze the item */ + switch (o_ptr->tval) + { + /* Eggs */ + case TV_EGG: + { + monster_race *r_ptr = &r_info[o_ptr->pval2]; + + /* Pay the monster level */ + value += r_ptr->level * 100; + + /* Done */ + break; + } + + /* Wands/Staffs */ + case TV_WAND: + { + /* Par for the spell */ + value *= spell_type_skill_level(spell_at(o_ptr->pval2)); + /* Take the average of the base and max spell levels */ + value *= (((o_ptr->pval3 >> 16) & 0xFFFF) + (o_ptr->pval3 & 0xFFFF)) / 2; + /* Hack */ + value /= 6; + + /* Pay extra for charges */ + value += ((value / 20) * o_ptr->pval) / o_ptr->number; + + /* Done */ + break; + } + case TV_STAFF: + { + /* Par for the spell */ + value *= spell_type_skill_level(spell_at(o_ptr->pval2)); + /* Take the average of the base and max spell levels */ + value *= (((o_ptr->pval3 >> 16) & 0xFFFF) + (o_ptr->pval3 & 0xFFFF)) / 2; + /* Hack */ + value /= 6; + + /* Pay extra for charges */ + value += ((value / 20) * o_ptr->pval); + + /* Done */ + break; + } + case TV_BOOK: + { + if (o_ptr->sval == 255) + { + /* Pay extra for the spell */ + value = value * spell_type_skill_level(spell_at(o_ptr->pval)); + } + /* Done */ + break; + } + + /* Rods */ + case TV_ROD_MAIN: + { + s16b tip_idx; + + /* It's not combined */ + if (o_ptr->pval == 0) break; + + /* Look up the tip attached */ + tip_idx = lookup_kind(TV_ROD, o_ptr->pval); + + /* Paranoia */ + if (tip_idx > 0) + { + /* Add its cost */ + value += k_info[tip_idx].cost; + } + + /* Done */ + break; + } + + /* Rings/Amulets */ + case TV_RING: + case TV_AMULET: + { + /* Hack -- negative bonuses are bad */ + if (o_ptr->to_a < 0 && !value) return (0L); + if (o_ptr->to_h < 0 && !value) return (0L); + if (o_ptr->to_d < 0 && !value) return (0L); + + /* Give credit for bonuses */ + value += ((o_ptr->to_h + o_ptr->to_d + o_ptr->to_a) * 100L); + + /* Done */ + break; + } + + /* Armor */ + case TV_BOOTS: + case TV_GLOVES: + case TV_CLOAK: + case TV_CROWN: + case TV_HELM: + case TV_SHIELD: + case TV_SOFT_ARMOR: + case TV_HARD_ARMOR: + case TV_DRAG_ARMOR: + { + /* Hack -- negative armor bonus */ + if (o_ptr->to_a < 0 && !value) return (0L); + + /* Give credit for bonuses */ + value += ((o_ptr->to_h + o_ptr->to_d + o_ptr->to_a) * 100L); + + /* Done */ + break; + } + + /* Bows/Weapons */ + case TV_BOW: + case TV_BOOMERANG: + case TV_DIGGING: + case TV_HAFTED: + case TV_SWORD: + case TV_DAEMON_BOOK: + case TV_AXE: + case TV_POLEARM: + case TV_TRAPKIT: + { + /* Hack -- negative hit/damage bonuses */ + if (o_ptr->to_h + o_ptr->to_d < 0 && !value) return (0L); + + /* Factor in the bonuses */ + value += ((o_ptr->to_h + o_ptr->to_d + o_ptr->to_a) * 100L); + + /* Hack -- Factor in extra damage dice */ + if ((o_ptr->dd > k_ptr->dd) && (o_ptr->ds == k_ptr->ds)) + { + value += (o_ptr->dd - k_ptr->dd) * o_ptr->ds * 100L; + } + + /* Done */ + break; + } + + /* Ammo */ + case TV_SHOT: + case TV_ARROW: + case TV_BOLT: + { + /* Hack -- negative hit/damage bonuses */ + if (o_ptr->to_h + o_ptr->to_d < 0 && !value) return (0L); + + /* Factor in the bonuses */ + value += ((o_ptr->to_h + o_ptr->to_d) * 5L); + + /* Hack -- Factor in extra damage dice */ + if ((o_ptr->dd > k_ptr->dd) && (o_ptr->ds == k_ptr->ds)) + { + value += (o_ptr->dd - k_ptr->dd) * o_ptr->ds * 5L; + } + + /* Special attack (exploding arrow) */ + if (o_ptr->pval2 != 0) value *= 14; + + /* Done */ + break; + } + } + + /* Return the value */ + return (value); +} + + +/* + * Return the price of an item including plusses (and charges) + * + * This function returns the "value" of the given item (qty one) + * + * Never notice "unknown" bonuses or properties, including "curses", + * since that would give the player information he did not have. + * + * Note that discounted items stay discounted forever, even if + * the discount is "forgotten" by the player via memory loss. + */ +s32b object_value(object_type *o_ptr) +{ + s32b value; + + + /* Unknown items -- acquire a base value */ + if (object_known_p(o_ptr)) + { + /* Cursed items -- worthless */ + if (cursed_p(o_ptr)) return (0L); + + /* Real value (see above) */ + value = object_value_real(o_ptr); + } + + /* Known items -- acquire the actual value */ + else + { + /* Hack -- Felt cursed items */ + if ((o_ptr->ident & (IDENT_SENSE)) && cursed_p(o_ptr)) return (0L); + + /* Base value (see above) */ + value = object_value_base(o_ptr); + } + + + /* Apply discount (if any) */ + if (o_ptr->discount) value -= (value * o_ptr->discount / 100L); + + + /* Return the final value */ + return (value); +} + + + + + +/* + * Determine if an item can "absorb" a second item + * + * See "object_absorb()" for the actual "absorption" code. + * + * If permitted, we allow wands/staffs (if they are known to have equal + * charges) and rods (if fully charged) to combine. They will unstack + * (if necessary) when they are used. + * + * If permitted, we allow weapons/armor to stack, if fully "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, never stack (for various reasons). + */ +bool_ object_similar(object_type *o_ptr, object_type *j_ptr) +{ + int total = o_ptr->number + j_ptr->number; + u32b f1, f2, f3, f4, f5, esp, f11, f12, f13, f14, esp1, f15; + + /* Extract the flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + object_flags(j_ptr, &f11, &f12, &f13, &f14, &f15, &esp1); + + + /* Require identical object types */ + if (o_ptr->k_idx != j_ptr->k_idx) return (0); + + if ((f5 & TR5_SPELL_CONTAIN) || (f15 & TR5_SPELL_CONTAIN)) + return FALSE; + + /* Analyze the items */ + switch (o_ptr->tval) + { + /* School Book */ + case TV_BOOK: + { + if (!object_known_p(o_ptr) || !object_known_p(j_ptr)) return FALSE; + + /* Beware artifatcs should not combibne with "lesser" thing */ + if (artifact_p(o_ptr) != artifact_p(j_ptr)) return (FALSE); + + /* Do not combine different ego or normal ones */ + if (ego_item_p(o_ptr) != ego_item_p(j_ptr)) return (FALSE); + + /* Random books should stack if they are identical */ + if ((o_ptr->sval == 255) && (j_ptr->sval == 255)) + { + if (o_ptr->pval != j_ptr->pval) + return (FALSE); + } + + return (TRUE); + } + + /* Chests */ + case TV_CHEST: + { + /* Never okay */ + return (0); + } + + case TV_RANDART: + { + return FALSE; + } + + case TV_RUNE1: + { + return TRUE; + } + + case TV_RUNE2: + { + if ((o_ptr->sval == RUNE_STONE) || (j_ptr->sval == RUNE_STONE)) return FALSE; + else return TRUE; + } + + case TV_INSTRUMENT: + { + return FALSE; + } + + case TV_HYPNOS: + case TV_EGG: + { + return FALSE; + } + + /* Totems */ + case TV_TOTEM: + { + if ((o_ptr->pval == j_ptr->pval) && (o_ptr->pval2 == j_ptr->pval2)) return TRUE; + return FALSE; + } + + /* Corpses*/ + case TV_CORPSE: + { + return FALSE; + } + + /* Food and Potions and Scrolls */ + case TV_POTION: + case TV_POTION2: + { + if (o_ptr->pval2 != j_ptr->pval2) return FALSE; + + /* Assume okay */ + break; + } + + case TV_SCROLL: + { + if (o_ptr->pval != j_ptr->pval) return FALSE; + if (o_ptr->pval2 != j_ptr->pval2) return FALSE; + break; + } + + /* Staffs */ + case TV_STAFF: + { + /* Require either knowledge or known empty for both staffs. */ + if ((!(o_ptr->ident & (IDENT_EMPTY)) && + !object_known_p(o_ptr)) || + (!(j_ptr->ident & (IDENT_EMPTY)) && + !object_known_p(j_ptr))) return (0); + + /* Require identical charges, since staffs are bulky. */ + if (o_ptr->pval != j_ptr->pval) return (0); + + /* Do not combine recharged ones with non recharged ones. */ + if ((f4 & TR4_RECHARGED) != (f14 & TR4_RECHARGED)) return (0); + + /* Do not combine different spells */ + if (o_ptr->pval2 != j_ptr->pval2) return (0); + + /* Do not combine different base levels */ + if (o_ptr->pval3 != j_ptr->pval3) return (0); + + /* Beware artifatcs should not combibne with "lesser" thing */ + if (o_ptr->name1 != j_ptr->name1) return (0); + + /* Do not combine different ego or normal ones */ + if (o_ptr->name2 != j_ptr->name2) return (0); + + /* Do not combine different ego or normal ones */ + if (o_ptr->name2b != j_ptr->name2b) return (0); + + /* Assume okay */ + break; + } + + /* Wands */ + case TV_WAND: + { + + /* Require either knowledge or known empty for both wands. */ + if ((!(o_ptr->ident & (IDENT_EMPTY)) && + !object_known_p(o_ptr)) || + (!(j_ptr->ident & (IDENT_EMPTY)) && + !object_known_p(j_ptr))) return (0); + + /* Beware artifatcs should not combibne with "lesser" thing */ + if (o_ptr->name1 != j_ptr->name1) return (0); + + /* Do not combine recharged ones with non recharged ones. */ + if ((f4 & TR4_RECHARGED) != (f14 & TR4_RECHARGED)) return (0); + + /* Do not combine different spells */ + if (o_ptr->pval2 != j_ptr->pval2) return (0); + + /* Do not combine different base levels */ + if (o_ptr->pval3 != j_ptr->pval3) return (0); + + /* Do not combine different ego or normal ones */ + if (o_ptr->name2 != j_ptr->name2) return (0); + + /* Do not combine different ego or normal ones */ + if (o_ptr->name2b != j_ptr->name2b) return (0); + + /* Assume okay */ + break; + } + + /* Rod Tips */ + case TV_ROD: + { + /* Probably okay */ + break; + } + + /* Rods */ + case TV_ROD_MAIN: + { + return FALSE; + break; + } + + /* Weapons and Armor */ + case TV_BOW: + case TV_BOOMERANG: + case TV_DIGGING: + case TV_HAFTED: + case TV_POLEARM: + case TV_MSTAFF: + case TV_SWORD: + case TV_AXE: + case TV_BOOTS: + case TV_GLOVES: + case TV_HELM: + case TV_CROWN: + case TV_SHIELD: + case TV_CLOAK: + case TV_SOFT_ARMOR: + case TV_HARD_ARMOR: + case TV_DRAG_ARMOR: + case TV_TRAPKIT: + case TV_DAEMON_BOOK: + { + /* Require permission */ + if (!stack_allow_items) return (0); + + /* Fall through */ + } + + /* Rings, Amulets, Lites */ + case TV_RING: + case TV_AMULET: + case TV_LITE: + { + /* Require full knowledge of both items */ + if (!object_known_p(o_ptr) || !object_known_p(j_ptr)) return (0); + + /* Require identical "turns of light" */ + if (o_ptr->timeout != j_ptr->timeout) return (FALSE); + + /* Fall through */ + } + + /* Missiles */ + case TV_BOLT: + case TV_ARROW: + case TV_SHOT: + { + /* Require identical knowledge of both items */ + if (object_known_p(o_ptr) != object_known_p(j_ptr)) return (0); + + /* Require identical "bonuses" */ + if (o_ptr->to_h != j_ptr->to_h) return (FALSE); + if (o_ptr->to_d != j_ptr->to_d) return (FALSE); + if (o_ptr->to_a != j_ptr->to_a) return (FALSE); + + /* Require identical "pval" code */ + if (o_ptr->pval != j_ptr->pval) return (FALSE); + + /* Require identical exploding status code */ + if (o_ptr->pval2 != j_ptr->pval2) return (FALSE); + + /* Require identical "artifact" names */ + if (o_ptr->name1 != j_ptr->name1) return (FALSE); + + /* Require identical "ego-item" names */ + if (o_ptr->name2 != j_ptr->name2) return (FALSE); + + /* Do not combine different ego or normal ones */ + if (o_ptr->name2b != j_ptr->name2b) return (FALSE); + + /* Hack -- Never stack "powerful" items */ + /* + Why?! + -- wilh + */ + /* #if 0 */ + if (o_ptr->xtra1 || j_ptr->xtra1) return (FALSE); + /* #endif */ + + /* Hack -- Never stack recharging items */ + if ((o_ptr->timeout || j_ptr->timeout) && + (o_ptr->tval != TV_LITE)) return (FALSE); + + /* Require identical "values" */ + if (o_ptr->ac != j_ptr->ac) return (FALSE); + if (o_ptr->dd != j_ptr->dd) return (FALSE); + if (o_ptr->ds != j_ptr->ds) return (FALSE); + + /* Probably okay */ + break; + } + + /* UHH ugly hack for the mushroom quest, sorry */ + case TV_FOOD: + { + if (o_ptr->pval2 != j_ptr->pval2) return (FALSE); + break; + } + + /* UHH ugly hack for the fireproof quest, sorry */ + case TV_BATERIE: + { + if (o_ptr->pval2 != j_ptr->pval2) return (FALSE); + break; + } + + /* Various */ + default: + { + /* Require knowledge */ + if (!object_known_p(o_ptr) || !object_known_p(j_ptr)) return (0); + + /* Probably okay */ + break; + } + } + + + /* Hack -- Identical art_flags! */ + if ((o_ptr->art_flags1 != j_ptr->art_flags1) || + (o_ptr->art_flags2 != j_ptr->art_flags2) || + (o_ptr->art_flags3 != j_ptr->art_flags3)) + return (0); + + /* Hack -- Require identical "cursed" status */ + if ((o_ptr->ident & (IDENT_CURSED)) != (j_ptr->ident & (IDENT_CURSED))) return (0); + + /* Hack -- require semi-matching "inscriptions" */ + if (o_ptr->note && j_ptr->note && (o_ptr->note != j_ptr->note)) return (0); + + /* Hack -- normally require matching "inscriptions" */ + if (!stack_force_notes && (o_ptr->note != j_ptr->note)) return (0); + + /* Hack -- normally require matching "discounts" */ + if (!stack_force_costs && (o_ptr->discount != j_ptr->discount)) return (0); + + + /* Maximal "stacking" limit */ + if (total >= MAX_STACK_SIZE) return (0); + + + /* They match, so they must be similar */ + return (TRUE); +} + + +/* + * Allow one item to "absorb" another, assuming they are similar + */ +void object_absorb(object_type *o_ptr, object_type *j_ptr) +{ + int total = o_ptr->number + j_ptr->number; + + /* Add together the item counts */ + o_ptr->number = ((total < MAX_STACK_SIZE) ? total : (MAX_STACK_SIZE - 1)); + + /* Hack -- blend "known" status */ + if (object_known_p(j_ptr)) object_known(o_ptr); + + /* Hack -- clear "storebought" if only one has it */ + if (((o_ptr->ident & IDENT_STOREB) || (j_ptr->ident & IDENT_STOREB)) && + (!((o_ptr->ident & IDENT_STOREB) && (j_ptr->ident & IDENT_STOREB)))) + { + if (j_ptr->ident & IDENT_STOREB) j_ptr->ident &= 0xEF; + if (o_ptr->ident & IDENT_STOREB) o_ptr->ident &= 0xEF; + } + + /* Hack -- blend "mental" status */ + if (j_ptr->ident & (IDENT_MENTAL)) o_ptr->ident |= (IDENT_MENTAL); + + /* Hack -- blend "inscriptions" */ + if (j_ptr->note) o_ptr->note = j_ptr->note; + + /* Hack -- could average discounts XXX XXX XXX */ + /* Hack -- save largest discount XXX XXX XXX */ + if (o_ptr->discount < j_ptr->discount) o_ptr->discount = j_ptr->discount; + + /* Hack -- if wands are stacking, combine the charges. -LM- */ + if (o_ptr->tval == TV_WAND) + { + o_ptr->pval += j_ptr->pval; + } +} + + + +/* + * Find the index of the object_kind with the given tval and sval + */ +s16b lookup_kind(int tval, int sval) +{ + int k; + + /* Look for it */ + for (k = 1; k < max_k_idx; k++) + { + object_kind *k_ptr = &k_info[k]; + + /* Found a match */ + if ((k_ptr->tval == tval) && (k_ptr->sval == sval)) return (k); + } + + /* Oops */ + if (wizard) msg_format("No object (%d,%d)", tval, sval); + + /* Oops */ + return (0); +} + + +/* + * Wipe an object clean. + */ +void object_wipe(object_type *o_ptr) +{ + /* Wipe the structure */ + WIPE(o_ptr, object_type); +} + + +/* + * Prepare an object based on an existing object + */ +void object_copy(object_type *o_ptr, object_type *j_ptr) +{ + /* Copy the structure */ + COPY(o_ptr, j_ptr, object_type); +} + + +/* + * Prepare an object based on an object kind. + */ +void object_prep(object_type *o_ptr, int k_idx) +{ + object_kind *k_ptr = &k_info[k_idx]; + + /* Clear the record */ + WIPE(o_ptr, object_type); + + /* Save the kind index */ + o_ptr->k_idx = k_idx; + + /* Efficiency -- tval/sval */ + o_ptr->tval = k_ptr->tval; + o_ptr->sval = k_ptr->sval; + + /* Default "pval" */ + o_ptr->pval = k_ptr->pval; + o_ptr->pval2 = k_ptr->pval2; + + /* Default number */ + o_ptr->number = 1; + + /* Default weight */ + o_ptr->weight = k_ptr->weight; + + /* Default magic */ + o_ptr->to_h = k_ptr->to_h; + o_ptr->to_d = k_ptr->to_d; + o_ptr->to_a = k_ptr->to_a; + + /* Default power */ + o_ptr->ac = k_ptr->ac; + o_ptr->dd = k_ptr->dd; + o_ptr->ds = k_ptr->ds; + + /* Hack -- cursed items are always "cursed" */ + if (k_ptr->flags3 & (TR3_CURSED)) o_ptr->ident |= (IDENT_CURSED); + + /* Hack give a basic exp/exp level to an object that needs it */ + if (k_ptr->flags4 & TR4_LEVELS) + { + o_ptr->elevel = (k_ptr->level / 10) + 1; + o_ptr->exp = player_exp[o_ptr->elevel - 1]; + o_ptr->pval2 = 1; /* Start with one point */ + o_ptr->pval3 = 0; /* No flags groups */ + } +} + + +/* + * Help determine an "enchantment bonus" for an object. + * + * To avoid floating point but still provide a smooth distribution of bonuses, + * we simply round the results of division in such a way as to "average" the + * correct floating point value. + * + * This function has been changed. It uses "randnor()" to choose values from + * a normal distribution, whose mean moves from zero towards the max as the + * level increases, and whose standard deviation is equal to 1/4 of the max, + * and whose values are forced to lie between zero and the max, inclusive. + * + * Since the "level" rarely passes 100 before Morgoth is dead, it is very + * rare to get the "full" enchantment on an object, even a deep levels. + * + * It is always possible (albeit unlikely) to get the "full" enchantment. + * + * A sample distribution of values from "m_bonus(10, N)" is shown below: + * + * N 0 1 2 3 4 5 6 7 8 9 10 + * --- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- + * 0 66.37 13.01 9.73 5.47 2.89 1.31 0.72 0.26 0.12 0.09 0.03 + * 8 46.85 24.66 12.13 8.13 4.20 2.30 1.05 0.36 0.19 0.08 0.05 + * 16 30.12 27.62 18.52 10.52 6.34 3.52 1.95 0.90 0.31 0.15 0.05 + * 24 22.44 15.62 30.14 12.92 8.55 5.30 2.39 1.63 0.62 0.28 0.11 + * 32 16.23 11.43 23.01 22.31 11.19 7.18 4.46 2.13 1.20 0.45 0.41 + * 40 10.76 8.91 12.80 29.51 16.00 9.69 5.90 3.43 1.47 0.88 0.65 + * 48 7.28 6.81 10.51 18.27 27.57 11.76 7.85 4.99 2.80 1.22 0.94 + * 56 4.41 4.73 8.52 11.96 24.94 19.78 11.06 7.18 3.68 1.96 1.78 + * 64 2.81 3.07 5.65 9.17 13.01 31.57 13.70 9.30 6.04 3.04 2.64 + * 72 1.87 1.99 3.68 7.15 10.56 20.24 25.78 12.17 7.52 4.42 4.62 + * 80 1.02 1.23 2.78 4.75 8.37 12.04 27.61 18.07 10.28 6.52 7.33 + * 88 0.70 0.57 1.56 3.12 6.34 10.06 15.76 30.46 12.58 8.47 10.38 + * 96 0.27 0.60 1.25 2.28 4.30 7.60 10.77 22.52 22.51 11.37 16.53 + * 104 0.22 0.42 0.77 1.36 2.62 5.33 8.93 13.05 29.54 15.23 22.53 + * 112 0.15 0.20 0.56 0.87 2.00 3.83 6.86 10.06 17.89 27.31 30.27 + * 120 0.03 0.11 0.31 0.46 1.31 2.48 4.60 7.78 11.67 25.53 45.72 + * 128 0.02 0.01 0.13 0.33 0.83 1.41 3.24 6.17 9.57 14.22 64.07 + */ +s16b m_bonus(int max, int level) +{ + int bonus, stand, extra, value; + + + /* Paranoia -- enforce maximal "level" */ + if (level > MAX_DEPTH - 1) level = MAX_DEPTH - 1; + + + /* The "bonus" moves towards the max */ + bonus = ((max * level) / MAX_DEPTH); + + /* Hack -- determine fraction of error */ + extra = ((max * level) % MAX_DEPTH); + + /* Hack -- simulate floating point computations */ + if (rand_int(MAX_DEPTH) < extra) bonus++; + + + /* The "stand" is equal to one quarter of the max */ + stand = (max / 4); + + /* Hack -- determine fraction of error */ + extra = (max % 4); + + /* Hack -- simulate floating point computations */ + if (rand_int(4) < extra) stand++; + + + /* Choose an "interesting" value */ + value = randnor(bonus, stand); + + /* Enforce the minimum value */ + if (value < 0) return (0); + + /* Enforce the maximum value */ + if (value > max) return (max); + + /* Result */ + return (value); +} + + +/* + * Tinker with the random artifact to make it acceptable + * for a certain depth; also connect a random artifact to an + * object. + */ +static void finalize_randart(object_type* o_ptr, int lev) +{ + int r; + int i = 0; + int foo = lev + randnor(0, 5); + bool_ flag = TRUE; + + /* Paranoia */ + if (o_ptr->tval != TV_RANDART) return; + + if (foo < 1) foo = 1; + if (foo > 100) foo = 100; + + while (flag) + { + r = rand_int(MAX_RANDARTS); + + if (!(random_artifacts[r].generated) || i > 2000) + { + random_artifact* ra_ptr = &random_artifacts[r]; + + o_ptr->sval = r; + o_ptr->pval2 = ra_ptr->activation; + o_ptr->xtra2 = activation_info[ra_ptr->activation].spell; + + ra_ptr->level = lev; + ra_ptr->generated = TRUE; + flag = FALSE; + } + + i++; + } +} + + + +/* + * Cheat -- describe a created object for the user + */ +static void object_mention(object_type *o_ptr) +{ + char o_name[80]; + + /* Describe */ + object_desc_store(o_name, o_ptr, FALSE, 0); + + /* Artifact */ + if (artifact_p(o_ptr)) + { + /* Silly message */ + msg_format("Artifact (%s)", o_name); + } + + /* Random Artifact */ + else if (o_ptr->art_name) + { + msg_print("Random artifact"); + } + + /* Ego-item */ + else if (ego_item_p(o_ptr)) + { + /* Silly message */ + msg_format("Ego-item (%s)", o_name); + } + + /* Normal item */ + else + { + /* Silly message */ + msg_format("Object (%s)", o_name); + } +} + + +void random_artifact_resistance(object_type * o_ptr) +{ + bool_ give_resistance = FALSE, give_power = FALSE; + + switch (o_ptr->name1) + { + case ART_CELEBORN: + case ART_ARVEDUI: + case ART_CASPANION: + case ART_TRON: + case ART_ROHIRRIM: + case ART_CELEGORM: + case ART_ANARION: + case ART_THRANDUIL: + case ART_LUTHIEN: + case ART_THROR: + case ART_THORIN: + case ART_NIMTHANC: + case ART_DETHANC: + case ART_NARTHANC: + case ART_STING: + case ART_TURMIL: + case ART_THALKETTOTH: + { + /* Give a resistance */ + give_resistance = TRUE; + } + break; + case ART_MAEDHROS: + case ART_GLAMDRING: + case ART_ORCRIST: + case ART_ANDURIL: + case ART_ZARCUTHRA: + case ART_GURTHANG: + case ART_HARADEKKET: + case ART_CUBRAGOL: + case ART_DAWN: + { + /* Give a resistance OR a power */ + if (randint(2) == 1) give_resistance = TRUE; + else give_power = TRUE; + } + break; + case ART_NENYA: + case ART_VILYA: + case ART_BERUTHIEL: + case ART_FINGOLFIN: + case ART_THINGOL: + case ART_ULMO: + case ART_OLORIN: + { + /* Give a power */ + give_power = TRUE; + } + break; + case ART_POWER: + case ART_GONDOR: + case ART_AULE: + { + /* Give both */ + give_power = TRUE; + give_resistance = TRUE; + } + break; + } + + if (give_power) + { + o_ptr->xtra1 = EGO_XTRA_ABILITY; + + /* Randomize the "xtra" power */ + if (o_ptr->xtra1) o_ptr->xtra2 = randint(256); + } + + artifact_bias = 0; + + if (give_resistance) + { + random_resistance(o_ptr, FALSE, ((randint(22)) + 16)); + } +} + + +/* + * Mega-Hack -- Attempt to create one of the "Special Objects" + * + * We are only called from "make_object()", and we assume that + * "apply_magic()" is called immediately after we return. + * + * Note -- see "make_artifact()" and "apply_magic()" + */ +static bool_ make_artifact_special(object_type *o_ptr) +{ + int i; + int k_idx = 0; + u32b f1, f2, f3, f4, f5, esp; + + /* No artifacts in the town */ + if (!dun_level) return (FALSE); + + /* Check the artifact list (just the "specials") */ + for (i = 0; i < max_a_idx; i++) + { + artifact_type *a_ptr = &a_info[i]; + + /* Skip "empty" artifacts */ + if (!a_ptr->name) continue; + + /* Cannot make an artifact twice */ + if (a_ptr->cur_num) continue; + + /* Cannot generate non special ones */ + if (!(a_ptr->flags3 & TR3_INSTA_ART)) continue; + + /* Cannot generate some artifacts because they can only exists in special dungeons/quests/... */ + if ((a_ptr->flags4 & TR4_SPECIAL_GENE) && (!a_allow_special[i])) continue; + + /* XXX XXX Enforce minimum "depth" (loosely) */ + if (a_ptr->level > dun_level) + { + /* Acquire the "out-of-depth factor" */ + int d = (a_ptr->level - dun_level) * 2; + + /* Roll for out-of-depth creation */ + if (rand_int(d) != 0) continue; + } + + /* Artifact "rarity roll" */ + if (rand_int(a_ptr->rarity - luck( -(a_ptr->rarity / 2), a_ptr->rarity / 2)) != 0) continue; + + /* Find the base object */ + k_idx = lookup_kind(a_ptr->tval, a_ptr->sval); + + /* XXX XXX Enforce minimum "object" level (loosely) */ + if (k_info[k_idx].level > object_level) + { + /* Acquire the "out-of-depth factor" */ + int d = (k_info[k_idx].level - object_level) * 5; + + /* Roll for out-of-depth creation */ + if (rand_int(d) != 0) continue; + } + + /* Assign the template */ + object_prep(o_ptr, k_idx); + + /* Mega-Hack -- mark the item as an artifact */ + o_ptr->name1 = i; + + /* Extract some flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Hack give a basic exp/exp level to an object that needs it */ + if (f4 & TR4_LEVELS) + { + o_ptr->elevel = (k_info[k_idx].level / 10) + 1; + o_ptr->exp = player_exp[o_ptr->elevel - 1]; + } + + /* Success */ + return (TRUE); + } + + /* Failure */ + return (FALSE); +} + + +/* + * Attempt to change an object into an artifact + * + * This routine should only be called by "apply_magic()" + * + * Note -- see "make_artifact_special()" and "apply_magic()" + */ +static bool_ make_artifact(object_type *o_ptr) +{ + int i; + u32b f1, f2, f3, f4, f5, esp; + object_kind *k_ptr = &k_info[o_ptr->k_idx]; + + /* No artifacts in the town */ + if (!dun_level) return (FALSE); + + /* Paranoia -- no "plural" artifacts */ + if (o_ptr->number != 1) return (FALSE); + + /* Check the artifact list (skip the "specials") */ + for (i = 0; i < max_a_idx; i++) + { + artifact_type *a_ptr = &a_info[i]; + + /* Skip "empty" items */ + if (!a_ptr->name) continue; + + /* Cannot make an artifact twice */ + if (a_ptr->cur_num) continue; + + /* Cannot generate special ones */ + if (a_ptr->flags3 & TR3_INSTA_ART) continue; + + /* Cannot generate some artifacts because they can only exists in special dungeons/quests/... */ + if ((a_ptr->flags4 & TR4_SPECIAL_GENE) && (!a_allow_special[i])) continue; + + /* Must have the correct fields */ + if (a_ptr->tval != o_ptr->tval) continue; + if (a_ptr->sval != o_ptr->sval) continue; + + /* XXX XXX Enforce minimum "depth" (loosely) */ + if (a_ptr->level > dun_level) + { + /* Acquire the "out-of-depth factor" */ + int d = (a_ptr->level - dun_level) * 2; + + /* Roll for out-of-depth creation */ + if (rand_int(d) != 0) continue; + } + + /* We must make the "rarity roll" */ + if (rand_int(a_ptr->rarity - luck( -(a_ptr->rarity / 2), a_ptr->rarity / 2)) != 0) continue; + + /* Hack -- mark the item as an artifact */ + o_ptr->name1 = i; + + /* Hack: Some artifacts get random extra powers */ + random_artifact_resistance(o_ptr); + + /* Extract some flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Hack give a basic exp/exp level to an object that needs it */ + if (f4 & TR4_LEVELS) + { + o_ptr->elevel = (k_ptr->level / 10) + 1; + o_ptr->exp = player_exp[o_ptr->elevel - 1]; + } + + /* Success */ + return (TRUE); + } + + /* Failure */ + return (FALSE); +} + +/* + * Attempt to change an object into an ego + * + * This routine should only be called by "apply_magic()" + */ +static bool_ make_ego_item(object_type *o_ptr, bool_ good) +{ + int i = 0, j; + bool_ ret = FALSE; + object_kind *k_ptr = &k_info[o_ptr->k_idx]; + + if (artifact_p(o_ptr) || o_ptr->name2) return (FALSE); + + std::vector ok_ego; + + /* Grab the ok ego */ + for (i = 0; i < max_e_idx; i++) + { + ego_item_type *e_ptr = &e_info[i]; + bool_ ok = FALSE; + + /* Skip "empty" items */ + if (!e_ptr->name) continue; + + /* Must have the correct fields */ + for (j = 0; j < 6; j++) + { + if (e_ptr->tval[j] == o_ptr->tval) + { + if ((e_ptr->min_sval[j] <= o_ptr->sval) && (e_ptr->max_sval[j] >= o_ptr->sval)) ok = TRUE; + } + + if (ok) break; + } + if (!ok) + { + /* Doesnt count as a try*/ + continue; + } + + /* Good should be good, bad should be bad */ + if (good && (!e_ptr->cost)) continue; + if ((!good) && e_ptr->cost) continue; + + /* Must posses the good flags */ + if (((k_ptr->flags1 & e_ptr->need_flags1) != e_ptr->need_flags1) || + ((k_ptr->flags2 & e_ptr->need_flags2) != e_ptr->need_flags2) || + ((k_ptr->flags3 & e_ptr->need_flags3) != e_ptr->need_flags3) || + ((k_ptr->flags4 & e_ptr->need_flags4) != e_ptr->need_flags4) || + ((k_ptr->flags5 & e_ptr->need_flags5) != e_ptr->need_flags5) || + ((k_ptr->esp & e_ptr->need_esp) != e_ptr->need_esp)) + continue; + if ((k_ptr->flags1 & e_ptr->forbid_flags1) || + (k_ptr->flags2 & e_ptr->forbid_flags2) || + (k_ptr->flags3 & e_ptr->forbid_flags3) || + (k_ptr->flags4 & e_ptr->forbid_flags4) || + (k_ptr->flags5 & e_ptr->forbid_flags5) || + (k_ptr->esp & e_ptr->forbid_esp)) + continue; + + /* ok */ + ok_ego.push_back(i); + } + + /* Now test them a few times */ + for (i = 0; i < ok_ego.size() * 10; i++) + { + ego_item_type *e_ptr; + + int j = ok_ego[rand_int(ok_ego.size())]; + e_ptr = &e_info[j]; + + /* XXX XXX Enforce minimum "depth" (loosely) */ + if (e_ptr->level > dun_level) + { + /* Acquire the "out-of-depth factor" */ + int d = (e_ptr->level - dun_level); + + /* Roll for out-of-depth creation */ + if (rand_int(d) != 0) + { + continue; + } + } + + /* We must make the "rarity roll" */ + if (rand_int(e_ptr->mrarity - luck( -(e_ptr->mrarity / 2), e_ptr->mrarity / 2)) > e_ptr->rarity) + { + continue; + } + + /* Hack -- mark the item as an ego */ + o_ptr->name2 = j; + + /* Success */ + ret = TRUE; + break; + } + + /* + * Sometimes(rarely) tries for a double ego + * Also make sure we dont already have a name2b, wchih would mean a special ego item + */ + if (magik(7 + luck( -7, 7)) && (!o_ptr->name2b)) + { + /* Now test them a few times */ + for (i = 0; i < ok_ego.size() * 10; i++) + { + ego_item_type *e_ptr; + + int j = ok_ego[rand_int(ok_ego.size())]; + e_ptr = &e_info[j]; + + /* Cannot be a double ego of the same ego type */ + if (j == o_ptr->name2) continue; + + /* Cannot have 2 suffixes or 2 prefixes */ + if (e_info[o_ptr->name2].before && e_ptr->before) continue; + if ((!e_info[o_ptr->name2].before) && (!e_ptr->before)) continue; + + /* XXX XXX Enforce minimum "depth" (loosely) */ + if (e_ptr->level > dun_level) + { + /* Acquire the "out-of-depth factor" */ + int d = (e_ptr->level - dun_level); + + /* Roll for out-of-depth creation */ + if (rand_int(d) != 0) + { + continue; + } + } + + /* We must make the "rarity roll" */ + if (rand_int(e_ptr->mrarity - luck( -(e_ptr->mrarity / 2), e_ptr->mrarity / 2)) > e_ptr->rarity) + { + continue; + } + + /* Hack -- mark the item as an ego */ + o_ptr->name2b = j; + + /* Success */ + ret = TRUE; + break; + } + } + + /* Return */ + return (ret); +} + + +/* + * Charge a new stick. + */ +void charge_stick(object_type *o_ptr) +{ + spell_type *spell = spell_at(o_ptr->pval2); + o_ptr->pval = spell_type_roll_charges(spell); +} + +/* + * Apply magic to an item known to be a "weapon" + * + * Hack -- note special base damage dice boosting + * Hack -- note special processing for weapon/digger + * Hack -- note special rating boost for dragon scale mail + */ +static void a_m_aux_1(object_type *o_ptr, int level, int power) +{ + int tohit1 = randint(5) + m_bonus(5, level); + int todam1 = randint(5) + m_bonus(5, level); + + int tohit2 = m_bonus(10, level); + int todam2 = m_bonus(10, level); + + artifact_bias = 0; + + /* Very good */ + if (power > 1) + { + /* Make ego item */ + if ((rand_int(RANDART_WEAPON) == 1) && (o_ptr->tval != TV_TRAPKIT)) create_artifact(o_ptr, FALSE, TRUE); + else make_ego_item(o_ptr, TRUE); + } + else if (power < -1) + { + /* Make ego item */ + make_ego_item(o_ptr, FALSE); + } + + /* Good */ + if (power > 0) + { + /* Enchant */ + o_ptr->to_h += tohit1; + o_ptr->to_d += todam1; + + /* Very good */ + if (power > 1) + { + /* Enchant again */ + o_ptr->to_h += tohit2; + o_ptr->to_d += todam2; + } + } + + /* Cursed */ + else if (power < 0) + { + /* Penalize */ + o_ptr->to_h -= tohit1; + o_ptr->to_d -= todam1; + + /* Very cursed */ + if (power < -1) + { + /* Penalize again */ + o_ptr->to_h -= tohit2; + o_ptr->to_d -= todam2; + } + + /* Cursed (if "bad") */ + if (o_ptr->to_h + o_ptr->to_d < 0) o_ptr->ident |= (IDENT_CURSED); + } + + /* Some special cases */ + if (process_hooks(HOOK_APPLY_MAGIC, "(O,d,d)", o_ptr, level, power)) + return; + switch (o_ptr->tval) + { + case TV_TRAPKIT: + { + /* Good */ + if (power > 0) o_ptr->to_a += randint(5); + + /* Very good */ + if (power > 1) o_ptr->to_a += randint(5); + + /* Bad */ + if (power < 0) o_ptr->to_a -= randint(5); + + /* Very bad */ + if (power < -1) o_ptr->to_a -= randint(5); + + break; + } + case TV_MSTAFF: + { + if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL)) + { + int gf[2], i; + + for (i = 0; i < 2; i++) + { + int k = 0; + + gf[i] = 0; + while (!k) + { + k = lookup_kind(TV_RUNE1, (gf[i] = rand_int(MAX_GF))); + } + } + + o_ptr->pval = gf[0] + (gf[1] << 16); + o_ptr->pval3 = rand_int(RUNE_MOD_MAX) + (rand_int(RUNE_MOD_MAX) << 16); + o_ptr->pval2 = randint(70) + (randint(70) << 8); + } + else + o_ptr->art_flags5 |= (TR5_SPELL_CONTAIN | TR5_WIELD_CAST); + break; + } + case TV_BOLT: + case TV_ARROW: + case TV_SHOT: + { + if ((power == 1) && !o_ptr->name2) + { + if (randint(100) < 30) + { + /* Exploding missile */ + int power[27] = {GF_ELEC, GF_POIS, GF_ACID, + GF_COLD, GF_FIRE, GF_PLASMA, GF_LITE, + GF_DARK, GF_SHARDS, GF_SOUND, + GF_CONFUSION, GF_FORCE, GF_INERTIA, + GF_MANA, GF_METEOR, GF_ICE, GF_CHAOS, + GF_NETHER, GF_NEXUS, GF_TIME, + GF_GRAVITY, GF_KILL_WALL, GF_AWAY_ALL, + GF_TURN_ALL, GF_NUKE, GF_STUN, + GF_DISINTEGRATE}; + + o_ptr->pval2 = power[rand_int(27)]; + } + } + break; + } + } +} + + +static void dragon_resist(object_type * o_ptr) +{ + do + { + artifact_bias = 0; + + if (randint(4) == 1) + random_resistance(o_ptr, FALSE, ((randint(14)) + 4)); + else + random_resistance(o_ptr, FALSE, ((randint(22)) + 16)); + } + while (randint(2) == 1); +} + + +/* + * Apply magic to an item known to be "armor" + * + * Hack -- note special processing for crown/helm + * Hack -- note special processing for robe of permanence + */ +static void a_m_aux_2(object_type *o_ptr, int level, int power) +{ + int toac1 = randint(5) + m_bonus(5, level); + + int toac2 = m_bonus(10, level); + + artifact_bias = 0; + + /* Very good */ + if (power > 1) + { + /* Make ego item */ + if (rand_int(RANDART_ARMOR) == 1) create_artifact(o_ptr, FALSE, TRUE); + else make_ego_item(o_ptr, TRUE); + } + else if (power < -1) + { + /* Make ego item */ + make_ego_item(o_ptr, FALSE); + } + + /* Good */ + if (power > 0) + { + /* Enchant */ + o_ptr->to_a += toac1; + + /* Very good */ + if (power > 1) + { + /* Enchant again */ + o_ptr->to_a += toac2; + } + } + + /* Cursed */ + else if (power < 0) + { + /* Penalize */ + o_ptr->to_a -= toac1; + + /* Very cursed */ + if (power < -1) + { + /* Penalize again */ + o_ptr->to_a -= toac2; + } + + /* Cursed (if "bad") */ + if (o_ptr->to_a < 0) o_ptr->ident |= (IDENT_CURSED); + } + + /* Analyze type */ + if (process_hooks(HOOK_APPLY_MAGIC, "(O,d,d)", o_ptr, level, power)) + return; + switch (o_ptr->tval) + { + case TV_CLOAK: + { + if (o_ptr->sval == SV_ELVEN_CLOAK) + o_ptr->pval = randint(4); /* No cursed elven cloaks...? */ + else if (o_ptr->sval == SV_MIMIC_CLOAK) + { + s32b mimic = find_random_mimic_shape(level, TRUE); + o_ptr->pval2 = mimic; + } + break; + } + case TV_DRAG_ARMOR: + { + /* Rating boost */ + rating += 30; + + /* Mention the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + + break; + } + case TV_SHIELD: + { + if (o_ptr->sval == SV_DRAGON_SHIELD) + { + /* Rating boost */ + rating += 5; + + /* Mention the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + dragon_resist(o_ptr); + } + break; + } + case TV_HELM: + { + if (o_ptr->sval == SV_DRAGON_HELM) + { + /* Rating boost */ + rating += 5; + + /* Mention the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + dragon_resist(o_ptr); + } + break; + } + } +} + + + +/* + * Apply magic to an item known to be a "ring" or "amulet" + * + * Hack -- note special rating boost for ring of speed + * Hack -- note special rating boost for amulet of the magi + * Hack -- note special "pval boost" code for ring of speed + * Hack -- note that some items must be cursed (or blessed) + */ +static void a_m_aux_3(object_type *o_ptr, int level, int power) +{ + + artifact_bias = 0; + + /* Very good */ + if (power > 1) + { + /* Make ego item */ + if (rand_int(RANDART_JEWEL) == 1) create_artifact(o_ptr, FALSE, TRUE); + else make_ego_item(o_ptr, TRUE); + } + else if (power < -1) + { + /* Make ego item */ + make_ego_item(o_ptr, FALSE); + } + + /* Apply magic (good or bad) according to type */ + if (process_hooks(HOOK_APPLY_MAGIC, "(O,d,d)", o_ptr, level, power)) + return; + switch (o_ptr->tval) + { + case TV_RING: + { + /* Analyze */ + switch (o_ptr->sval) + { + /* Strength, Constitution, Dexterity, Intelligence */ + case SV_RING_ATTACKS: + { + /* Stat bonus */ + o_ptr->pval = m_bonus(3, level); + if (o_ptr->pval < 1) o_ptr->pval = 1; + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse pval */ + o_ptr->pval = 0 - (o_ptr->pval); + } + + break; + } + + /* Critical hits */ + case SV_RING_CRIT: + { + /* Stat bonus */ + o_ptr->pval = m_bonus(10, level); + if (o_ptr->pval < 1) o_ptr->pval = 1; + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse pval */ + o_ptr->pval = 0 - (o_ptr->pval); + } + + break; + } + + + case SV_RING_STR: + case SV_RING_CON: + case SV_RING_DEX: + case SV_RING_INT: + { + /* Stat bonus */ + o_ptr->pval = 1 + m_bonus(5, level); + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse pval */ + o_ptr->pval = 0 - (o_ptr->pval); + } + + break; + } + + /* Ring of Speed! */ + case SV_RING_SPEED: + { + /* Base speed (1 to 10) */ + o_ptr->pval = randint(5) + m_bonus(5, level); + + /* Super-charge the ring */ + while (rand_int(100) < 50) o_ptr->pval++; + + /* Cursed Ring */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse pval */ + o_ptr->pval = 0 - (o_ptr->pval); + + break; + } + + /* Rating boost */ + rating += 25; + + /* Mention the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + + break; + } + + case SV_RING_LORDLY: + { + do + { + random_resistance(o_ptr, FALSE, ((randint(20)) + 18)); + } + while (randint(4) == 1); + + /* Bonus to armor class */ + o_ptr->to_a = 10 + randint(5) + m_bonus(10, level); + rating += 5; + } + break; + + /* Searching */ + case SV_RING_SEARCHING: + { + /* Bonus to searching */ + o_ptr->pval = 1 + m_bonus(5, level); + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse pval */ + o_ptr->pval = 0 - (o_ptr->pval); + } + + break; + } + + /* Flames, Acid, Ice */ + case SV_RING_FLAMES: + case SV_RING_ACID: + case SV_RING_ICE: + { + /* Bonus to armor class */ + o_ptr->to_a = 5 + randint(5) + m_bonus(10, level); + break; + } + + /* Weakness, Stupidity */ + case SV_RING_WEAKNESS: + case SV_RING_STUPIDITY: + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Penalize */ + o_ptr->pval = 0 - (1 + m_bonus(5, level)); + + break; + } + + /* WOE, Stupidity */ + case SV_RING_WOE: + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Penalize */ + o_ptr->to_a = 0 - (5 + m_bonus(10, level)); + o_ptr->pval = 0 - (1 + m_bonus(5, level)); + + break; + } + + /* Ring of damage */ + case SV_RING_DAMAGE: + { + /* Bonus to damage */ + o_ptr->to_d = 5 + randint(8) + m_bonus(10, level); + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse bonus */ + o_ptr->to_d = 0 - (o_ptr->to_d); + } + + break; + } + + /* Ring of Accuracy */ + case SV_RING_ACCURACY: + { + /* Bonus to hit */ + o_ptr->to_h = 5 + randint(8) + m_bonus(10, level); + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse tohit */ + o_ptr->to_h = 0 - (o_ptr->to_h); + } + + break; + } + + /* Ring of Protection */ + case SV_RING_PROTECTION: + { + /* Bonus to armor class */ + o_ptr->to_a = 5 + randint(8) + m_bonus(10, level); + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse toac */ + o_ptr->to_a = 0 - (o_ptr->to_a); + } + + break; + } + + /* Ring of Slaying */ + case SV_RING_SLAYING: + { + /* Bonus to damage and to hit */ + o_ptr->to_d = randint(7) + m_bonus(10, level); + o_ptr->to_h = randint(7) + m_bonus(10, level); + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse bonuses */ + o_ptr->to_h = 0 - (o_ptr->to_h); + o_ptr->to_d = 0 - (o_ptr->to_d); + } + + break; + } + } + + break; + } + + case TV_AMULET: + { + /* Analyze */ + switch (o_ptr->sval) + { + /* Amulet of Trickery */ + case SV_AMULET_TRICKERY: + case SV_AMULET_DEVOTION: + { + o_ptr->pval = 1 + m_bonus(3, level); + + /* Mention the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + break; + } + + case SV_AMULET_WEAPONMASTERY: + { + o_ptr->pval = 1 + m_bonus(2, level); + o_ptr->to_a = 1 + m_bonus(4, level); + o_ptr->to_h = 1 + m_bonus(5, level); + o_ptr->to_d = 1 + m_bonus(5, level); + + /* Mention the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + break; + } + + /* Amulet of wisdom/charisma */ + case SV_AMULET_BRILLANCE: + case SV_AMULET_CHARISMA: + case SV_AMULET_WISDOM: + case SV_AMULET_INFRA: + { + o_ptr->pval = 1 + m_bonus(5, level); + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse bonuses */ + o_ptr->pval = 0 - (o_ptr->pval); + } + + break; + } + + /* Amulet of the Serpents */ + case SV_AMULET_SERPENT: + { + o_ptr->pval = 1 + m_bonus(5, level); + o_ptr->to_a = 1 + m_bonus(6, level); + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse bonuses */ + o_ptr->pval = 0 - (o_ptr->pval); + } + + break; + } + + case SV_AMULET_NO_MAGIC: + case SV_AMULET_NO_TELE: + { + if (power < 0) + { + o_ptr->ident |= (IDENT_CURSED); + } + break; + } + + case SV_AMULET_RESISTANCE: + { + if (randint(3) == 1) random_resistance(o_ptr, FALSE, ((randint(34)) + 4)); + if (randint(5) == 1) o_ptr->art_flags2 |= TR2_RES_POIS; + } + break; + + /* Amulet of searching */ + case SV_AMULET_SEARCHING: + { + o_ptr->pval = randint(5) + m_bonus(5, level); + + /* Cursed */ + if (power < 0) + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Reverse bonuses */ + o_ptr->pval = 0 - (o_ptr->pval); + } + + break; + } + + /* Amulet of the Magi -- never cursed */ + case SV_AMULET_THE_MAGI: + { + o_ptr->pval = 1 + m_bonus(3, level); + + if (randint(3) == 1) o_ptr->art_flags3 |= TR3_SLOW_DIGEST; + + /* Boost the rating */ + rating += 25; + + /* Mention the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + + break; + } + + /* Amulet of Doom -- always cursed */ + case SV_AMULET_DOOM: + { + /* Cursed */ + o_ptr->ident |= (IDENT_CURSED); + + /* Penalize */ + o_ptr->pval = 0 - (randint(5) + m_bonus(5, level)); + o_ptr->to_a = 0 - (randint(5) + m_bonus(5, level)); + + break; + } + } + + break; + } + } +} + +/* + * Get a spell for a given stick(wand, staff, rod) + */ +long get_random_stick(byte tval, int level) +{ + int tries; + + for (tries = 0; tries < 1000; tries++) + { + long spell_idx = rand_int(school_spells_count); + spell_type *spell = spell_at(spell_idx); + device_allocation *device_allocation = spell_type_device_allocation(spell, tval); + + if ((device_allocation != NULL) && + (rand_int(spell_type_skill_level(spell) * 3) < level) && + (magik(100 - device_allocation->rarity))) + { + return spell_idx; + } + } + + return -1; +} + + +/* + * Randomized level + */ +static int randomized_level_in_range(range_type *range, int level) +{ + s32b r = range->max - range->min; + + /* The basic idea is to have a max possible level of half the dungeon level */ + if (r * 2 > level) + { + r = level / 2; + } + + /* Randomize a bit */ + r = m_bonus(r, dun_level); + + /* get the result */ + return range->min + r; +} + + +/* + * Get a random base level + */ +static int get_stick_base_level(byte tval, int level, int spl) +{ + spell_type *spell = spell_at(spl); + device_allocation *device_allocation = spell_type_device_allocation(spell, tval); + assert(device_allocation != NULL); + return randomized_level_in_range(&device_allocation->base_level, level); +} + +/* + * Get a random max level + */ +static int get_stick_max_level(byte tval, int level, int spl) +{ + spell_type *spell = spell_at(spl); + device_allocation *device_allocation = spell_type_device_allocation(spell, tval); + assert(device_allocation != NULL); + return randomized_level_in_range(&device_allocation->max_level, level); +} + + +/* + * Apply magic to an item known to be "boring" + * + * Hack -- note the special code for various items + */ +static void a_m_aux_4(object_type *o_ptr, int level, int power) +{ + u32b f1, f2, f3, f4, f5, esp; + s32b bonus_lvl, max_lvl; + object_kind *k_ptr = &k_info[o_ptr->k_idx]; + + /* Very good */ + if (power > 1) + { + /* Make ego item */ + if ((rand_int(RANDART_JEWEL) == 1) && (o_ptr->tval == TV_LITE)) create_artifact(o_ptr, FALSE, TRUE); + else make_ego_item(o_ptr, TRUE); + } + else if (power < -1) + { + /* Make ego item */ + make_ego_item(o_ptr, FALSE); + } + + /* Apply magic (good or bad) according to type */ + if (process_hooks(HOOK_APPLY_MAGIC, "(O,d,d)", o_ptr, level, power)) + return; + switch (o_ptr->tval) + { + case TV_BOOK: + { + /* Randomize random books */ + if (o_ptr->sval == 255) + { + int i = 0; + + /* Only random ones */ + if (magik(75)) + { + i = get_random_spell(SKILL_MAGIC, level); + } + else + { + i = get_random_spell(SKILL_SPIRITUALITY, level); + } + + /* Use globe of light(or the first one) */ + if (i == -1) + o_ptr->pval = 0; + else + o_ptr->pval = i; + } + + break; + } + + case TV_LITE: + { + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Hack -- random fuel */ + if (f4 & TR4_FUEL_LITE) + { + if (k_info[o_ptr->k_idx].pval2 > 0) o_ptr->timeout = randint(k_info[o_ptr->k_idx].pval2); + } + + break; + } + + case TV_CORPSE: + { + /* Hack -- choose a monster */ + monster_race* r_ptr; + int r_idx = get_mon_num(dun_level); + r_ptr = &r_info[r_idx]; + + if (!(r_ptr->flags1 & RF1_UNIQUE)) + o_ptr->pval2 = r_idx; + else + o_ptr->pval2 = 2; + o_ptr->pval3 = 0; + break; + } + + case TV_EGG: + { + /* Hack -- choose a monster */ + monster_race* r_ptr; + int r_idx, count = 0; + bool_ OK = FALSE; + + while ((!OK) && (count < 1000)) + { + r_idx = get_mon_num(dun_level); + r_ptr = &r_info[r_idx]; + + if (r_ptr->flags9 & RF9_HAS_EGG) + { + o_ptr->pval2 = r_idx; + OK = TRUE; + } + count++; + } + if (count == 1000) o_ptr->pval2 = 940; /* Blue fire-lizard */ + + r_ptr = &r_info[o_ptr->pval2]; + o_ptr->weight = (r_ptr->weight + rand_int(r_ptr->weight) / 100) + 1; + o_ptr->pval = r_ptr->weight * 3 + rand_int(r_ptr->weight) + 1; + break; + } + + case TV_HYPNOS: + { + /* Hack -- choose a monster */ + monster_race* r_ptr; + int r_idx = get_mon_num(dun_level); + r_ptr = &r_info[r_idx]; + + if (!(r_ptr->flags1 & RF1_NEVER_MOVE)) + o_ptr->pval = r_idx; + else + o_ptr->pval = 20; + + r_idx = o_ptr->pval; + r_ptr = &r_info[r_idx]; + + o_ptr->pval3 = maxroll(r_ptr->hdice, r_ptr->hside); + o_ptr->pval2 = o_ptr->pval2; + o_ptr->exp = 0; + o_ptr->elevel = r_ptr->level; + break; + } + + case TV_WAND: + { + /* Decide the spell, pval == -1 means to bypass spell selection */ + if (o_ptr->pval != -1) + { + int spl = get_random_stick(TV_WAND, dun_level); + + if (spl == -1) + { + spl = MANATHRUST; + } + + o_ptr->pval2 = spl; + } + /* Is the spell predefined by the object kind? */ + else if (k_ptr->pval == -1) + { + o_ptr->pval2 = k_ptr->pval2; + } + + /* Ok now get a base level */ + bonus_lvl = get_stick_base_level(TV_WAND, dun_level, o_ptr->pval2); + max_lvl = get_stick_max_level(TV_WAND, dun_level, o_ptr->pval2); + o_ptr->pval3 = (max_lvl << 16) + (bonus_lvl & 0xFFFF); + + /* Hack -- charge wands */ + charge_stick(o_ptr); + + break; + } + + case TV_STAFF: + { + /* Decide the spell, pval == -1 means to bypass spell selection */ + if (o_ptr->pval != -1) + { + int spl = get_random_stick(TV_STAFF, dun_level); + + if (spl == -1) + { + spl = GLOBELIGHT; + } + + o_ptr->pval2 = spl; + } + /* Is the spell predefined by the object kind? */ + else if (k_ptr->pval == -1) + { + o_ptr->pval2 = k_ptr->pval2; + } + + /* Ok now get a base level */ + bonus_lvl = get_stick_base_level(TV_STAFF, dun_level, o_ptr->pval2); + max_lvl = get_stick_max_level(TV_STAFF, dun_level, o_ptr->pval2); + o_ptr->pval3 = (max_lvl << 16) + (bonus_lvl & 0xFFFF); + + /* Hack -- charge staffs */ + charge_stick(o_ptr); + + break; + } + + case TV_CHEST: + { + /* Hack -- skip ruined chests */ + if (k_info[o_ptr->k_idx].level <= 0) break; + + /* Pick a trap */ + place_trap_object(o_ptr); + + /* Hack - set pval2 to the number of objects in it */ + if (o_ptr->pval) + o_ptr->pval2 = (o_ptr->sval % SV_CHEST_MIN_LARGE) * 2; + break; + } + case TV_POTION: + if (o_ptr->sval == SV_POTION_BLOOD) + { + /* Rating boost */ + rating += 25; + /* Mention the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + } + break; + case TV_POTION2: + if (o_ptr->sval == SV_POTION2_MIMIC) + { + s32b mimic = find_random_mimic_shape(level, FALSE); + o_ptr->pval2 = mimic; + } + break; + case TV_INSTRUMENT: + { + if (o_ptr->sval != SV_HORN) + { + /* Nothing */ + } + else + { + if (is_ego_p(o_ptr, EGO_INST_DRAGONKIND)) + { + switch (randint(4)) + { + case 1: + o_ptr->pval2 = GF_ELEC; + break; + case 2: + o_ptr->pval2 = GF_FIRE; + break; + case 3: + o_ptr->pval2 = GF_COLD; + break; + case 4: + o_ptr->pval2 = GF_ACID; + break; + } + } + } + break; + } + + case TV_TOOL: + { + break; + } + + } +} + +void trap_hack(object_type *o_ptr) +{ + if (o_ptr->tval != TV_TRAPKIT) return; + + switch (o_ptr->sval) + { + case SV_TRAPKIT_POTION: + case SV_TRAPKIT_SCROLL: + case SV_TRAPKIT_DEVICE: + o_ptr->to_h = 0; + o_ptr->to_d = 0; + default: + return; + } +} + +/* Add a random glag to the ego item */ +void add_random_ego_flag(object_type *o_ptr, int fego, bool_ *limit_blows) +{ + if (fego & ETR4_SUSTAIN) + { + /* Make a random sustain */ + switch (randint(6)) + { + case 1: + o_ptr->art_flags2 |= TR2_SUST_STR; + break; + case 2: + o_ptr->art_flags2 |= TR2_SUST_INT; + break; + case 3: + o_ptr->art_flags2 |= TR2_SUST_WIS; + break; + case 4: + o_ptr->art_flags2 |= TR2_SUST_DEX; + break; + case 5: + o_ptr->art_flags2 |= TR2_SUST_CON; + break; + case 6: + o_ptr->art_flags2 |= TR2_SUST_CHR; + break; + } + } + + if (fego & ETR4_OLD_RESIST) + { + /* Make a random resist, equal probabilities */ + switch (randint(11)) + { + case 1: + o_ptr->art_flags2 |= (TR2_RES_BLIND); + break; + case 2: + o_ptr->art_flags2 |= (TR2_RES_CONF); + break; + case 3: + o_ptr->art_flags2 |= (TR2_RES_SOUND); + break; + case 4: + o_ptr->art_flags2 |= (TR2_RES_SHARDS); + break; + case 5: + o_ptr->art_flags2 |= (TR2_RES_NETHER); + break; + case 6: + o_ptr->art_flags2 |= (TR2_RES_NEXUS); + break; + case 7: + o_ptr->art_flags2 |= (TR2_RES_CHAOS); + break; + case 8: + o_ptr->art_flags2 |= (TR2_RES_DISEN); + break; + case 9: + o_ptr->art_flags2 |= (TR2_RES_POIS); + break; + case 10: + o_ptr->art_flags2 |= (TR2_RES_DARK); + break; + case 11: + o_ptr->art_flags2 |= (TR2_RES_LITE); + break; + } + } + + if (fego & ETR4_ABILITY) + { + /* Choose an ability */ + switch (randint(8)) + { + case 1: + o_ptr->art_flags3 |= (TR3_FEATHER); + break; + case 2: + o_ptr->art_flags3 |= (TR3_LITE1); + break; + case 3: + o_ptr->art_flags3 |= (TR3_SEE_INVIS); + break; + case 4: + o_ptr->art_esp |= (ESP_ALL); + break; + case 5: + o_ptr->art_flags3 |= (TR3_SLOW_DIGEST); + break; + case 6: + o_ptr->art_flags3 |= (TR3_REGEN); + break; + case 7: + o_ptr->art_flags2 |= (TR2_FREE_ACT); + break; + case 8: + o_ptr->art_flags2 |= (TR2_HOLD_LIFE); + break; + } + } + + if (fego & ETR4_R_ELEM) + { + /* Make an acid/elec/fire/cold/poison resist */ + random_resistance(o_ptr, FALSE, randint(14) + 4); + } + if (fego & ETR4_R_LOW) + { + /* Make an acid/elec/fire/cold resist */ + random_resistance(o_ptr, FALSE, randint(12) + 4); + } + + if (fego & ETR4_R_HIGH) + { + /* Make a high resist */ + random_resistance(o_ptr, FALSE, randint(22) + 16); + } + if (fego & ETR4_R_ANY) + { + /* Make any resist */ + random_resistance(o_ptr, FALSE, randint(34) + 4); + } + + if (fego & ETR4_R_DRAGON) + { + /* Make "dragon resist" */ + dragon_resist(o_ptr); + } + + if (fego & ETR4_SLAY_WEAP) + { + /* Make a Weapon of Slaying */ + + if (randint(3) == 1) /* double damage */ + o_ptr->dd *= 2; + else + { + do + { + o_ptr->dd++; + } + while (randint(o_ptr->dd) == 1); + do + { + o_ptr->ds++; + } + while (randint(o_ptr->ds) == 1); + } + if (randint(5) == 1) + { + o_ptr->art_flags1 |= TR1_BRAND_POIS; + } + if (o_ptr->tval == TV_SWORD && (randint(3) == 1)) + { + o_ptr->art_flags1 |= TR1_VORPAL; + } + } + + if (fego & ETR4_DAM_DIE) + { + /* Increase damage dice */ + o_ptr->dd++; + } + + if (fego & ETR4_DAM_SIZE) + { + /* Increase damage dice size */ + o_ptr->ds++; + } + + if (fego & ETR4_LIMIT_BLOWS) + { + /* Swap this flag */ + *limit_blows = !(*limit_blows); + } + + if (fego & ETR4_PVAL_M1) + { + /* Increase pval */ + o_ptr->pval++; + } + + if (fego & ETR4_PVAL_M2) + { + /* Increase pval */ + o_ptr->pval += m_bonus(2, dun_level); + } + + if (fego & ETR4_PVAL_M3) + { + /* Increase pval */ + o_ptr->pval += m_bonus(3, dun_level); + } + + if (fego & ETR4_PVAL_M5) + { + /* Increase pval */ + o_ptr->pval += m_bonus(5, dun_level); + } + if (fego & ETR4_AC_M1) + { + /* Increase ac */ + o_ptr->to_a++; + } + + if (fego & ETR4_AC_M2) + { + /* Increase ac */ + o_ptr->to_a += m_bonus(2, dun_level); + } + + if (fego & ETR4_AC_M3) + { + /* Increase ac */ + o_ptr->to_a += m_bonus(3, dun_level); + } + + if (fego & ETR4_AC_M5) + { + /* Increase ac */ + o_ptr->to_a += m_bonus(5, dun_level); + } + + if (fego & ETR4_TH_M1) + { + /* Increase to hit */ + o_ptr->to_h++; + } + + if (fego & ETR4_TH_M2) + { + /* Increase to hit */ + o_ptr->to_h += m_bonus(2, dun_level); + } + + if (fego & ETR4_TH_M3) + { + /* Increase to hit */ + o_ptr->to_h += m_bonus(3, dun_level); + } + + if (fego & ETR4_TH_M5) + { + /* Increase to hit */ + o_ptr->to_h += m_bonus(5, dun_level); + } + + if (fego & ETR4_TD_M1) + { + /* Increase to dam */ + o_ptr->to_d++; + } + + if (fego & ETR4_TD_M2) + { + /* Increase to dam */ + o_ptr->to_d += m_bonus(2, dun_level); + } + + if (fego & ETR4_TD_M3) + { + /* Increase to dam */ + o_ptr->to_d += m_bonus(3, dun_level); + } + + if (fego & ETR4_TD_M5) + { + /* Increase to dam */ + o_ptr->to_d += m_bonus(5, dun_level); + } + + if (fego & ETR4_R_P_ABILITY) + { + /* Add a random pval-affected ability */ + /* This might cause boots with + to blows */ + switch (randint(6)) + { + case 1: + o_ptr->art_flags1 |= TR1_STEALTH; + break; + case 2: + o_ptr->art_flags1 |= TR1_SEARCH; + break; + case 3: + o_ptr->art_flags1 |= TR1_INFRA; + break; + case 4: + o_ptr->art_flags1 |= TR1_TUNNEL; + break; + case 5: + o_ptr->art_flags1 |= TR1_SPEED; + break; + case 6: + o_ptr->art_flags1 |= TR1_BLOWS; + break; + } + } + if (fego & ETR4_R_STAT) + { + /* Add a random stat */ + switch (randint(6)) + { + case 1: + o_ptr->art_flags1 |= TR1_STR; + break; + case 2: + o_ptr->art_flags1 |= TR1_INT; + break; + case 3: + o_ptr->art_flags1 |= TR1_WIS; + break; + case 4: + o_ptr->art_flags1 |= TR1_DEX; + break; + case 5: + o_ptr->art_flags1 |= TR1_CON; + break; + case 6: + o_ptr->art_flags1 |= TR1_CHR; + break; + } + } + + if (fego & ETR4_R_STAT_SUST) + { + /* Add a random stat and sustain it */ + switch (randint(6)) + { + case 1: + { + o_ptr->art_flags1 |= TR1_STR; + o_ptr->art_flags2 |= TR2_SUST_STR; + break; + } + + case 2: + { + o_ptr->art_flags1 |= TR1_INT; + o_ptr->art_flags2 |= TR2_SUST_INT; + break; + } + + case 3: + { + o_ptr->art_flags1 |= TR1_WIS; + o_ptr->art_flags2 |= TR2_SUST_WIS; + break; + } + + case 4: + { + o_ptr->art_flags1 |= TR1_DEX; + o_ptr->art_flags2 |= TR2_SUST_DEX; + break; + } + + case 5: + { + o_ptr->art_flags1 |= TR1_CON; + o_ptr->art_flags2 |= TR2_SUST_CON; + break; + } + case 6: + { + o_ptr->art_flags1 |= TR1_CHR; + o_ptr->art_flags2 |= TR2_SUST_CHR; + break; + } + } + } + + if (fego & ETR4_R_IMMUNITY) + { + /* Give a random immunity */ + switch (randint(4)) + { + case 1: + { + o_ptr->art_flags2 |= TR2_IM_FIRE; + o_ptr->art_flags3 |= TR3_IGNORE_FIRE; + break; + } + case 2: + { + o_ptr->art_flags2 |= TR2_IM_ACID; + o_ptr->art_flags3 |= TR3_IGNORE_ACID; + break; + } + case 3: + { + o_ptr->art_flags2 |= TR2_IM_ELEC; + o_ptr->art_flags3 |= TR3_IGNORE_ELEC; + break; + } + case 4: + { + o_ptr->art_flags2 |= TR2_IM_COLD; + o_ptr->art_flags3 |= TR3_IGNORE_COLD; + break; + } + } + } +} + +/* + * Complete the "creation" of an object by applying "magic" to the item + * + * This includes not only rolling for random bonuses, but also putting the + * finishing touches on ego-items and artifacts, giving charges to wands and + * staffs, giving fuel to lites, and placing traps on chests. + * + * In particular, note that "Instant Artifacts", if "created" by an external + * routine, must pass through this function to complete the actual creation. + * + * The base "chance" of the item being "good" increases with the "level" + * parameter, which is usually derived from the dungeon level, being equal + * to the level plus 10, up to a maximum of 75. If "good" is true, then + * the object is guaranteed to be "good". If an object is "good", then + * the chance that the object will be "great" (ego-item or artifact), also + * increases with the "level", being equal to half the level, plus 5, up to + * a maximum of 20. If "great" is true, then the object is guaranteed to be + * "great". At dungeon level 65 and below, 15/100 objects are "great". + * + * If the object is not "good", there is a chance it will be "cursed", and + * if it is "cursed", there is a chance it will be "broken". These chances + * are related to the "good" / "great" chances above. + * + * Otherwise "normal" rings and amulets will be "good" half the time and + * "cursed" half the time, unless the ring/amulet is always good or cursed. + * + * If "okay" is true, and the object is going to be "great", then there is + * a chance that an artifact will be created. This is true even if both the + * "good" and "great" arguments are false. As a total hack, if "great" is + * true, then the item gets 3 extra "attempts" to become an artifact. + */ +int hack_apply_magic_power = 0; +void apply_magic(object_type *o_ptr, int lev, bool_ okay, bool_ good, bool_ great) +{ + int i, rolls, f1, f2, power; + object_kind *k_ptr = &k_info[o_ptr->k_idx]; + + /* Aply luck */ + lev += luck( -7, 7); + + /* Spell in it ? no ! */ + if (k_ptr->flags5 & TR5_SPELL_CONTAIN) + o_ptr->pval2 = -1; + + /* Important to do before all else, be sure to have the basic obvious flags set */ + o_ptr->art_oflags1 = k_ptr->oflags1; + o_ptr->art_oflags2 = k_ptr->oflags2; + o_ptr->art_oflags3 = k_ptr->oflags3; + o_ptr->art_oflags4 = k_ptr->oflags4; + o_ptr->art_oflags5 = k_ptr->oflags5; + o_ptr->art_oesp = k_ptr->oesp; + + /* No need to touch normal artifacts */ + if (k_ptr->flags3 & TR3_NORM_ART) + { + /* Ahah! we tried to trick us !! */ + if (k_ptr->artifact || + ((k_ptr->flags4 & TR4_SPECIAL_GENE) && + (!k_allow_special[o_ptr->k_idx]))) + { + object_prep(o_ptr, lookup_kind(k_ptr->btval, k_ptr->bsval)); + if (wizard) msg_print("We've been tricked!"); + } + else + { + /* Arg I hate so much to do that ... but I see no other way */ + if ((o_ptr->tval == TV_WAND) || (o_ptr->tval == TV_STAFF)) + { + s32b base_lvl, max_lvl; + + /* Is the spell predefined by the object kind? */ + if (k_ptr->pval == -1) + { + o_ptr->pval2 = k_ptr->pval2; + } + + /* Determine a base and a max level */ + base_lvl = get_stick_base_level(o_ptr->tval, dun_level, o_ptr->pval2); + max_lvl = get_stick_max_level(o_ptr->tval, dun_level, o_ptr->pval2); + o_ptr->pval3 = (max_lvl << 16) + (base_lvl & 0xFFFF); + + /* Hack -- charge wands */ + charge_stick(o_ptr); + } + + k_ptr->artifact = TRUE; + + if (cheat_peek || p_ptr->precognition) object_mention(o_ptr); + } + + return; + } + + /* Maximum "level" for various things */ + if (lev > MAX_DEPTH - 1) lev = MAX_DEPTH - 1; + + + /* Base chance of being "good" */ + f1 = lev + 10 + luck( -15, 15); + + /* Maximal chance of being "good" */ + if (f1 > 75) f1 = 75; + + /* Base chance of being "great" */ + f2 = f1 / 2; + + /* Maximal chance of being "great" */ + if (f2 > 20) f2 = 20; + + + /* Assume normal */ + power = 0; + + /* Roll for "good" */ + if (good || magik(f1)) + { + /* Assume "good" */ + power = 1; + + /* Roll for "great" */ + if (great || magik(f2)) power = 2; + } + + /* Roll for "cursed" */ + else if (magik(f1)) + { + /* Assume "cursed" */ + power = -1; + + /* Roll for "broken" */ + if (magik(f2)) power = -2; + } + + /* Mega hack */ + if (hack_apply_magic_power) + { + if (hack_apply_magic_power == -99) + power = 0; + else + power = hack_apply_magic_power; + } + hack_apply_magic_power = 0; + + /* Assume no rolls */ + rolls = 0; + + /* Get one roll if excellent */ + if (power >= 2) rolls = 1; + + /* Hack -- Get four rolls if forced great */ + if (great) rolls = 4; + + /* Hack -- Get no rolls if not allowed */ + if (!okay || o_ptr->name1) rolls = 0; + + /* Roll for artifacts if allowed */ + for (i = 0; i < rolls; i++) + { + /* Roll for an artifact */ + if (make_artifact(o_ptr)) break; + } + + /* Mega hack -- to lazy to do it properly with hooks :) */ + if ((o_ptr->name1 == ART_POWER) && (quest[QUEST_ONE].status < QUEST_STATUS_TAKEN)) + { + o_ptr->name1 = 0; + o_ptr->name2 = 0; + o_ptr->name2b = 0; + object_prep(o_ptr, lookup_kind(TV_RING, SV_RING_INVIS)); + } + + + /* Hack -- analyze artifacts */ + if (o_ptr->name1) + { + artifact_type *a_ptr = &a_info[o_ptr->name1]; + + /* Hack -- Mark the artifact as "created" */ + a_ptr->cur_num = 1; + + /* Extract the other fields */ + o_ptr->pval = a_ptr->pval; + o_ptr->ac = a_ptr->ac; + o_ptr->dd = a_ptr->dd; + o_ptr->ds = a_ptr->ds; + o_ptr->to_a = a_ptr->to_a; + o_ptr->to_h = a_ptr->to_h; + o_ptr->to_d = a_ptr->to_d; + o_ptr->weight = a_ptr->weight; + o_ptr->number = 1; + + /* Hack -- extract the "cursed" flag */ + if (a_ptr->flags3 & (TR3_CURSED)) o_ptr->ident |= (IDENT_CURSED); + + /* Mega-Hack -- increase the rating */ + rating += 10; + + /* Mega-Hack -- increase the rating again */ + if (a_ptr->cost > 50000L) rating += 10; + + /* Set the good item flag */ + good_item_flag = TRUE; + + /* Cheat -- peek at the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + + /* Spell in it ? no ! */ + if (a_ptr->flags5 & TR5_SPELL_CONTAIN) + o_ptr->pval2 = -1; + + /* Give a basic exp/exp level to an artifact that needs it */ + if (a_ptr->flags4 & TR4_LEVELS) + { + o_ptr->elevel = (k_ptr->level / 10) + 1; + o_ptr->exp = player_exp[o_ptr->elevel - 1]; + } + + /* Done */ + return; + } + + + /* Apply magic */ + switch (o_ptr->tval) + { + case TV_RANDART: + { + finalize_randart(o_ptr, lev); + break; + } + case TV_HAFTED: + case TV_POLEARM: + case TV_MSTAFF: + case TV_SWORD: + case TV_AXE: + case TV_BOOMERANG: + case TV_BOW: + case TV_SHOT: + case TV_ARROW: + case TV_BOLT: + case TV_TRAPKIT: + { + if (power) a_m_aux_1(o_ptr, lev, power); + break; + } + + case TV_DAEMON_BOOK: + { + /* UGLY, but needed, depending of sval teh demon stuff are eitehr weapon or armor */ + if (o_ptr->sval == SV_DEMONBLADE) + { + if (power) a_m_aux_1(o_ptr, lev, power); + } + else + { + if (power) a_m_aux_2(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: + { + a_m_aux_2(o_ptr, lev, power); + break; + } + + case TV_RING: + case TV_AMULET: + { + if (!power && (rand_int(100) < 50)) power = -1; + a_m_aux_3(o_ptr, lev, power); + break; + } + + default: + { + a_m_aux_4(o_ptr, lev, power); + break; + } + } + + if (o_ptr->art_name) rating += 40; + + /* Hack -- analyze ego-items */ + else if (o_ptr->name2) + { + ego_item_type *e_ptr; + int j; + bool_ limit_blows = FALSE; + u32b f1, f2, f3, f4, f5, esp; + s16b e_idx; + + e_idx = o_ptr->name2; + + /* Ok now, THAT is truly ugly */ +try_an_other_ego: + e_ptr = &e_info[e_idx]; + + /* Hack -- extra powers */ + for (j = 0; j < 5; j++) + { + /* Rarity check */ + if (magik(e_ptr->rar[j])) + { + o_ptr->art_flags1 |= e_ptr->flags1[j]; + o_ptr->art_flags2 |= e_ptr->flags2[j]; + o_ptr->art_flags3 |= e_ptr->flags3[j]; + o_ptr->art_flags4 |= e_ptr->flags4[j]; + o_ptr->art_flags5 |= e_ptr->flags5[j]; + o_ptr->art_esp |= e_ptr->esp[j]; + + o_ptr->art_oflags1 |= e_ptr->oflags1[j]; + o_ptr->art_oflags2 |= e_ptr->oflags2[j]; + o_ptr->art_oflags3 |= e_ptr->oflags3[j]; + o_ptr->art_oflags4 |= e_ptr->oflags4[j]; + o_ptr->art_oflags5 |= e_ptr->oflags5[j]; + o_ptr->art_oesp |= e_ptr->oesp[j]; + + add_random_ego_flag(o_ptr, e_ptr->fego[j], &limit_blows); + } + } + + /* No insane number of blows */ + if (limit_blows && (o_ptr->art_flags1 & TR1_BLOWS)) + { + if (o_ptr->pval > 2) o_ptr->pval = randint(2); + } + + /* get flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Hack -- acquire "cursed" flag */ + if (f3 & TR3_CURSED) o_ptr->ident |= (IDENT_CURSED); + + /* Hack -- obtain bonuses */ + if (e_ptr->max_to_h > 0) o_ptr->to_h += randint(e_ptr->max_to_h); + if (e_ptr->max_to_h < 0) o_ptr->to_h -= randint( -e_ptr->max_to_h); + if (e_ptr->max_to_d > 0) o_ptr->to_d += randint(e_ptr->max_to_d); + if (e_ptr->max_to_d < 0) o_ptr->to_d -= randint( -e_ptr->max_to_d); + if (e_ptr->max_to_a > 0) o_ptr->to_a += randint(e_ptr->max_to_a); + if (e_ptr->max_to_a < 0) o_ptr->to_a -= randint( -e_ptr->max_to_a); + + /* Hack -- obtain pval */ + if (e_ptr->max_pval > 0) o_ptr->pval += randint(e_ptr->max_pval); + if (e_ptr->max_pval < 0) o_ptr->pval -= randint( -e_ptr->max_pval); + + /* Hack -- apply rating bonus */ + rating += e_ptr->rating; + + if (o_ptr->name2b && (o_ptr->name2b != e_idx)) + { + e_idx = o_ptr->name2b; + goto try_an_other_ego; + } + + /* Spell in it ? no ! */ + if (f5 & TR5_SPELL_CONTAIN) + { + /* Mega hack, mage staves of spell cannot SPELL_CONTAIN */ + if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL)) + { + o_ptr->art_flags5 &= ~TR5_SPELL_CONTAIN; + } + else + o_ptr->pval2 = -1; + } + + /* Cheat -- describe the item */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(o_ptr); + } + + + /* Examine real objects */ + if (o_ptr->k_idx) + { + u32b f1, f2, f3, f4, f5, esp; + + object_kind *k_ptr = &k_info[o_ptr->k_idx]; + + /* Hack -- acquire "cursed" flag */ + if (k_ptr->flags3 & (TR3_CURSED)) o_ptr->ident |= (IDENT_CURSED); + + /* Extract some flags */ + object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &esp); + + /* Hack give a basic exp/exp level to an object that needs it */ + if (f4 & TR4_LEVELS) + { + o_ptr->elevel = (k_ptr->level / 10) + 1; + o_ptr->exp = player_exp[o_ptr->elevel - 1]; + } + + /* Spell in it ? no ! */ + if (f5 & TR5_SPELL_CONTAIN) + { + /* Mega hack, mage staves of spell cannot SPELL_CONTAIN */ + if (is_ego_p(o_ptr, EGO_MSTAFF_SPELL)) + { + o_ptr->art_flags5 &= ~TR5_SPELL_CONTAIN; + } + else + o_ptr->pval2 = -1; + } + + /* Hacccccccckkkkk attack ! :) -- To prevent som ugly crashs */ + if ((o_ptr->tval == TV_MSTAFF) && (o_ptr->sval == SV_MSTAFF) && (o_ptr->pval < 0)) + { + o_ptr->pval = 0; + } + + /* Hack, cant be done in a_m_aux4 because the ego flags are not yet in place */ + if (o_ptr->tval == TV_ROD_MAIN) + { + /* Set the max mana and the current mana */ + o_ptr->pval2 = (f4 & TR4_CAPACITY) ? o_ptr->sval * 2 : o_ptr->sval; + + o_ptr->timeout = o_ptr->pval2; + } + + /* Remove some unnecessary stuff hack */ + if (o_ptr->tval == TV_TRAPKIT) trap_hack(o_ptr); + } +} + + +/* The themed objects to use */ +static obj_theme match_theme; + +/* + * XXX XXX XXX It relies on the fact that obj_theme is a four byte structure + * for its efficient operation. A horrendous hack, I'd say. + */ +void init_match_theme(obj_theme theme) +{ + /* Save the theme */ + match_theme = theme; +} + +/* + * Ditto XXX XXX XXX + */ +static bool_ theme_changed(obj_theme theme) +{ + /* Any of the themes has been changed */ + if (theme.treasure != match_theme.treasure) return (TRUE); + if (theme.combat != match_theme.combat) return (TRUE); + if (theme.magic != match_theme.magic) return (TRUE); + if (theme.tools != match_theme.tools) return (TRUE); + + /* No changes */ + return (FALSE); +} + + +/* + * Maga-Hack -- match certain types of object only. + */ +bool_ kind_is_theme(int k_idx) +{ + object_kind *k_ptr = &k_info[k_idx]; + + s32b prob = 0; + + + /* + * Paranoia -- Prevent accidental "(Nothing)" + * that are results of uninitialised theme structs. + * + * Caution: Junks go into the allocation table. + */ + if (match_theme.treasure + match_theme.combat + + match_theme.magic + match_theme.tools == 0) return (TRUE); + + + /* Pick probability to use */ + switch (k_ptr->tval) + { + case TV_SKELETON: + case TV_BOTTLE: + case TV_JUNK: + case TV_CORPSE: + case TV_EGG: + { + /* + * Degree of junk is defined in terms of the other + * 4 quantities XXX XXX XXX + * The type of prob should be *signed* as well as + * larger than theme components, or we would see + * unexpected, well, junks. + */ + prob = 100 - (match_theme.treasure + match_theme.combat + + match_theme.magic + match_theme.tools); + break; + } + case TV_CHEST: + prob = match_theme.treasure; + break; + case TV_CROWN: + prob = match_theme.treasure; + break; + case TV_DRAG_ARMOR: + prob = match_theme.treasure; + break; + case TV_AMULET: + prob = match_theme.treasure; + break; + case TV_RING: + prob = match_theme.treasure; + break; + + case TV_SHOT: + prob = match_theme.combat; + break; + case TV_ARROW: + prob = match_theme.combat; + break; + case TV_BOLT: + prob = match_theme.combat; + break; + case TV_BOOMERANG: + prob = match_theme.combat; + break; + case TV_BOW: + prob = match_theme.combat; + break; + case TV_HAFTED: + prob = match_theme.combat; + break; + case TV_POLEARM: + prob = match_theme.combat; + break; + case TV_SWORD: + prob = match_theme.combat; + break; + case TV_AXE: + prob = match_theme.combat; + break; + case TV_GLOVES: + prob = match_theme.combat; + break; + case TV_HELM: + prob = match_theme.combat; + break; + case TV_SHIELD: + prob = match_theme.combat; + break; + case TV_SOFT_ARMOR: + prob = match_theme.combat; + break; + case TV_HARD_ARMOR: + prob = match_theme.combat; + break; + + case TV_MSTAFF: + prob = match_theme.magic; + break; + case TV_STAFF: + prob = match_theme.magic; + break; + case TV_WAND: + prob = match_theme.magic; + break; + case TV_ROD: + prob = match_theme.magic; + break; + case TV_ROD_MAIN: + prob = match_theme.magic; + break; + case TV_SCROLL: + prob = match_theme.magic; + break; + case TV_PARCHMENT: + prob = match_theme.magic; + break; + case TV_POTION: + prob = match_theme.magic; + break; + case TV_POTION2: + prob = match_theme.magic; + break; + case TV_BATERIE: + prob = match_theme.magic; + break; + case TV_RANDART: + prob = match_theme.magic; + break; + case TV_RUNE1: + prob = match_theme.magic; + break; + case TV_RUNE2: + prob = match_theme.magic; + break; + case TV_BOOK: + prob = match_theme.magic; + break; + case TV_SYMBIOTIC_BOOK: + prob = match_theme.magic; + break; + case TV_MUSIC_BOOK: + prob = match_theme.magic; + break; + case TV_DRUID_BOOK: + prob = match_theme.magic; + break; + case TV_DAEMON_BOOK: + prob = match_theme.magic; + break; + + case TV_LITE: + prob = match_theme.tools; + break; + case TV_CLOAK: + prob = match_theme.tools; + break; + case TV_BOOTS: + prob = match_theme.tools; + break; + case TV_SPIKE: + prob = match_theme.tools; + break; + case TV_DIGGING: + prob = match_theme.tools; + break; + case TV_FLASK: + prob = match_theme.tools; + break; + case TV_FOOD: + prob = match_theme.tools; + break; + case TV_TOOL: + prob = match_theme.tools; + break; + case TV_INSTRUMENT: + prob = match_theme.tools; + break; + case TV_TRAPKIT: + prob = match_theme.tools; + break; + } + + /* Roll to see if it can be made */ + if (rand_int(100) < prob) return (TRUE); + + /* Not a match */ + return (FALSE); +} + +/* + * Determine if an object must not be generated. + */ +int kind_is_legal_special = -1; +bool_ kind_is_legal(int k_idx) +{ + object_kind *k_ptr = &k_info[k_idx]; + + if (!kind_is_theme(k_idx)) return FALSE; + + if (k_ptr->flags4 & TR4_SPECIAL_GENE) + { + if (k_allow_special[k_idx]) return TRUE; + else return FALSE; + } + + /* No 2 times the same normal artifact */ + if ((k_ptr->flags3 & TR3_NORM_ART) && (k_ptr->artifact)) + { + return FALSE; + } + + if (k_ptr->tval == TV_CORPSE) + { + if (k_ptr->sval != SV_CORPSE_SKULL && k_ptr->sval != SV_CORPSE_SKELETON && + k_ptr->sval != SV_CORPSE_HEAD && k_ptr->sval != SV_CORPSE_CORPSE) + { + return TRUE; + } + else + { + return FALSE; + } + } + + if (k_ptr->tval == TV_HYPNOS) return FALSE; + + /* Used only for the Nazgul rings */ + if ((k_ptr->tval == TV_RING) && (k_ptr->sval == SV_RING_SPECIAL)) return FALSE; + + /* Are we forced to one tval ? */ + if ((kind_is_legal_special != -1) && (kind_is_legal_special != k_ptr->tval)) return (FALSE); + + /* Assume legal */ + return TRUE; +} + + +/* + * Hack -- determine if a template is "good" + */ +bool_ kind_is_good(int k_idx) +{ + object_kind *k_ptr = &k_info[k_idx]; + + if (!kind_is_legal(k_idx)) return FALSE; + + /* Analyze the item type */ + switch (k_ptr->tval) + { + /* Armor -- Good unless damaged */ + case TV_HARD_ARMOR: + case TV_SOFT_ARMOR: + case TV_DRAG_ARMOR: + case TV_SHIELD: + case TV_CLOAK: + case TV_BOOTS: + case TV_GLOVES: + case TV_HELM: + case TV_CROWN: + { + if (k_ptr->to_a < 0) return (FALSE); + return (TRUE); + } + + /* Weapons -- Good unless damaged */ + case TV_BOW: + case TV_SWORD: + case TV_AXE: + case TV_HAFTED: + case TV_POLEARM: + case TV_DIGGING: + case TV_TRAPKIT: + case TV_MSTAFF: + case TV_BOOMERANG: + { + if (k_ptr->to_h < 0) return (FALSE); + if (k_ptr->to_d < 0) return (FALSE); + return (TRUE); + } + + /* Ammo -- Arrows/Bolts are good */ + case TV_BOLT: + case TV_ARROW: + { + return (TRUE); + } + + /* Rods - Silver and better are good */ + case TV_ROD_MAIN: + { + if (k_ptr->sval >= SV_ROD_SILVER) return (TRUE); + return FALSE; + } + + /* Expensive rod tips are good */ + case TV_ROD: + { + /* Probing is not good, but Recall is*/ + if (k_ptr->cost >= 4500) return TRUE; + return FALSE; + } + + /* The Tomes are good */ + case TV_BOOK: + { + if (k_ptr->sval <= SV_BOOK_MAX_GOOD) return (TRUE); + return FALSE; + } + + /* Rings -- Rings of Speed are good */ + case TV_RING: + { + if (k_ptr->sval == SV_RING_SPEED) return (TRUE); + return (FALSE); + } + + /* Amulets -- Some are good */ + case TV_AMULET: + { + if (k_ptr->sval == SV_AMULET_THE_MAGI) return (TRUE); + if (k_ptr->sval == SV_AMULET_DEVOTION) return (TRUE); + if (k_ptr->sval == SV_AMULET_WEAPONMASTERY) return (TRUE); + if (k_ptr->sval == SV_AMULET_TRICKERY) return (TRUE); + if (k_ptr->sval == SV_AMULET_RESISTANCE) return (TRUE); + if (k_ptr->sval == SV_AMULET_REFLECTION) return (TRUE); + if (k_ptr->sval == SV_AMULET_TELEPATHY) return (TRUE); + return (FALSE); + } + } + + /* Assume not good */ + return (FALSE); +} + +/* +* Determine if template is suitable for building a randart -- dsb +*/ +bool_ kind_is_artifactable(int k_idx) +{ + int i, j; + object_kind *k_ptr = &k_info[k_idx]; + + if (kind_is_good(k_idx)) + { + /* We consider the item artifactable if there is at least one + * randart power in ra_info that could be added to this item. */ + for (i = 0; i < max_ra_idx; i++) + { + randart_part_type *ra_ptr = &ra_info[i]; + + for (j = 0; j < 20; j++) + { + if (ra_ptr->tval[j] != k_ptr->tval) continue; + if (ra_ptr->min_sval[j] > k_ptr->sval) continue; + if (ra_ptr->max_sval[j] < k_ptr->sval) continue; + /* Winner */ + return TRUE; + } + } + } + + /* No match. Too bad. */ + return FALSE; +} + + +/* + * Attempt to make an object (normal or good/great) + * + * This routine plays nasty games to generate the "special artifacts". + * + * This routine uses "object_level" for the "generation level". + * + * We assume that the given object has been "wiped". + * + * To Watch: The allocation table caching is heavily relies on + * an assumption that the SPECIAL_GENE objects should only be created + * through the forge--object_prep()--apply_magic() sequence and + * get_obj_num() should never be called for that purpose XXX XXX XXX + */ +bool_ make_object(object_type *j_ptr, bool_ good, bool_ great, obj_theme theme) +{ + int invprob, base; + + + /* Chance of "special object" */ + invprob = (good ? 10 - luck( -9, 9) : 1000); + + /* Base level for the object */ + base = (good ? (object_level + 10) : object_level); + + + /* Generate a special object, or a normal object */ + if ((rand_int(invprob) != 0) || !make_artifact_special(j_ptr)) + { + int k_idx; + + /* See if the theme has been changed XXX XXX XXX */ + if (theme_changed(theme)) + { + /* Select items based on "theme" */ + init_match_theme(theme); + + /* Invalidate the cached allocation table */ + alloc_kind_table_valid = FALSE; + } + + /* Good objects */ + if (good) + { + /* Activate restriction */ + get_obj_num_hook = kind_is_good; + + /* Prepare allocation table */ + get_obj_num_prep(); + } + + /* Normal objects -- only when the cache is invalidated */ + else if (!alloc_kind_table_valid) + { + /* Activate normal restriction */ + get_obj_num_hook = kind_is_legal; + + /* Prepare allocation table */ + get_obj_num_prep(); + + /* The table is synchronised */ + alloc_kind_table_valid = TRUE; + } + + /* Pick a random object */ + k_idx = get_obj_num(base); + + /* Good objects */ + if (good) + { + /* Restore normal restriction */ + get_obj_num_hook = kind_is_legal; + + /* Prepare allocation table */ + get_obj_num_prep(); + + /* The table is synchronised */ + alloc_kind_table_valid = TRUE; + } + + /* Handle failure */ + if (!k_idx) return (FALSE); + + /* Prepare the object */ + object_prep(j_ptr, k_idx); + } + + /* Apply magic (allow artifacts) */ + apply_magic(j_ptr, object_level, TRUE, good, great); + + /* Hack -- generate multiple spikes/missiles */ + switch (j_ptr->tval) + { + case TV_SPIKE: + case TV_SHOT: + case TV_ARROW: + case TV_BOLT: + { + j_ptr->number = (byte)damroll(6, 7); + } + } + + /* hack, no multiple artifacts */ + if (artifact_p(j_ptr)) j_ptr->number = 1; + + /* Notice "okay" out-of-depth objects */ + if (!cursed_p(j_ptr) && + (k_info[j_ptr->k_idx].level > dun_level)) + { + /* Rating increase */ + rating += (k_info[j_ptr->k_idx].level - dun_level); + + /* Cheat -- peek at items */ + if ((cheat_peek) || (p_ptr->precognition)) object_mention(j_ptr); + } + + /* Success */ + return (TRUE); +} + + + +/* + * Attempt to place an object (normal or good/great) at the given location. + * + * This routine plays nasty games to generate the "special artifacts". + * + * This routine uses "object_level" for the "generation level". + * + * This routine requires a clean floor grid destination. + */ +void place_object(int y, int x, bool_ good, bool_ great, int where) +{ + s16b o_idx; + + cave_type *c_ptr; + + object_type forge; + object_type *q_ptr; + + + /* Paranoia -- check bounds */ + if (!in_bounds(y, x)) return; + + /* Require clean floor space */ + if (!cave_clean_bold(y, x)) return; + + + /* Get local object */ + q_ptr = &forge; + + /* Wipe the object */ + object_wipe(q_ptr); + + /* Make an object (if possible) */ + if (!make_object(q_ptr, good, great, d_info[dungeon_type].objs)) return; + + if (where == OBJ_FOUND_VAULT) + { + q_ptr->found = OBJ_FOUND_VAULT; + q_ptr->found_aux1 = dungeon_type; + q_ptr->found_aux2 = level_or_feat(dungeon_type, dun_level); + } + else if (where == OBJ_FOUND_FLOOR) + { + q_ptr->found = OBJ_FOUND_FLOOR; + q_ptr->found_aux1 = dungeon_type; + q_ptr->found_aux2 = level_or_feat(dungeon_type, dun_level); + } + else if (where == OBJ_FOUND_SPECIAL) + { + q_ptr->found = OBJ_FOUND_SPECIAL; + } + else if (where == OBJ_FOUND_RUBBLE) + { + q_ptr->found = OBJ_FOUND_RUBBLE; + } + + /* Make an object */ + o_idx = o_pop(); + + /* Success */ + if (o_idx) + { + object_type *o_ptr; + + /* Acquire object */ + o_ptr = &o_list[o_idx]; + + /* Structure Copy */ + object_copy(o_ptr, q_ptr); + + /* Location */ + o_ptr->iy = y; + o_ptr->ix = x; + + /* Acquire grid */ + c_ptr = &cave[y][x]; + + /* Build a stack */ + o_ptr->next_o_idx = c_ptr->o_idx; + + /* Place the object */ + c_ptr->o_idx = o_idx; + + /* Notice */ + note_spot(y, x); + + /* Redraw */ + lite_spot(y, x); + } + + /* Object array overflow */ + else + { + /* Hack -- Preserve artifacts */ + if (q_ptr->name1) + { + a_info[q_ptr->name1].cur_num = 0; + } + else if (k_info[q_ptr->k_idx].flags3 & TR3_NORM_ART) + { + k_info[q_ptr->k_idx].artifact = 0; + } + else if (q_ptr->tval == TV_RANDART) + { + random_artifacts[q_ptr->sval].generated = FALSE; + } + } +} + + +/* + * XXX XXX XXX Do not use these hard-coded values. + */ +#define OBJ_GOLD_LIST 480 /* First "gold" entry */ +#define MAX_GOLD 18 /* Number of "gold" entries */ + +/* + * Make a treasure object + * + * The location must be a legal, clean, floor grid. + */ +bool_ make_gold(object_type *j_ptr) +{ + int i; + + s32b base; + + + /* Hack -- Pick a Treasure variety */ + i = ((randint(object_level + 2) + 2) / 2) - 1; + + /* Apply "extra" magic */ + if (rand_int(GREAT_OBJ) == 0) + { + i += randint(object_level + 1); + } + + /* Hack -- Creeping Coins only generate "themselves" */ + if (coin_type) i = coin_type; + + /* Do not create "illegal" Treasure Types */ + if (i >= MAX_GOLD) i = MAX_GOLD - 1; + + /* Prepare a gold object */ + object_prep(j_ptr, OBJ_GOLD_LIST + i); + + /* Hack -- Base coin cost */ + base = k_info[OBJ_GOLD_LIST + i].cost; + + /* Determine how much the treasure is "worth" */ + j_ptr->pval = (base + (8L * randint(base)) + randint(8)); + + /* Success */ + return (TRUE); +} + + +/* + * Places a treasure (Gold or Gems) at given location + * + * The location must be a legal, clean, floor grid. + */ +void place_gold(int y, int x) +{ + s16b o_idx; + + cave_type *c_ptr; + + object_type forge; + object_type *q_ptr; + + + /* Paranoia -- check bounds */ + if (!in_bounds(y, x)) return; + + /* Require clean floor space */ + if (!cave_clean_bold(y, x)) return; + + + /* Get local object */ + q_ptr = &forge; + + /* Wipe the object */ + object_wipe(q_ptr); + + /* Make some gold */ + if (!make_gold(q_ptr)) return; + + + /* Make an object */ + o_idx = o_pop(); + + /* Success */ + if (o_idx) + { + object_type *o_ptr; + + /* Acquire object */ + o_ptr = &o_list[o_idx]; + + /* Copy the object */ + object_copy(o_ptr, q_ptr); + + /* Save location */ + o_ptr->iy = y; + o_ptr->ix = x; + + /* Acquire grid */ + c_ptr = &cave[y][x]; + + /* Build a stack */ + o_ptr->next_o_idx = c_ptr->o_idx; + + /* Place the object */ + c_ptr->o_idx = o_idx; + + /* Notice */ + note_spot(y, x); + + /* Redraw */ + lite_spot(y, x); + } +} + + +/* + * Let an object fall to the ground at or near a location. + * + * The initial location is assumed to be "in_bounds()". + * + * This function takes a parameter "chance". This is the percentage + * chance that the item will "disappear" instead of drop. If the object + * has been thrown, then this is the chance of disappearance on contact. + * + * Hack -- this function uses "chance" to determine if it should produce + * some form of "description" of the drop event (under the player). + * + * We check several locations to see if we can find a location at which + * the object can combine, stack, or be placed. Artifacts will try very + * hard to be placed, including "teleporting" to a useful grid if needed. + */ +s16b drop_near(object_type *j_ptr, int chance, int y, int x) +{ + int i, k, d, s; + + int bs, bn; + int by, bx; + int dy, dx; + int ty, tx; + + s16b o_idx = 0; + + s16b this_o_idx, next_o_idx = 0; + + cave_type *c_ptr; + + char o_name[80]; + + bool_ flag = FALSE; + bool_ done = FALSE; + + bool_ plural = FALSE; + + + /* Extract plural */ + if (j_ptr->number != 1) plural = TRUE; + + /* Describe object */ + object_desc(o_name, j_ptr, FALSE, 0); + + + /* Handle normal "breakage" */ + if (!(j_ptr->art_name || artifact_p(j_ptr)) && (rand_int(100) < chance)) + { + /* Message */ + msg_format("The %s disappear%s.", + o_name, (plural ? "" : "s")); + + /* Debug */ + if (wizard) msg_print("(breakage)"); + + /* Failure */ + return (0); + } + + + /* Score */ + bs = -1; + + /* Picker */ + bn = 0; + + /* Default */ + by = y; + bx = x; + + /* Scan local grids */ + for (dy = -3; dy <= 3; dy++) + { + /* Scan local grids */ + for (dx = -3; dx <= 3; dx++) + { + bool_ comb = FALSE; + + /* Calculate actual distance */ + d = (dy * dy) + (dx * dx); + + /* Ignore distant grids */ + if (d > 10) continue; + + /* Location */ + ty = y + dy; + tx = x + dx; + + /* Skip illegal grids */ + if (!in_bounds(ty, tx)) continue; + + /* Require line of sight */ + if (!los(y, x, ty, tx)) continue; + + /* Obtain grid */ + c_ptr = &cave[ty][tx]; + + /* Require floor space (or shallow terrain) -KMW- */ + if (!(f_info[c_ptr->feat].flags1 & FF1_FLOOR)) continue; + + /* No traps */ + if (c_ptr->t_idx) continue; + + /* No objects */ + k = 0; + + /* Scan objects in that grid */ + for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) + { + object_type * o_ptr; + + /* Acquire object */ + o_ptr = &o_list[this_o_idx]; + + /* Acquire next object */ + next_o_idx = o_ptr->next_o_idx; + + /* Check for possible combination */ + if (object_similar(o_ptr, j_ptr)) comb = TRUE; + + /* Count objects */ + k++; + } + + /* Add new object */ + if (!comb) k++; + + /* No stacking (allow combining) */ + if (!testing_stack && (k > 1)) continue; + + /* Paranoia */ + if (k > 23) continue; + + /* Calculate score */ + s = 1000 - (d + k * 5); + + /* Skip bad values */ + if (s < bs) continue; + + /* New best value */ + if (s > bs) bn = 0; + + /* Apply the randomizer to equivalent values */ + if ((++bn >= 2) && (rand_int(bn) != 0)) continue; + + /* Keep score */ + bs = s; + + /* Track it */ + by = ty; + bx = tx; + + /* Okay */ + flag = TRUE; + } + } + + + /* Handle lack of space */ + if (!flag && !(artifact_p(j_ptr) || j_ptr->art_name)) + { + /* Message */ + msg_format("The %s disappear%s.", + o_name, (plural ? "" : "s")); + + /* Debug */ + if (wizard) msg_print("(no floor space)"); + + /* Failure */ + return (0); + } + + + /* Find a grid */ + for (i = 0; !flag; i++) + { + /* Bounce around */ + if (i < 1000) + { + ty = rand_spread(by, 1); + tx = rand_spread(bx, 1); + } + + /* Random locations */ + else + { + ty = rand_int(cur_hgt); + tx = rand_int(cur_wid); + } + + /* Grid */ + c_ptr = &cave[ty][tx]; + + /* Require floor space (or shallow terrain) -KMW- */ + if ((c_ptr->feat != FEAT_FLOOR) && + (c_ptr->feat != FEAT_SHAL_WATER) && + (c_ptr->feat != FEAT_GRASS) && + (c_ptr->feat != FEAT_DIRT) && + (c_ptr->feat != FEAT_SHAL_LAVA)) continue; + + /* Bounce to that location */ + by = ty; + bx = tx; + + /* Require floor space */ + if (!cave_clean_bold(by, bx)) continue; + + /* Okay */ + flag = TRUE; + } + + + /* Grid */ + c_ptr = &cave[by][bx]; + + /* Scan objects in that grid for combination */ + for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) + { + object_type * o_ptr; + + /* Acquire object */ + o_ptr = &o_list[this_o_idx]; + + /* Acquire next object */ + next_o_idx = o_ptr->next_o_idx; + + /* Check for combination */ + if (object_similar(o_ptr, j_ptr)) + { + /* Combine the items */ + object_absorb(o_ptr, j_ptr); + + /* Success */ + done = TRUE; + + /* Done */ + break; + } + } + + /* Get new object */ + if (!done) o_idx = o_pop(); + + /* Failure */ + if (!done && !o_idx) + { + /* Message */ + msg_format("The %s disappear%s.", + o_name, (plural ? "" : "s")); + + /* Debug */ + if (wizard) msg_print("(too many objects)"); + + /* Hack -- Preserve artifacts */ + if (j_ptr->name1) + { + a_info[j_ptr->name1].cur_num = 0; + } + else if (k_info[j_ptr->k_idx].flags3 & TR3_NORM_ART) + { + k_info[j_ptr->k_idx].artifact = 0; + } + else if (j_ptr->tval == TV_RANDART) + { + random_artifacts[j_ptr->sval].generated = FALSE; + } + + /* Failure */ + return (0); + } + + /* Stack */ + if (!done) + { + /* Structure copy */ + object_copy(&o_list[o_idx], j_ptr); + + /* Access new object */ + j_ptr = &o_list[o_idx]; + + /* Locate */ + j_ptr->iy = by; + j_ptr->ix = bx; + + /* No monster */ + j_ptr->held_m_idx = 0; + + /* Build a stack */ + j_ptr->next_o_idx = c_ptr->o_idx; + + /* Place the object */ + c_ptr->o_idx = o_idx; + + /* Success */ + done = TRUE; + } + + /* Note the spot */ + note_spot(by, bx); + + /* Draw the spot */ + lite_spot(by, bx); + + /* Mega-Hack -- no message if "dropped" by player */ + /* Message when an object falls under the player */ + if (chance && (by == p_ptr->py) && (bx == p_ptr->px)) + { + msg_print("You feel something roll beneath your feet."); + /* Sound */ + sound(SOUND_DROP); + } + + /* XXX XXX XXX */ + + /* Result */ + return (o_idx); +} + + + + +/* + * Scatter some "great" objects near the player + */ +void acquirement(int y1, int x1, int num, bool_ great, bool_ known) +{ + object_type *i_ptr; + object_type object_type_body; + + /* Acquirement */ + while (num--) + { + /* Get local object */ + i_ptr = &object_type_body; + + /* Wipe the object */ + object_wipe(i_ptr); + + /* Make a good (or great) object (if possible) */ + if (!make_object(i_ptr, TRUE, great, d_info[dungeon_type].objs)) continue; + + if (known) + { + object_aware(i_ptr); + object_known(i_ptr); + } + + /* Drop the object */ + drop_near(i_ptr, -1, y1, x1); + } +} + + + +/* + * Hack -- instantiate a trap + * + * XXX XXX XXX This routine should be redone to reflect trap "level". + * That is, it does not make sense to have spiked pits at 50 feet. + * Actually, it is not this routine, but the "trap instantiation" + * code, which should also check for "trap doors" on quest levels. + */ +void pick_trap(int y, int x) +{ + cave_type *c_ptr = &cave[y][x]; + + /* Paranoia */ + if ((c_ptr->t_idx == 0) || (c_ptr->info & CAVE_TRDT)) return; + + /* Activate the trap */ + c_ptr->info |= (CAVE_TRDT); + + /* Notice and redraw */ + note_spot(y, x); + lite_spot(y, x); +} + +/* + * Describe the charges on an item in the inventory. + */ +void inven_item_charges(int item) +{ + object_type *o_ptr = &p_ptr->inventory[item]; + + /* Require staff/wand */ + if ((o_ptr->tval != TV_STAFF) && (o_ptr->tval != TV_WAND)) return; + + /* Require known item */ + if (!object_known_p(o_ptr)) return; + + /* Multiple charges */ + if (o_ptr->pval != 1) + { + /* Print a message */ + msg_format("You have %d charges remaining.", o_ptr->pval); + } + + /* Single charge */ + else + { + /* Print a message */ + msg_format("You have %d charge remaining.", o_ptr->pval); + } +} + + +/* + * Describe an item in the inventory. + */ +void inven_item_describe(int item) +{ + object_type *o_ptr = &p_ptr->inventory[item]; + char o_name[80]; + + /* Get a description */ + object_desc(o_name, o_ptr, TRUE, 3); + + /* Print a message */ + msg_format("You have %s.", o_name); +} + + +/* + * Increase the "number" of an item in the inventory + */ +void inven_item_increase(int item, int num) +{ + object_type *o_ptr = &p_ptr->inventory[item]; + + /* Apply */ + num += o_ptr->number; + + /* Bounds check */ + if (num > 255) num = 255; + else if (num < 0) num = 0; + + /* Un-apply */ + num -= o_ptr->number; + + /* Change the number and weight */ + if (num) + { + /* Add the number */ + o_ptr->number += num; + + /* Recalculate bonuses */ + p_ptr->update |= (PU_BONUS); + + /* Recalculate mana XXX */ + p_ptr->update |= (PU_MANA); + + /* Combine the pack */ + p_ptr->notice |= (PN_COMBINE); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN | PW_EQUIP); + } +} + + +/* + * Erase an inventory slot if it has no more items + */ +bool_ inven_item_optimize(int item) +{ + object_type *o_ptr = &p_ptr->inventory[item]; + + /* Only optimize real items */ + if (!o_ptr->k_idx) return (FALSE); + + /* Only optimize empty items */ + if (o_ptr->number) return (FALSE); + + /* The item is in the pack */ + if (item < INVEN_WIELD) + { + int i; + + /* One less item */ + inven_cnt--; + + /* Slide everything down */ + for (i = item; i < INVEN_PACK; i++) + { + /* Structure copy */ + p_ptr->inventory[i] = p_ptr->inventory[i + 1]; + } + + /* Erase the "final" slot */ + object_wipe(&p_ptr->inventory[i]); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN); + } + + /* The item is being wielded */ + else + { + /* One less item */ + equip_cnt--; + + /* Take care of item sets*/ + if (o_ptr->name1) + { + takeoff_set(p_ptr->inventory[item].name1, a_info[p_ptr->inventory[item].name1].set); + } + + /* Erase the empty slot */ + object_wipe(&p_ptr->inventory[item]); + + /* Recalculate bonuses */ + p_ptr->update |= (PU_BONUS); + + /* Recalculate torch */ + p_ptr->update |= (PU_TORCH); + + /* Recalculate mana XXX */ + p_ptr->update |= (PU_MANA); + + /* Window stuff */ + p_ptr->window |= (PW_EQUIP); + } + + return (TRUE); +} + + +/* + * Describe the charges on an item on the floor. + */ +void floor_item_charges(int item) +{ + object_type *o_ptr = &o_list[item]; + + /* Require staff/wand */ + if ((o_ptr->tval != TV_STAFF) && (o_ptr->tval != TV_WAND)) return; + + /* Require known item */ + if (!object_known_p(o_ptr)) return; + + /* Multiple charges */ + if (o_ptr->pval != 1) + { + /* Print a message */ + msg_format("There are %d charges remaining.", o_ptr->pval); + } + + /* Single charge */ + else + { + /* Print a message */ + msg_format("There is %d charge remaining.", o_ptr->pval); + } +} + + + +/* + * Describe an item in the inventory. + */ +void floor_item_describe(int item) +{ + object_type *o_ptr = &o_list[item]; + char o_name[80]; + + /* Get a description */ + object_desc(o_name, o_ptr, TRUE, 3); + + /* Print a message */ + msg_format("You see %s.", o_name); +} + + +/* + * Increase the "number" of an item on the floor + */ +void floor_item_increase(int item, int num) +{ + object_type *o_ptr = &o_list[item]; + + /* Apply */ + num += o_ptr->number; + + /* Bounds check */ + if (num > 255) num = 255; + else if (num < 0) num = 0; + + /* Un-apply */ + num -= o_ptr->number; + + /* Change the number */ + o_ptr->number += num; +} + + +/* + * Optimize an item on the floor (destroy "empty" items) + */ +void floor_item_optimize(int item) +{ + object_type *o_ptr = &o_list[item]; + + /* Paranoia -- be sure it exists */ + if (!o_ptr->k_idx) return; + + /* Only optimize empty items */ + if (o_ptr->number) return; + + /* Delete the object */ + delete_object_idx(item); +} + + +/* + * Increase stack size for item, describe and optimize. + */ +void inc_stack_size(int item, int delta) { + inc_stack_size_ex(item, delta, OPTIMIZE, DESCRIBE); +} + +/* + * Increase stack size for item. + */ +void inc_stack_size_ex(int item, int delta, optimize_flag opt, describe_flag desc) { + /* Pack item? */ + if (item >= 0) + { + inven_item_increase(item, delta); + if (desc == DESCRIBE) + { + inven_item_describe(item); + } + if (opt == OPTIMIZE) + { + inven_item_optimize(item); + } + } + + /* Floor item? */ + else + { + floor_item_increase(0 - item, delta); + if (desc == DESCRIBE) + { + floor_item_describe(0 - item); + } + if (opt == OPTIMIZE) + { + floor_item_optimize(0 - item); + } + } +} + + + +/* + * Check if we have space for an item in the pack without overflow + */ +bool_ inven_carry_okay(object_type *o_ptr) +{ + int j; + + if (o_ptr->tval == TV_GOLD) return FALSE; + + /* Empty slot? */ + if (inven_cnt < INVEN_PACK) return (TRUE); + + /* Similar slot? */ + for (j = 0; j < INVEN_PACK; j++) + { + object_type *j_ptr = &p_ptr->inventory[j]; + + /* Skip non-objects */ + if (!j_ptr->k_idx) continue; + + /* Check if the two items can be combined */ + if (object_similar(j_ptr, o_ptr)) return (TRUE); + } + + /* Nope */ + return (FALSE); +} + + +/* + * Add an item to the players inventory, and return the slot used. + * + * If the new item can combine with an existing item in the inventory, + * it will do so, using "object_similar()" and "object_absorb()", otherwise, + * the item will be placed into the "proper" location in the inventory. + * + * This function can be used to "over-fill" the player's pack, but only + * once, and such an action must trigger the "overflow" code immediately. + * Note that when the pack is being "over-filled", the new item must be + * placed into the "overflow" slot, and the "overflow" must take place + * before the pack is reordered, but (optionally) after the pack is + * combined. This may be tricky. See "dungeon.c" for info. + * + * Note that this code must remove any location/stack information + * from the object once it is placed into the inventory. + * + * The "final" flag tells this function to bypass the "combine" + * and "reorder" code until later. + */ +s16b inven_carry(object_type *o_ptr, bool_ final) +{ + int i, j, k; + int n = -1; + object_type *j_ptr; + + /* Not final */ + if (!final) + { + /* Check for combining */ + for (j = 0; j < INVEN_PACK; j++) + { + j_ptr = &p_ptr->inventory[j]; + + /* Skip non-objects */ + if (!j_ptr->k_idx) continue; + + /* Hack -- track last item */ + n = j; + + /* Check if the two items can be combined */ + if (object_similar(j_ptr, o_ptr)) + { + /* Combine the items */ + object_absorb(j_ptr, o_ptr); + + /* Recalculate bonuses */ + p_ptr->update |= (PU_BONUS); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN); + + /* Success */ + return (j); + } + } + } + + + /* Paranoia */ + if (inven_cnt > INVEN_PACK) return ( -1); + + + /* Find an empty slot */ + for (j = 0; j <= INVEN_PACK; j++) + { + j_ptr = &p_ptr->inventory[j]; + + /* Use it if found */ + if (!j_ptr->k_idx) break; + } + + /* Use that slot */ + i = j; + + + /* Hack -- pre-reorder the pack */ + if (!final && (i < INVEN_PACK)) + { + s32b o_value, j_value; + + /* Get the "value" of the item */ + o_value = object_value(o_ptr); + + /* Scan every occupied slot */ + for (j = 0; j < INVEN_PACK; j++) + { + j_ptr = &p_ptr->inventory[j]; + + /* Use empty slots */ + if (!j_ptr->k_idx) break; + + /* Objects sort by decreasing type */ + if (o_ptr->tval > j_ptr->tval) break; + if (o_ptr->tval < j_ptr->tval) continue; + + /* Non-aware (flavored) items always come last */ + if (!object_aware_p(o_ptr)) continue; + if (!object_aware_p(j_ptr)) break; + + /* Objects sort by increasing sval */ + if (o_ptr->sval < j_ptr->sval) break; + if (o_ptr->sval > j_ptr->sval) continue; + + /* Unidentified objects always come last */ + if (!object_known_p(o_ptr)) continue; + if (!object_known_p(j_ptr)) break; + + /* Hack: otherwise identical rods sort by + increasing recharge time --dsb */ + if (o_ptr->tval == TV_ROD_MAIN) + { + if (o_ptr->timeout > j_ptr->timeout) break; + if (o_ptr->timeout < j_ptr->timeout) continue; + } + + /* Determine the "value" of the pack item */ + j_value = object_value(j_ptr); + + /* Objects sort by decreasing value */ + if (o_value > j_value) break; + if (o_value < j_value) continue; + } + + /* Use that slot */ + i = j; + + /* Slide objects */ + for (k = n; k >= i; k--) + { + /* Hack -- Slide the item */ + object_copy(&p_ptr->inventory[k + 1], &p_ptr->inventory[k]); + } + + /* Wipe the empty slot */ + object_wipe(&p_ptr->inventory[i]); + } + + + /* Acquire a copy of the item */ + object_copy(&p_ptr->inventory[i], o_ptr); + + /* Access new object */ + o_ptr = &p_ptr->inventory[i]; + + /* Clean out unused fields */ + o_ptr->iy = o_ptr->ix = 0; + o_ptr->next_o_idx = 0; + o_ptr->held_m_idx = 0; + + /* Count the items */ + inven_cnt++; + + /* Recalculate bonuses */ + p_ptr->update |= (PU_BONUS); + + /* Combine and Reorder pack */ + p_ptr->notice |= (PN_COMBINE | PN_REORDER); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN); + + /* Return the slot */ + return (i); +} + + + +/* + * Take off (some of) a non-cursed equipment item + * + * Note that only one item at a time can be wielded per slot. + * + * Note that taking off an item when "full" may cause that item + * to fall to the ground. + * + * Return the inventory slot into which the item is placed. + */ +s16b inven_takeoff(int item, int amt, bool_ force_drop) +{ + int slot; + + object_type forge; + object_type *q_ptr; + + object_type *o_ptr; + + cptr act; + + char o_name[80]; + + + /* Get the item to take off */ + o_ptr = &p_ptr->inventory[item]; + + /* Paranoia */ + if (amt <= 0) return ( -1); + + /* Verify */ + if (amt > o_ptr->number) amt = o_ptr->number; + + /* Get local object */ + q_ptr = &forge; + + /* Obtain a local object */ + object_copy(q_ptr, o_ptr); + + /* Modify quantity */ + q_ptr->number = amt; + + /* Describe the object */ + object_desc(o_name, q_ptr, TRUE, 3); + + /* Took off weapon */ + if (item == INVEN_WIELD) + { + act = "You were wielding"; + } + + /* Took off bow */ + else if (item == INVEN_BOW) + { + act = "You were holding"; + } + + /* Took off light */ + else if (item == INVEN_LITE) + { + act = "You were holding"; + } + + /* Took off ammo */ + else if (item == INVEN_AMMO) + { + act = "You were carrying in your quiver"; + } + + /* Took off tool */ + else if (item == INVEN_TOOL) + { + act = "You were using"; + } + + /* Took off something */ + else + { + act = "You were wearing"; + } + + /* Modify, Optimize */ + inc_stack_size_ex(item, -amt, OPTIMIZE, NO_DESCRIBE); + + if ((item == INVEN_CARRY) && (get_skill(SKILL_SYMBIOTIC))) + { + /* Drop the monster */ + o_ptr->pval2 = 0; + msg_print("You carefully drop the poor monster on the floor."); + drop_near(q_ptr, 0, p_ptr->py, p_ptr->px); + slot = -1; + } + else if (force_drop) + { + drop_near(q_ptr, 0, p_ptr->py, p_ptr->px); + slot = -1; + } + else + { + /* Carry the object */ + slot = inven_carry(q_ptr, FALSE); + } + + /* Message */ + msg_format("%s %s (%c).", act, o_name, index_to_label(slot)); + + /* Return slot */ + return (slot); +} + + + + +/* + * Drop (some of) a non-cursed inventory/equipment item + * + * The object will be dropped "near" the current location + */ +void inven_drop(int item, int amt, int dy, int dx, bool_ silent) +{ + object_type forge; + object_type *q_ptr; + + object_type *o_ptr; + + char o_name[80]; + + + /* Access original object */ + o_ptr = &p_ptr->inventory[item]; + + /* Error check */ + if (amt <= 0) return; + + /* Not too many */ + if (amt > o_ptr->number) amt = o_ptr->number; + + + /* Take off equipment */ + if (item >= INVEN_WIELD) + { + /* Take off first */ + item = inven_takeoff(item, amt, FALSE); + + /* Access original object */ + o_ptr = &p_ptr->inventory[item]; + } + + if (item > -1) + { + /* Get local object */ + q_ptr = &forge; + + /* Obtain local object */ + object_copy(q_ptr, o_ptr); + + /* + * Hack -- If rods or wands are dropped, the total maximum timeout or + * charges need to be allocated between the two stacks. If all the items + * are being dropped, it makes for a neater message to leave the original + * stack's pval alone. -LM- + */ + if (o_ptr->tval == TV_WAND) + { + if (o_ptr->tval == TV_WAND) + { + q_ptr->pval = o_ptr->pval * amt / o_ptr->number; + if (amt < o_ptr->number) o_ptr->pval -= q_ptr->pval; + } + } + + /* Modify quantity */ + q_ptr->number = amt; + + /* Describe local object */ + object_desc(o_name, q_ptr, TRUE, 3); + + /* Message */ + if (!silent) msg_format("You drop %s (%c).", o_name, index_to_label(item)); + + /* Drop it near the player */ + drop_near(q_ptr, 0, dy, dx); + + /* Modify, Describe, Optimize */ + inc_stack_size(item, -amt); + } +} + + + +/* + * Combine items in the pack + * + * Note special handling of the "overflow" slot + */ +void combine_pack(void) +{ + int i, j, k; + object_type *o_ptr; + object_type *j_ptr; + bool_ flag = FALSE; + + + /* Combine the pack (backwards) */ + for (i = INVEN_PACK; i > 0; i--) + { + /* Get the item */ + o_ptr = &p_ptr->inventory[i]; + + /* Skip empty items */ + if (!o_ptr->k_idx) continue; + + /* Scan the items above that item */ + for (j = 0; j < i; j++) + { + /* Get the item */ + j_ptr = &p_ptr->inventory[j]; + + /* Skip empty items */ + if (!j_ptr->k_idx) continue; + + /* Can we drop "o_ptr" onto "j_ptr"? */ + if (object_similar(j_ptr, o_ptr)) + { + /* Take note */ + flag = TRUE; + + /* Add together the item counts */ + object_absorb(j_ptr, o_ptr); + + /* One object is gone */ + inven_cnt--; + + /* Slide everything down */ + for (k = i; k < INVEN_PACK; k++) + { + /* Structure copy */ + p_ptr->inventory[k] = p_ptr->inventory[k + 1]; + } + + /* Erase the "final" slot */ + object_wipe(&p_ptr->inventory[k]); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN); + + /* Done */ + break; + } + } + } + + /* Message */ + if (flag) msg_print("You combine some items in your pack."); +} + + +/* + * Reorder items in the pack + * + * Note special handling of the "overflow" slot + */ +void reorder_pack(void) +{ + int i, j, k; + s32b o_value; + s32b j_value; + object_type forge; + object_type *q_ptr; + object_type *j_ptr; + object_type *o_ptr; + bool_ flag = FALSE; + + + /* Re-order the pack (forwards) */ + for (i = 0; i < INVEN_PACK; i++) + { + /* Mega-Hack -- allow "proper" over-flow */ + if ((i == INVEN_PACK) && (inven_cnt == INVEN_PACK)) break; + + /* Get the item */ + o_ptr = &p_ptr->inventory[i]; + + /* Skip empty slots */ + if (!o_ptr->k_idx) continue; + + /* Get the "value" of the item */ + o_value = object_value(o_ptr); + + /* Scan every occupied slot */ + for (j = 0; j < INVEN_PACK; j++) + { + /* Get the item already there */ + j_ptr = &p_ptr->inventory[j]; + + /* Use empty slots */ + if (!j_ptr->k_idx) break; + + /* Objects sort by decreasing type */ + if (o_ptr->tval > j_ptr->tval) break; + if (o_ptr->tval < j_ptr->tval) continue; + + /* Non-aware (flavored) items always come last */ + if (!object_aware_p(o_ptr)) continue; + if (!object_aware_p(j_ptr)) break; + + /* Objects sort by increasing sval */ + if (o_ptr->sval < j_ptr->sval) break; + if (o_ptr->sval > j_ptr->sval) continue; + + /* Unidentified objects always come last */ + if (!object_known_p(o_ptr)) continue; + if (!object_known_p(j_ptr)) break; + + + /* Hack: otherwise identical rods sort by + increasing recharge time --dsb */ + if (o_ptr->tval == TV_ROD_MAIN) + { + if (o_ptr->timeout > j_ptr->timeout) break; + if (o_ptr->timeout < j_ptr->timeout) continue; + } + + /* Determine the "value" of the pack item */ + j_value = object_value(j_ptr); + + + + /* Objects sort by decreasing value */ + if (o_value > j_value) break; + if (o_value < j_value) continue; + } + + /* Never move down */ + if (j >= i) continue; + + /* Take note */ + flag = TRUE; + + /* Get local object */ + q_ptr = &forge; + + /* Save a copy of the moving item */ + object_copy(q_ptr, &p_ptr->inventory[i]); + + /* Slide the objects */ + for (k = i; k > j; k--) + { + /* Slide the item */ + object_copy(&p_ptr->inventory[k], &p_ptr->inventory[k - 1]); + } + + /* Insert the moving item */ + object_copy(&p_ptr->inventory[j], q_ptr); + + /* Window stuff */ + p_ptr->window |= (PW_INVEN); + } + + /* Message */ + if (flag) msg_print("You reorder some items in your pack."); +} + +/* + * Hack -- display an object kind in the current window + * + * Include list of usable spells for readible books + */ +void display_koff(int k_idx) +{ + int y; + + object_type forge; + object_type *q_ptr; + + char o_name[80]; + + + /* Erase the window */ + for (y = 0; y < Term->hgt; y++) + { + /* Erase the line */ + Term_erase(0, y, 255); + } + + /* No info */ + if (!k_idx) return; + + + /* Get local object */ + q_ptr = &forge; + + /* Prepare the object */ + object_wipe(q_ptr); + + /* Prepare the object */ + object_prep(q_ptr, k_idx); + + + /* Describe */ + object_desc_store(o_name, q_ptr, FALSE, 0); + + /* Mention the object name */ + Term_putstr(0, 0, -1, TERM_WHITE, o_name); +} + + +/* + * Let the floor carry an object + */ +s16b floor_carry(int y, int x, object_type *j_ptr) +{ + int n = 0; + + s16b o_idx; + + s16b this_o_idx, next_o_idx = 0; + + + /* Scan objects in that grid for combination */ + for (this_o_idx = cave[y][x].o_idx; this_o_idx; this_o_idx = next_o_idx) + { + object_type * o_ptr; + + /* Acquire object */ + o_ptr = &o_list[this_o_idx]; + + /* Acquire next object */ + next_o_idx = o_ptr->next_o_idx; + + /* Check for combination */ + if (object_similar(o_ptr, j_ptr)) + { + /* Combine the items */ + object_absorb(o_ptr, j_ptr); + + /* Result */ + return (this_o_idx); + } + + /* Count objects */ + n++; + } + + /* The stack is already too large */ + if (n > 23) return (0); + + /* Make an object */ + o_idx = o_pop(); + + /* Success */ + if (o_idx) + { + object_type *o_ptr; + + /* Acquire object */ + o_ptr = &o_list[o_idx]; + + /* Structure Copy */ + object_copy(o_ptr, j_ptr); + + /* Location */ + o_ptr->iy = y; + o_ptr->ix = x; + + /* Forget monster */ + o_ptr->held_m_idx = 0; + + /* Build a stack */ + o_ptr->next_o_idx = cave[y][x].o_idx; + + /* Place the object */ + cave[y][x].o_idx = o_idx; + + /* Notice */ + note_spot(y, x); + + /* Redraw */ + lite_spot(y, x); + } + + /* Result */ + return (o_idx); +} + +/* + * Notice a decaying object in the pack + */ +void pack_decay(int item) +{ + object_type *o_ptr = &p_ptr->inventory[item]; + + monster_race *r_ptr = &r_info[o_ptr->pval2]; + + object_type *i_ptr; + object_type object_type_body; + + int amt = o_ptr->number; + + s16b m_type; + s32b wt; + + byte known = o_ptr->name1; + + byte gone = 1; + + char desc[80]; + + /* Player notices each decaying object */ + object_desc(desc, o_ptr, TRUE, 3); + msg_format("You feel %s decompose.", desc); + + /* Get local object */ + i_ptr = &object_type_body; + + /* Obtain local object */ + object_copy(i_ptr, o_ptr); + + /* Remember what creature we were */ + m_type = o_ptr->pval2; + + /* and how much we weighed */ + wt = r_ptr->weight; + + /* Get rid of decayed object */ + inc_stack_size_ex(item, -amt, OPTIMIZE, NO_DESCRIBE); + + if (i_ptr->tval == TV_CORPSE) + { + /* Monster must have a skull for its head to become one */ + if (i_ptr->sval == SV_CORPSE_HEAD) + { + /* Replace the head with a skull */ + object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_SKULL)); + i_ptr->weight = wt / 60 + rand_int(wt) / 600; + + /* Stay here */ + gone = 0; + } + + /* Monster must have a skeleton for its corpse to become one */ + if ((i_ptr->sval == SV_CORPSE_CORPSE) && (r_ptr->flags3 & RF9_DROP_SKELETON)) + { + /* Replace the corpse with a skeleton */ + object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_SKELETON)); + i_ptr->weight = wt / 4 + rand_int(wt) / 40; + + /* Stay here */ + gone = 0; + } + + /* Don't restore if the item is gone */ + if (!gone) + { + i_ptr->number = amt; + i_ptr->pval2 = m_type; + + /* Should become "The skull of Farmer Maggot", not "A skull" */ + if (known) + { + object_aware(i_ptr); + + /* Named skeletons are artifacts */ + i_ptr->name1 = 201; + } + inven_carry(i_ptr, TRUE); + } + } +} + +/* + * Decay an object on the floor + */ +void floor_decay(int item) +{ + object_type *o_ptr = &o_list[item]; + + monster_race *r_ptr = &r_info[o_ptr->pval2]; + + object_type *i_ptr; + object_type object_type_body; + + int amt = o_ptr->number; + + s16b m_type; + s32b wt; + + byte known = o_ptr->name1; + + /* Assume we disappear */ + byte gone = 1; + + byte x = o_ptr->ix; + byte y = o_ptr->iy; + + /* Maybe the player sees it */ + bool_ visible = player_can_see_bold(o_ptr->iy, o_ptr->ix); + char desc[80]; + + if (visible) + { + /* Player notices each decaying object */ + object_desc(desc, o_ptr, TRUE, 3); + msg_format("You see %s decompose.", desc); + } + + + /* Get local object */ + i_ptr = &object_type_body; + + /* Obtain local object */ + object_copy(i_ptr, o_ptr); + + /* Remember what creature we were */ + m_type = o_ptr->pval2; + + /* and how much we weighed */ + wt = r_ptr->weight; + + floor_item_increase(item, -amt); + floor_item_optimize(item); + + if (i_ptr->tval == TV_CORPSE) + { + /* Monster must have a skull for its head to become one */ + if (i_ptr->sval == SV_CORPSE_HEAD) + { + /* Replace the head with a skull */ + object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_SKULL)); + i_ptr->weight = wt / 60 + rand_int(wt) / 600; + + /* Stay here */ + gone = 0; + } + + /* Monster must have a skeleton for its corpse to become one */ + if ((i_ptr->sval == SV_CORPSE_CORPSE) && (r_ptr->flags3 & RF9_DROP_SKELETON)) + { + /* Replace the corpse with a skeleton */ + object_prep(i_ptr, lookup_kind(TV_CORPSE, SV_CORPSE_SKELETON)); + i_ptr->weight = wt / 4 + rand_int(wt) / 40; + + /* Stay here */ + gone = 0; + } + + /* Don't restore if the item is gone */ + if (!gone) + { + i_ptr->number = amt; + i_ptr->pval2 = m_type; + + /* Should become "The skull of Farmer Maggot", not "A skull" */ + if (known) + { + object_aware(i_ptr); + + /* Named skeletons are artifacts */ + i_ptr->name1 = 201; + } + floor_carry(y, x, i_ptr); + } + } +} + +/* Return the item be it on the floor or in inven */ +object_type *get_object(int item) +{ + /* Get the item (in the pack) */ + if (item >= 0) + { + return &p_ptr->inventory[item]; + } + + /* Get the item (on the floor) */ + else + { + return &o_list[0 - item]; + } +} + -- cgit v1.2.3