static void describe_flavor_text(textblock * tb, const object_type * o_ptr) { /* Display the known artifact description */ if (o_ptr->name1 && object_known_p(o_ptr) && a_info[o_ptr->name1].text) { textblock_append(tb, "%s\n\n", a_info[o_ptr->name1].text); } /* Display the known object description */ else if (object_aware_p(o_ptr) || object_known_p(o_ptr)) { bool did_desc = FALSE; if (k_info[o_ptr->k_idx].text) { textblock_append(tb, "%s", k_info[o_ptr->k_idx].text); did_desc = TRUE; } /* Display an additional ego-item description */ if (has_ego_properties(o_ptr) && e_info[o_ptr->name2].text) { if (did_desc) textblock_append(tb, " "); textblock_append(tb, "%s\n\n", e_info[o_ptr->name2].text); } else if (did_desc) { textblock_append(tb, "\n\n"); } } }
/** * Put the autoinscription on an object */ int apply_autoinscription(object_type * o_ptr) { char o_name[80]; const char *note = get_autoinscription(o_ptr->k_idx); const char *existing_inscription = quark_str(o_ptr->note); /* Don't inscribe unaware objects */ if (!note || !object_aware_p(o_ptr)) return 0; /* Don't re-inscribe if it's already correctly inscribed */ if (existing_inscription && streq(note, existing_inscription)) return 0; /* Get an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); if (note[0] != 0) o_ptr->note = quark_add(note); else o_ptr->note = 0; msg("You autoinscribe %s.", o_name); return 1; }
/* * Header for additional information when printing to screen. * * Header for additional information when printing to screen. */ static bool screen_out_head(const object_type *o_ptr) { char *o_name; int name_size = Term->wid; bool has_description = FALSE; /* Allocate memory to the size of the screen */ o_name = C_RNEW(name_size, char); /* Description */ object_desc(o_name, name_size, o_ptr, TRUE, 3); /* Print, in colour */ text_out_c(TERM_YELLOW, format("%^s", o_name)); /* Free up the memory */ FREE(o_name); /* Display the known artefact description */ if (!adult_rand_artefacts && o_ptr->name1 && object_known_p(o_ptr) && a_info[o_ptr->name1].text) { p_text_out("\n\n "); p_text_out(a_text + a_info[o_ptr->name1].text); has_description = TRUE; } /* Display the known object description */ else if (object_aware_p(o_ptr) || object_known_p(o_ptr)) { if (k_info[o_ptr->k_idx].text) { p_text_out("\n\n "); p_text_out(k_text + k_info[o_ptr->k_idx].text); has_description = TRUE; } /* Display an additional special item description */ if (o_ptr->name2 && object_known_p(o_ptr) && e_info[o_ptr->name2].text) { p_text_out("\n\n "); p_text_out(e_text + e_info[o_ptr->name2].text); has_description = TRUE; } } return (has_description); }
static size_t obj_desc_charges(const object_type * o_ptr, char *buf, size_t max, size_t end) { object_kind *k_ptr = &k_info[o_ptr->k_idx]; bool aware = object_aware_p(o_ptr); /* Wands and Staffs have charges */ if (aware && (o_ptr->tval == TV_STAFF || o_ptr->tval == TV_WAND)) strnfcat(buf, max, &end, " (%d charge%s)", o_ptr->pval, PLURAL(o_ptr->pval)); /* Charging things */ else if (o_ptr->timeout > 0) { if (o_ptr->tval == TV_ROD && o_ptr->number > 1) { int power; int time_base = randcalc(k_ptr->time, 0, MINIMISE); if (!time_base) time_base = 1; /* * Find out how many rods are charging, by dividing * current timeout by each rod's maximum timeout. * Ensure that any remainder is rounded up. Display * very discharged stacks as merely fully discharged. */ power = (o_ptr->timeout + (time_base - 1)) / time_base; if (power > o_ptr->number) power = o_ptr->number; /* Display prettily */ strnfcat(buf, max, &end, " (%d charging)", power); } /* Artifacts, single rods */ else if (!(o_ptr->tval == TV_LIGHT && !artifact_p(o_ptr))) { strnfcat(buf, max, &end, " (charging)"); } } return end; }
static size_t obj_desc_inscrip(const object_type * o_ptr, char *buf, size_t max, size_t end) { const char *u[4] = { 0, 0, 0, 0 }; int n = 0; /* Get inscription */ if (o_ptr->note) u[n++] = quark_str(o_ptr->note); /* Use special inscription, if any */ if (o_ptr->feel) { u[n++] = feel_text[o_ptr->feel]; } else if ((o_ptr->ident & IDENT_EMPTY) && !object_known_p(o_ptr)) u[n++] = "empty"; else if (!object_aware_p(o_ptr) && object_tried_p(o_ptr)) u[n++] = "tried"; /* Use the discount, if any. No annoying inscription for homemade * branded items. */ if ((o_ptr->discount > 0) && (o_ptr->discount != 80)) u[n++] = format("%d%% off", o_ptr->discount); /* Note squelch */ if (squelch_item_ok(o_ptr)) u[n++] = "squelch"; if (n) { int i; for (i = 0; i < n; i++) { if (i == 0) strnfcat(buf, max, &end, " {"); strnfcat(buf, max, &end, "%s", u[i]); if (i < n - 1) strnfcat(buf, max, &end, ", "); } strnfcat(buf, max, &end, "}"); } return end; }
/* * Describe an object's effect, if any. */ static bool describe_effect(textblock * tb, const object_type * o_ptr, oinfo_detail_t mode) { const object_kind *k_ptr = &k_info[o_ptr->k_idx]; const char *desc; random_value timeout = { 0, 0, 0, 0 }; bool full = mode & OINFO_FULL; bool subjective = mode & OINFO_SUBJ; bool terse = mode & OINFO_TERSE; int effect = 0, fail; if (wearable_p(o_ptr)) { /* Wearable + effect <=> activates */ if ((o_ptr->ident & IDENT_WORN) || full) { effect = o_ptr->effect; timeout = o_ptr->time; } else if (object_effect(o_ptr)) { textblock_append(tb, "It can be activated.\n"); return TRUE; } } else { /* Sometimes only print activation info */ if (terse) return FALSE; if ((object_aware_p(o_ptr) && kf_has(k_ptr->flags_kind, KF_EASY_KNOW)) || full) { effect = o_ptr->effect; timeout = o_ptr->time; } else if (object_effect(o_ptr)) { if (effect_aim(k_ptr->effect)) textblock_append(tb, "It can be aimed.\n"); else if (o_ptr->tval == TV_FOOD) textblock_append(tb, "It can be eaten.\n"); else if (o_ptr->tval == TV_POTION) textblock_append(tb, "It can be drunk.\n"); else if (o_ptr->tval == TV_SCROLL) textblock_append(tb, "It can be read.\n"); else textblock_append(tb, "It can be activated.\n"); return TRUE; } } /* Forget it without an effect */ if (!effect) return FALSE; /* Obtain the description */ desc = effect_desc(effect); if (!desc) return FALSE; if (effect_aim(effect)) textblock_append(tb, "When aimed, it "); else if (o_ptr->tval == TV_FOOD) textblock_append(tb, "When eaten, it "); else if (o_ptr->tval == TV_POTION) textblock_append(tb, "When drunk, it "); else if (o_ptr->tval == TV_SCROLL) textblock_append(tb, "When read, it "); else textblock_append(tb, "When activated, it "); /* Print a colourised description */ do { if (isdigit((unsigned char) *desc)) textblock_append_c(tb, TERM_L_GREEN, "%c", *desc); else textblock_append(tb, "%c", *desc); } while (*desc++); textblock_append(tb, ".\n"); if (randcalc(timeout, 0, MAXIMISE) > 0) { int min_time, max_time; /* Sometimes adjust for player speed */ int multiplier = extract_energy[p_ptr->state.pspeed]; if (!subjective) multiplier = 10; textblock_append(tb, "Takes "); /* Correct for player speed */ min_time = randcalc(timeout, 0, MINIMISE) * multiplier / 10; max_time = randcalc(timeout, 0, MAXIMISE) * multiplier / 10; textblock_append_c(tb, TERM_L_GREEN, "%d", min_time); if (min_time != max_time) { textblock_append(tb, " to "); textblock_append_c(tb, TERM_L_GREEN, "%d", max_time); } textblock_append(tb, " turns to recharge"); if (subjective && p_ptr->state.pspeed != 110) textblock_append(tb, " at your current speed"); textblock_append(tb, ".\n"); } if (!subjective || o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION || o_ptr->tval == TV_SCROLL) { return TRUE; } else { fail = get_use_device_chance(o_ptr); textblock_append(tb, "Your chance of success is %d.%d%%\n", (1000 - fail) / 10, (1000 - fail) % 10); } return TRUE; }
/* * Activate (zap) a Rod * * Unstack fully charged rods as needed. * * Hack -- rods of perception/banishment can be "cancelled" * All rods can be cancelled at the "Direction?" prompt */ void do_cmd_zap_rod(void) { int item; bool ident; object_type *o_ptr; cptr q, s; /* Restrict choices to rods */ item_tester_tval = TV_ROD; /* Get an item */ q = "Zap which rod? "; s = "You have no rod to zap."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Mega-Hack -- refuse to zap a pile from the ground */ if ((item < 0) && (o_ptr->number > 1)) { msg_print("You must first pick up the rods."); return; } /* Zap the rod */ if (!use_object(o_ptr, &ident)) return; /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* Tried the object */ object_tried(o_ptr); /* Successfully determined the object function */ if (ident && !object_aware_p(o_ptr)) { /* Object level */ int lev = k_info[o_ptr->k_idx].level; object_aware(o_ptr); gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); } /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP); /* XXX Hack -- unstack if necessary */ if ((item >= 0) && (o_ptr->number > 1) && (o_ptr->pval > 0)) { object_type *i_ptr; object_type object_type_body; /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Restore "charge" */ o_ptr->pval = 0; /* Unstack the used item */ o_ptr->number--; p_ptr->total_weight -= i_ptr->weight; item = inven_carry(i_ptr); /* Message */ msg_print("You unstack your rod."); } }
/* * Eat some food (from the pack or floor) */ void do_cmd_eat_food(void) { int item, lev; bool ident; object_type *o_ptr; cptr q, s; /* Restrict choices to food */ item_tester_tval = TV_FOOD; /* Get an item */ q = "Eat which item? "; s = "You have nothing to eat."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Sound */ sound(MSG_EAT); /* Take a turn */ p_ptr->energy_use = 100; /* Identity not known yet */ ident = FALSE; /* Object level */ lev = k_info[o_ptr->k_idx].level; /* Eat the food */ use_object(o_ptr, &ident); /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* We have tried it */ object_tried(o_ptr); /* The player is now aware of the object */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); } /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP); /* Destroy a food in the pack */ if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Destroy a food on the floor */ else { floor_item_increase(0 - item, -1); floor_item_describe(0 - item); floor_item_optimize(0 - item); } }
/* * Creates a description of the item "o_ptr", and stores it in "out_val". * * One can choose the "verbosity" of the description, including whether * or not the "number" of items should be described, and how much detail * should be used when describing the item. * * The given "buf" must be MAX_NLEN chars long to hold the longest possible * description, which can get pretty long, including incriptions, such as: * "no more Maces of Disruption (Defender) (+10,+10) [+5] (+3 to stealth)". * Note that the inscription will be clipped to keep the total description * under MAX_NLEN-1 chars (plus a terminator). * * Note the use of "object_desc_num()" and "object_desc_int()" as hyper-efficient, * portable, versions of some common "sprintf()" commands. * * Note that all ego-items (when known) append an "Ego-Item Name", unless * the item is also an artifact, which should NEVER happen. * * Note that all artifacts (when known) append an "Artifact Name", so we * have special processing for "Specials" (artifact Lites, Rings, Amulets). * The "Specials" never use "modifiers" if they are "known", since they * have special "descriptions", such as "The Necklace of the Dwarves". * * Special Lite's use the "k_info" base-name (Phial, Star, or Arkenstone), * plus the artifact name, just like any other artifact, if known. * * Special Ring's and Amulet's, if not "aware", use the same code as normal * rings and amulets, and if "aware", use the "k_info" base-name (Ring or * Amulet or Necklace). They will NEVER "append" the "k_info" name. But, * they will append the artifact name, just like any artifact, if known. * * Hack -- Display "The One Ring" as "a Plain Gold Ring" until aware. * * Mode: * OD_NAME_ONLY : The Cloak of Death * OD_NAME_AND_ENCHANT : The Cloak of Death [1,+3] * OD_OMIT_INSCRIPTION : The Cloak of Death [1,+3] (+2 to Stealth) * 0 : The Cloak of Death [1,+3] (+2 to Stealth) {nifty} * * OD_OMIT_PREFIX : Forbidden numeric prefix * OD_NO_PLURAL : Forbidden use of plural * OD_STORE : Assume to be aware and known * OD_NO_FLAVOR : Allow to hidden flavor * OD_FORCE_FLAVOR : Get un-shuffled flavor name */ void object_desc(char *buf, const object_type *o_ptr, u32b mode) { /* Extract object kind name */ cptr kindname = get_object_name(o_ptr); /* Extract default "base" string */ cptr basenm = kindname; /* Assume no "modifier" string */ cptr modstr = ""; int power; bool aware = FALSE; bool known = FALSE; bool flavor = TRUE; bool show_weapon = FALSE; bool show_armour = FALSE; cptr s, s0; char *t; char p1 = '(', p2 = ')'; char b1 = '[', b2 = ']'; char c1 = '{', c2 = '}'; char tmp_val[MAX_NLEN+160]; char tmp_val2[MAX_NLEN+10]; char fake_insc_buf[30]; u32b f1, f2, f3; bool fullname = FALSE; object_type *bow_ptr; object_kind *k_ptr = &k_info[o_ptr->k_idx]; object_kind *flavor_k_ptr = &k_info[k_ptr->flavor]; /* Extract some flags */ object_flags(o_ptr, &f1, &f2, &f3); /* See if the object is "aware" */ if (object_aware_p(o_ptr)) aware = TRUE; /* See if the object is "known" */ if (object_known_p(o_ptr)) known = TRUE; /* Allow flavors to be hidden when aware */ if (aware && ((mode & OD_NO_FLAVOR) || plain_descriptions)) flavor = FALSE; /* Object is in the inventory of a store or spoiler */ if ((mode & OD_STORE) || (o_ptr->ident & IDENT_STORE)) { /* Don't show flavors */ flavor = FALSE; /* Pretend known and aware */ aware = TRUE; known = TRUE; } /* Force to be flavor name only */ if (mode & OD_FORCE_FLAVOR) { aware = FALSE; flavor = TRUE; known = FALSE; /* Cancel shuffling */ flavor_k_ptr = k_ptr; } /* Analyze the object */ switch (o_ptr->tval) { /* Some objects are easy to describe */ case TV_SKELETON: case TV_BOTTLE: case TV_JUNK: case TV_SPIKE: case TV_FLASK: case TV_CHEST: case TV_FOOD: { break; } /* Figurines/Statues */ case TV_FIGURINE: case TV_STATUE: { monster_race *r_ptr = &r_info[o_ptr->pval]; #ifdef JP modstr = r_name + r_ptr->name; #else cptr t = r_name + r_ptr->name; if (!(r_ptr->flags1 & RF1_UNIQUE)) { sprintf(tmp_val2, "%s%s", (is_a_vowel(*t) ? "an " : "a "), t); modstr = tmp_val2; } else { modstr = t; } #endif break; } /* Corpses */ case TV_CORPSE: { monster_race *r_ptr = &r_info[o_ptr->pval]; modstr = r_name + r_ptr->name; #ifdef JP basenm = "#%"; #else if (r_ptr->flags1 & RF1_UNIQUE) basenm = "& % of #"; else basenm = "& # %"; #endif break; } /* Missiles/ Bows/ Weapons */ case TV_SHOT: case TV_BOLT: case TV_ARROW: case TV_BOW: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_DIGGING: { show_weapon = TRUE; break; } /* Armour */ 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: { show_armour = TRUE; break; } /* Lites (including a few "Specials") */ case TV_LITE: { break; } /* Amulets (including a few "Specials") */ case TV_AMULET: { /* Known artifacts */ if (aware) { if (artifact_p(o_ptr)) break; if (k_ptr->gen_flags & TRG_INSTA_ART) break; } /* Color the object */ modstr = k_name + flavor_k_ptr->flavor_name; #ifdef JP if (!flavor) basenm = "%のアミュレット"; else if (aware) basenm = "%の#アミュレット"; else basenm = "#アミュレット"; #else if (!flavor) basenm = "& Amulet~ of %"; else if (aware) basenm = "& # Amulet~ of %"; else basenm = "& # Amulet~"; #endif break; } /* Rings (including a few "Specials") */ case TV_RING: { /* Known artifacts */ if (aware) { if (artifact_p(o_ptr)) break; if (k_ptr->gen_flags & TRG_INSTA_ART) break; } /* Color the object */ modstr = k_name + flavor_k_ptr->flavor_name; #ifdef JP if (!flavor) basenm = "%の指輪"; else if (aware) basenm = "%の#指輪"; else basenm = "#指輪"; #else if (!flavor) basenm = "& Ring~ of %"; else if (aware) basenm = "& # Ring~ of %"; else basenm = "& # Ring~"; #endif if (!k_ptr->to_h && !k_ptr->to_d && (o_ptr->to_h || o_ptr->to_d)) show_weapon = TRUE; break; } case TV_STAFF: { /* Color the object */ modstr = k_name + flavor_k_ptr->flavor_name; #ifdef JP if (!flavor) basenm = "%のスタッフ"; else if (aware) basenm = "%の#スタッフ"; else basenm = "#スタッフ"; #else if (!flavor) basenm = "& Staff~ of %"; else if (aware) basenm = "& # Staff~ of %"; else basenm = "& # Staff~"; #endif break; } case TV_WAND: { /* Color the object */ modstr = k_name + flavor_k_ptr->flavor_name; #ifdef JP if (!flavor) basenm = "%のワンド"; else if (aware) basenm = "%の#ワンド"; else basenm = "#ワンド"; #else if (!flavor) basenm = "& Wand~ of %"; else if (aware) basenm = "& # Wand~ of %"; else basenm = "& # Wand~"; #endif break; } case TV_ROD: { /* Color the object */ modstr = k_name + flavor_k_ptr->flavor_name; #ifdef JP if (!flavor) basenm = "%のロッド"; else if (aware) basenm = "%の#ロッド"; else basenm = "#ロッド"; #else if (!flavor) basenm = "& Rod~ of %"; else if (aware) basenm = "& # Rod~ of %"; else basenm = "& # Rod~"; #endif break; } case TV_SCROLL: { /* Color the object */ modstr = k_name + flavor_k_ptr->flavor_name; #ifdef JP if (!flavor) basenm = "%の巻物"; else if (aware) basenm = "\"#\"と書かれた%の巻物"; else basenm = "\"#\"と書かれた巻物"; #else if (!flavor) basenm = "& Scroll~ of %"; else if (aware) basenm = "& Scroll~ titled \"#\" of %"; else basenm = "& Scroll~ titled \"#\""; #endif break; } case TV_POTION: { /* Color the object */ modstr = k_name + flavor_k_ptr->flavor_name; #ifdef JP if (!flavor) basenm = "%の薬"; else if (aware) basenm = "%の#薬"; else basenm = "#薬"; #else if (!flavor) basenm = "& Potion~ of %"; else if (aware) basenm = "& # Potion~ of %"; else basenm = "& # Potion~"; #endif break; } /* Magic Books */ case TV_LIFE_BOOK: { #ifdef JP basenm = "生命の魔法書%"; #else if (mp_ptr->spell_type == ST_PRAYER) basenm = "& Book~ of Life Magic %"; else basenm = "& Life Spellbook~ %"; #endif break; } case TV_SORCERY_BOOK: { #ifdef JP basenm = "仙術の魔法書%"; #else if (mp_ptr->spell_type == ST_PRAYER) basenm = "& Book~ of Sorcery %"; else basenm = "& Sorcery Spellbook~ %"; #endif break; } /* Hack -- Gold/Gems */ case TV_GOLD: { strcpy(buf, basenm); return; } /* Used in the "inventory" routine */ default: { #ifdef JP strcpy(buf, "(なし)"); #else strcpy(buf, "(nothing)"); #endif return; } } /* Use full name from a_info */ if (known && o_ptr->name1) { artifact_type *a_ptr = &a_info[o_ptr->name1]; if (prefix(a_name + a_ptr->name, "$")) { basenm = a_name + a_info[o_ptr->name1].name + 1; fullname = TRUE; } } /* Start dumping the result */ t = tmp_val; #ifdef JP if (basenm[0] == '&') s = basenm + 2; else s = basenm; /* No prefix */ if (mode & OD_OMIT_PREFIX) { /* Nothing */ } else if (o_ptr->number > 1) { t = object_desc_kosuu(t, o_ptr); t = object_desc_str(t, "の "); } /* 英語の場合アーティファクトは The が付くので分かるが * 日本語では分からないのでマークをつける */ if (known) { if (artifact_p(o_ptr)) t = object_desc_str(t, "★"); else if (o_ptr->art_name) t = object_desc_str(t, "☆"); } #else /* The object "expects" a "number" */ if (basenm[0] == '&') { /* Skip the ampersand (and space) */ s = basenm + 2; /* No prefix */ if (mode & OD_OMIT_PREFIX) { /* Nothing */ } /* Hack -- None left */ else if (o_ptr->number <= 0) { t = object_desc_str(t, "no more "); } /* Extract the number */ else if (o_ptr->number > 1) { t = object_desc_num(t, o_ptr->number); t = object_desc_chr(t, ' '); } /* Hack -- The only one of its kind */ else if ((known && (artifact_p(o_ptr) || o_ptr->art_name)) || ((o_ptr->tval == TV_CORPSE) && (r_info[o_ptr->pval].flags1 & RF1_UNIQUE))) { t = object_desc_str(t, "The "); } /* A single one */ else { bool vowel; switch (*s) { case '#': vowel = is_a_vowel(modstr[0]); break; case '%': vowel = is_a_vowel(*kindname); break; default: vowel = is_a_vowel(*s); break; } if (vowel) { /* A single one, with a vowel */ t = object_desc_str(t, "an "); } else { /* A single one, without a vowel */ t = object_desc_str(t, "a "); } } } /* Hack -- objects that "never" take an article */ else { /* No ampersand */ s = basenm; /* No pref */ if (mode & OD_OMIT_PREFIX) { /* Nothing */ } /* Hack -- all gone */ else if (o_ptr->number <= 0) { t = object_desc_str(t, "no more "); } /* Prefix a number if required */ else if (o_ptr->number > 1) { t = object_desc_num(t, o_ptr->number); t = object_desc_chr(t, ' '); } /* Hack -- The only one of its kind */ else if (known && (artifact_p(o_ptr) || o_ptr->art_name)) { t = object_desc_str(t, "The "); } /* Hack -- single items get no prefix */ else { /* Nothing */ } } #endif /* Paranoia -- skip illegal tildes */ /* while (*s == '~') s++; */ #ifdef JP /* 伝説のアイテム、名のあるアイテムの名前を付加する */ if (known) { /* ランダム・アーティファクト */ if (o_ptr->art_name) { cptr temp = quark_str(o_ptr->art_name); /* '『' から始まらない伝説のアイテムの名前は最初に付加する */ /* 英語版のセーブファイルから来た 'of XXX' は,「XXXの」と表示する */ if (strncmp(temp, "of ", 3) == 0) { t = object_desc_str(t, &temp[3]); t = object_desc_str(t, "の"); } else if ((strncmp(temp, "『", 2) != 0) && (temp[0] != '\'')) t = object_desc_str(t, temp); } /* 伝説のアイテム */ else if (o_ptr->name1 && !fullname) { artifact_type *a_ptr = &a_info[o_ptr->name1]; /* '『' から始まらない伝説のアイテムの名前は最初に付加する */ if (strncmp(a_name + a_ptr->name, "『", 2) != 0) { t = object_desc_str(t, a_name + a_ptr->name); } } /* 名のあるアイテム */ else if (o_ptr->name2) { ego_item_type *e_ptr = &e_info[o_ptr->name2]; t = object_desc_str(t, e_name + e_ptr->name); } } #endif /* Copy the string */ for (s0 = NULL; *s || s0; ) { /* The end of the flavour/kind string. */ if (!*s) { s = s0 + 1; s0 = NULL; } /* Begin to append the modifier (flavor) */ else if ((*s == '#') && !s0) { s0 = s; s = modstr; /* Paranoia -- Never append multiple modstrs */ modstr = ""; } /* Begin to append the kind name */ else if ((*s == '%') && !s0) { s0 = s; s = kindname; /* Paranoia -- Never append multiple kindnames */ kindname = ""; } #ifndef JP /* Pluralizer */ else if (*s == '~') { /* Add a plural if needed */ if (!(mode & OD_NO_PLURAL) && (o_ptr->number != 1)) { char k = t[-1]; /* XXX XXX XXX Mega-Hack */ /* Hack -- "Cutlass-es" and "Torch-es" */ if ((k == 's') || (k == 'h')) *t++ = 'e'; /* Add an 's' */ *t++ = 's'; } s++; } #endif /* Normal */ else { /* Copy */ *t++ = *s++; } } /* Terminate */ *t = '\0'; #ifdef JP /* '『'から始まる伝説のアイテムの名前は最後に付加する */ if (known) { /* ランダムアーティファクトの名前はセーブファイルに記録 されるので、英語版の名前もそれらしく変換する */ if (o_ptr->art_name) { char temp[256]; int itemp; strcpy(temp, quark_str(o_ptr->art_name)); /* MEGA HACK by ita */ if (strncmp(temp, "『", 2) == 0) t = object_desc_str(t, temp); else if (temp[0] == '\'') { itemp = strlen(temp); temp[itemp - 1] = 0; t = object_desc_str(t, "『"); t = object_desc_str(t, &temp[1]); t = object_desc_str(t, "』"); } } else if (o_ptr->name1) { artifact_type *a_ptr = &a_info[o_ptr->name1]; if (strncmp(a_name + a_ptr->name, "『", 2) == 0) { t = object_desc_str(t, a_name + a_ptr->name); } } else if (o_ptr->ego_name) { t = object_desc_str(t, quark_str(o_ptr->ego_name)); } else if (o_ptr->inscription) { cptr str = quark_str(o_ptr->inscription); while(*str) { if (iskanji(*str)) { str += 2; continue; } if (*str == '#') break; str++; } if (*str) { /* Find the '#' */ cptr str = my_strchr(quark_str(o_ptr->inscription), '#'); /* Add the false name */ t = object_desc_str(t,"『"); t = object_desc_str(t, &str[1]); t = object_desc_str(t,"』"); } } } #else /* Hack -- Append "Artifact" or "Special" names */ if (known && !fullname) { /* Is it a new random artifact ? */ if (o_ptr->art_name) { t = object_desc_chr(t, ' '); t = object_desc_str(t, quark_str(o_ptr->art_name)); } /* Grab any artifact name */ else if (o_ptr->name1) { artifact_type *a_ptr = &a_info[o_ptr->name1]; t = object_desc_chr(t, ' '); t = object_desc_str(t, a_name + a_ptr->name); } /* Grab any ego-item name */ else { if (o_ptr->name2) { ego_item_type *e_ptr = &e_info[o_ptr->name2]; t = object_desc_chr(t, ' '); t = object_desc_str(t, e_name + e_ptr->name); } if (o_ptr->ego_name) { t = object_desc_chr(t, ' '); t = object_desc_str(t, quark_str(o_ptr->ego_name)); } else if (o_ptr->inscription && my_strchr(quark_str(o_ptr->inscription), '#')) { /* Find the '#' */ cptr str = my_strchr(quark_str(o_ptr->inscription), '#'); /* Add the false name */ t = object_desc_chr(t, ' '); t = object_desc_str(t, &str[1]); } } } #endif /* No more details wanted */ if (mode & OD_NAME_ONLY) goto object_desc_done; /* Hack -- Chests must be described in detail */ if (o_ptr->tval == TV_CHEST) { /* Not searched yet */ if (!known) { /* Nothing */ } /* May be "empty" */ else if (!o_ptr->pval) { #ifdef JP t = object_desc_str(t, "(空)"); #else t = object_desc_str(t, " (empty)"); #endif } /* May be "disarmed" */ else if (o_ptr->pval < 0) { if (chest_traps[0 - o_ptr->pval]) { #ifdef JP t = object_desc_str(t, "(解除済)"); #else t = object_desc_str(t, " (disarmed)"); #endif } else { #ifdef JP t = object_desc_str(t, "(非施錠)"); #else t = object_desc_str(t, " (unlocked)"); #endif } } /* Describe the traps, if any */ else { /* Describe the traps */ switch (chest_traps[o_ptr->pval]) { case 0: { #ifdef JP t = object_desc_str(t, "(施錠)"); #else t = object_desc_str(t, " (Locked)"); #endif break; } case CHEST_LOSE_STR: { #ifdef JP t = object_desc_str(t, "(毒針)"); #else t = object_desc_str(t, " (Poison Needle)"); #endif break; } case CHEST_LOSE_CON: { #ifdef JP t = object_desc_str(t, "(毒針)"); #else t = object_desc_str(t, " (Poison Needle)"); #endif break; } case CHEST_POISON: { #ifdef JP t = object_desc_str(t, "(ガス・トラップ)"); #else t = object_desc_str(t, " (Gas Trap)"); #endif break; } case CHEST_PARALYZE: { #ifdef JP t = object_desc_str(t, "(ガス・トラップ)"); #else t = object_desc_str(t, " (Gas Trap)"); #endif break; } case CHEST_EXPLODE: { #ifdef JP t = object_desc_str(t, "(爆発装置)"); #else t = object_desc_str(t, " (Explosion Device)"); #endif break; } case CHEST_SUMMON: { #ifdef JP t = object_desc_str(t, "(召喚のルーン)"); #else t = object_desc_str(t, " (Summoning Runes)"); #endif break; } default: { #ifdef JP t = object_desc_str(t, "(マルチ・トラップ)"); #else t = object_desc_str(t, " (Multiple Traps)"); #endif break; } } } } /* Display the item like a weapon */ if (f3 & TR3_SHOW_MODS) show_weapon = TRUE; /* Display the item like a weapon */ if (o_ptr->to_h && o_ptr->to_d) show_weapon = TRUE; /* Display the item like armour */ if (o_ptr->ac) show_armour = TRUE; /* Dump base weapon info */ switch (o_ptr->tval) { /* Missiles and Weapons */ case TV_SHOT: case TV_BOLT: case TV_ARROW: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_DIGGING: /* Append a "damage" string */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_num(t, o_ptr->dd); t = object_desc_chr(t, 'd'); t = object_desc_num(t, o_ptr->ds); t = object_desc_chr(t, p2); /* All done */ break; /* Bows get a special "damage string" */ case TV_BOW: /* Mega-Hack -- Extract the "base power" */ power = bow_tmul(o_ptr->sval); /* Apply the "Extra Might" flag */ if (f3 & TR3_XTRA_MIGHT) power++; /* Append a special "damage" string */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_chr(t, 'x'); t = object_desc_num(t, power); t = object_desc_chr(t, p2); /* All done */ break; } /* Add the weapon bonuses */ if (known) { /* Show the tohit/todam on request */ if (show_weapon) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_int(t, o_ptr->to_h); t = object_desc_chr(t, ','); t = object_desc_int(t, o_ptr->to_d); t = object_desc_chr(t, p2); } /* Show the tohit if needed */ else if (o_ptr->to_h) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_int(t, o_ptr->to_h); t = object_desc_chr(t, p2); } /* Show the todam if needed */ else if (o_ptr->to_d) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_int(t, o_ptr->to_d); t = object_desc_chr(t, p2); } } bow_ptr = &inventory[INVEN_BOW]; /* If have a firing weapon + ammo matches bow */ if (bow_ptr->k_idx && (o_ptr->tval == p_ptr->tval_ammo)) { int avgdam = o_ptr->dd * (o_ptr->ds + 1) * 10 / 2; int tmul = bow_tmul(bow_ptr->sval); s16b energy_fire = bow_energy(bow_ptr->sval); /* See if the bow is "known" - then set damage bonus */ if (object_known_p(bow_ptr)) avgdam += (bow_ptr->to_d * 10); /* Effect of ammo */ if (known) avgdam += (o_ptr->to_d * 10); /* Get extra "power" from "extra might" */ if (p_ptr->xtra_might) tmul++; tmul = tmul * (100 + (int)(adj_str_td[p_ptr->stat_ind[A_STR]]) - 128); /* Launcher multiplier */ avgdam *= tmul; avgdam /= (100 * 10); if (avgdam < 0) avgdam = 0; /* Display (shot damage/ avg damage) */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_num(t, avgdam); t = object_desc_chr(t, '/'); if (p_ptr->num_fire == 0) { t = object_desc_chr(t, '0'); } else { /* Calc effects of energy */ avgdam *= (p_ptr->num_fire * 100); avgdam /= energy_fire * 100; t = object_desc_num(t, avgdam); } t = object_desc_chr(t, p2); } /* Add the armor bonuses */ if (known) { /* Show the armor class info */ if (show_armour) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, b1); t = object_desc_num(t, o_ptr->ac); t = object_desc_chr(t, ','); t = object_desc_int(t, o_ptr->to_a); t = object_desc_chr(t, b2); } /* No base armor, but does increase armor */ else if (o_ptr->to_a) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, b1); t = object_desc_int(t, o_ptr->to_a); t = object_desc_chr(t, b2); } } /* Hack -- always show base armor */ else if (show_armour) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, b1); t = object_desc_num(t, o_ptr->ac); t = object_desc_chr(t, b2); } /* No more details wanted */ if (mode & OD_NAME_AND_ENCHANT) goto object_desc_done; if (known) /* Known item only */ { /* * Hack -- Wands and Staffs have charges. Make certain how many charges * a stack of staffs really has is clear. -LM- */ if (((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND))) { /* Dump " (N charges)" */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); /* Clear explaination for staffs. */ if ((o_ptr->tval == TV_STAFF) && (o_ptr->number > 1)) { t = object_desc_num(t, o_ptr->number); t = object_desc_str(t, "x "); } t = object_desc_num(t, o_ptr->pval); #ifdef JP t = object_desc_str(t, "回分"); #else t = object_desc_str(t, " charge"); if (o_ptr->pval != 1) t = object_desc_chr(t, 's'); #endif t = object_desc_chr(t, p2); } /* Hack -- Rods have a "charging" indicator. Now that stacks of rods may * be in any state of charge or discharge, this now includes a number. -LM- */ else if (o_ptr->tval == TV_ROD) { /* Hack -- Dump " (# charging)" if relevant */ if (o_ptr->timeout) { /* Stacks of rods display an exact count of charging rods. */ if (o_ptr->number > 1) { /* Paranoia. */ if (k_ptr->pval == 0) k_ptr->pval = 1; /* Find out how many rods are charging, by dividing * current timeout by each rod's maximum timeout. * Ensure that any remainder is rounded up. Display * very discharged stacks as merely fully discharged. */ power = (o_ptr->timeout + (k_ptr->pval - 1)) / k_ptr->pval; if (power > o_ptr->number) power = o_ptr->number; /* Display prettily. */ t = object_desc_str(t, " ("); t = object_desc_num(t, power); #ifdef JP t = object_desc_str(t, "本 充填中)"); #else t = object_desc_str(t, " charging)"); #endif } /* "one Rod of Perception (1 charging)" would look tacky. */ else { #ifdef JP t = object_desc_str(t, "(充填中)"); #else t = object_desc_str(t, " (charging)"); #endif } } } /* Dump "pval" flags for wearable items */ if (f1 & TR1_PVAL_MASK) { /* Start the display */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); /* Dump the "pval" itself */ t = object_desc_int(t, o_ptr->pval); /* Do not display the "pval" flags */ if (f3 & TR3_HIDE_TYPE) { /* Nothing */ } /* Speed */ else if (f1 & TR1_SPEED) { /* Dump " to speed" */ #ifdef JP t = object_desc_str(t, "加速"); #else t = object_desc_str(t, " to speed"); #endif } /* Attack speed */ else if (f1 & TR1_BLOWS) { /* Add " attack" */ #ifdef JP t = object_desc_str(t, "攻撃"); #else t = object_desc_str(t, " attack"); /* Add "attacks" */ if (ABS(o_ptr->pval) != 1) t = object_desc_chr(t, 's'); #endif } /* Stealth */ else if (f1 & TR1_STEALTH) { /* Dump " to stealth" */ #ifdef JP t = object_desc_str(t, "隠密"); #else t = object_desc_str(t, " to stealth"); #endif } /* Search */ else if (f1 & TR1_SEARCH) { /* Dump " to searching" */ #ifdef JP t = object_desc_str(t, "探索"); #else t = object_desc_str(t, " to searching"); #endif } /* Infravision */ else if (f1 & TR1_INFRA) { /* Dump " to infravision" */ #ifdef JP t = object_desc_str(t, "赤外線視力"); #else t = object_desc_str(t, " to infravision"); #endif } /* Finish the display */ t = object_desc_chr(t, p2); } /* Hack -- Process Lanterns/Torches */ if ((o_ptr->tval == TV_LITE) && ((o_ptr->sval == SV_LITE_TORCH) || (o_ptr->sval == SV_LITE_LANTERN))) { /* Hack -- Turns of light for normal lites */ #ifdef JP t = object_desc_chr(t, '('); #else t = object_desc_str(t, " (with "); #endif t = object_desc_num(t, o_ptr->xtra3); #ifdef JP t = object_desc_str(t, "ターンの寿命)"); #else t = object_desc_str(t, " turns of light)"); #endif } /* Indicate charging objects, but not rods. */ if (o_ptr->timeout && (o_ptr->tval != TV_ROD)) { /* Hack -- Dump " (charging)" if relevant */ #ifdef JP t = object_desc_str(t, "(充填中)"); #else t = object_desc_str(t, " (charging)"); #endif } } /* No more details wanted */ if (mode & OD_OMIT_INSCRIPTION) goto object_desc_done; /* Prepare real inscriptions in a buffer */ tmp_val2[0] = '\0'; /* Auto abbreviation inscribe */ if ((abbrev_extra || abbrev_all) && (o_ptr->ident & IDENT_MENTAL)) { if (!o_ptr->inscription || !my_strchr(quark_str(o_ptr->inscription), '%')) { bool kanji, all; #ifdef JP kanji = TRUE; #else kanji = FALSE; #endif all = abbrev_all; get_ability_abbreviation(tmp_val2, o_ptr, kanji, all, FALSE); } } /* Use the standard inscription if available */ if (o_ptr->inscription) { char buff[1024]; if (tmp_val2[0]) strcat(tmp_val2, ", "); /* Get inscription and convert {%} */ get_inscription(buff, o_ptr); /* strcat with correct treating of kanji */ my_strcat(tmp_val2, buff, sizeof(tmp_val2)); } /* No fake inscription yet */ fake_insc_buf[0] = '\0'; /* Use the game-generated "feeling" otherwise, if available */ if (o_ptr->feeling) { strcpy(fake_insc_buf, game_inscriptions[o_ptr->feeling]); } /* Note "cursed" if the item is known to be cursed */ else if (cursed_p(o_ptr) && (known || (o_ptr->ident & IDENT_SENSE))) { #ifdef JP strcpy(fake_insc_buf, "呪われている"); #else strcpy(fake_insc_buf, "cursed"); #endif } /* Note "unidentified" if the item is unidentified */ else if (((o_ptr->tval == TV_RING) || (o_ptr->tval == TV_AMULET) || (o_ptr->tval == TV_LITE) || (o_ptr->tval == TV_FIGURINE)) && aware && !known && !(o_ptr->ident & IDENT_SENSE)) { #ifdef JP strcpy(fake_insc_buf, "未鑑定"); #else strcpy(fake_insc_buf, "unidentified"); #endif } /* Mega-Hack -- note empty wands/staffs */ else if (!known && (o_ptr->ident & IDENT_EMPTY)) { #ifdef JP strcpy(fake_insc_buf, "空"); #else strcpy(fake_insc_buf, "empty"); #endif } /* Note "tried" if the object has been tested unsuccessfully */ else if (!aware && object_tried_p(o_ptr)) { #ifdef JP strcpy(fake_insc_buf, "未判明"); #else strcpy(fake_insc_buf, "tried"); #endif } /* Note the discount, if any */ if (o_ptr->discount) { /* Hidden by real inscription unless in a store */ if (!tmp_val2[0] || (o_ptr->ident & IDENT_STORE)) { char discount_num_buf[4]; /* Append to other fake inscriptions if any */ if (fake_insc_buf[0]) strcat(fake_insc_buf, ", "); (void)object_desc_num(discount_num_buf, o_ptr->discount); strcat(fake_insc_buf, discount_num_buf); #ifdef JP strcat(fake_insc_buf, "%引き"); #else strcat(fake_insc_buf, "% off"); #endif } } /* Append the inscription, if any */ if (fake_insc_buf[0] || tmp_val2[0]) { /* Append the inscription */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, c1); /* Append fake inscriptions */ if (fake_insc_buf[0]) { t = object_desc_str(t, fake_insc_buf); } /* Append a separater */ if (fake_insc_buf[0] && tmp_val2[0]) { t = object_desc_chr(t, ','); t = object_desc_chr(t, ' '); } /* Append real inscriptions */ if (tmp_val2[0]) { t = object_desc_str(t, tmp_val2); } t = object_desc_chr(t, c2); } object_desc_done: my_strcpy(buf, tmp_val, MAX_NLEN); }
static size_t obj_desc_inscrip(const object_type *o_ptr, char *buf, size_t max, size_t end) { const char *u[6] = { 0, 0, 0, 0, 0, 0}; int n = 0; /* See if the object is "known" */ bool known = (object_known_p(o_ptr) ? TRUE : FALSE); bool aware = (object_aware_p(o_ptr) ? TRUE : FALSE); u32b f1, f2, f3, fn; object_flags(o_ptr, &f1, &f2, &f3, &fn); /* Get inscription, pdeudo-id, or store discount */ if (o_ptr->obj_note) u[n++] = quark_str(o_ptr->obj_note); if (o_ptr->discount >= INSCRIP_NULL) { u[n++] = inscrip_text[o_ptr->discount - INSCRIP_NULL]; } else if (cursed_p(o_ptr) && known) { u[n++] = "cursed"; } else if ((o_ptr->ident & IDENT_EMPTY) && (!known)) { u[n++] = "empty"; } else if ((!aware) && object_tried_p(o_ptr)) { u[n++] = "tried"; } else if (o_ptr->discount > 0) { char buf[80]; my_strcpy(buf, format("%d%% off", o_ptr->discount), sizeof(buf)); u[n++] = buf; } /* Use the "unknown" inscription */ else if (!known && can_be_pseudo_ided(o_ptr) && (o_ptr->discount < INSCRIP_NULL)) { u[n++] = "unknown"; } if (n) { int i; for (i = 0; i < n; i++) { if (i == 0) strnfcat(buf, max, &end, " {"); strnfcat(buf, max, &end, "%s", u[i]); if (i < n-1) strnfcat(buf, max, &end, ", "); } strnfcat(buf, max, &end, "}"); } return end; }
/* * Creates a description of the item "o_ptr", and stores it in "out_val". * * One can choose the "verbosity" of the description, including whether * or not the "number" of items should be described, and how much detail * should be used when describing the item. * * The given "buf" must be 80 chars long to hold the longest possible * description, which can get pretty long, including incriptions, such as: * "no more Maces of Disruption (Defender) (+10,+10) [+5] (+3 to stealth)". * Note that the inscription will be clipped to keep the total description * under 79 chars (plus a terminator). * * Note the use of "object_desc_num()" and "object_desc_int()" as * hyper-efficient, portable, versions of some common "sprintf()" commands. * * Note that all ego-items (when known) append an "Ego-Item Name", unless * the item is also an artifact, which should NEVER happen. * * Note that all artifacts (when known) append an "Artifact Name", so we * have special processing for "Specials" (artifact Lites, Rings, Amulets). * The "Specials" never use "modifiers" if they are "known", since they * have special "descriptions", such as "The Necklace of the Dwarves". * * Special Lite's use the "k_info" base-name (Phial, Star, or Arkenstone), * plus the artifact name, just like any other artifact, if known. * * Special Ring's and Amulet's, if not "aware", use the same code as normal * rings and amulets, and if "aware", use the "k_info" base-name (Ring or * Amulet or Necklace). They will NEVER "append" the "k_info" name. But, * they will append the artifact name, just like any artifact, if known. * * None of the Special Rings/Amulets are "EASY_KNOW", though they could be, * at least, those which have no "pluses", such as the three artifact lites. * * Hack -- Display "The One Ring" as "a Plain Gold Ring" until aware. * * If "pref" then a "numeric" prefix will be pre-pended. * * Mode: * 0 -- The Cloak of Death * 1 -- The Cloak of Death [1,+3] * 2 -- The Cloak of Death [1,+3] (+2 to Stealth) * 3 -- The Cloak of Death [1,+3] (+2 to Stealth) {nifty} */ void object_desc(char *buf, const object_type *o_ptr, int pref, int mode) { cptr basenm, modstr; int power, indexx, durable; bool aware = FALSE; bool known = FALSE; bool append_name = FALSE; bool show_weapon = FALSE; bool show_armour = FALSE; cptr s, u; char *t; char p1 = '(', p2 = ')'; char b1 = '[', b2 = ']'; char c1 = '{', c2 = '}'; char pv1 = '<', pv2 = '>'; char tmp_val[160]; char tmp_val2[90]; u32b f1, f2, f3, f4, f5, f6; object_type *bow_ptr; /* damage dice, damage sides, damage bonus, energy */ int dd, ds, db, energy_use; int tmul; long avgdam; object_kind *k_ptr = &k_info[o_ptr->k_idx]; monster_race *r_ptr = &r_info[o_ptr->pval]; /* Extract some flags */ object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6); /***** NEEDS REWORKING *****/ durable = 0; /* See if the object is "aware" */ if (object_aware_p(o_ptr)) aware = TRUE; /* See if the object is "known" */ if (object_known_p(o_ptr)) known = TRUE; /* Hack -- Extract the sub-type "indexx" */ indexx = o_ptr->sval; /* Extract default "base" string */ basenm = get_object_name(o_ptr); /* Assume no "modifier" string */ modstr = ""; /* Analyze the object */ switch (o_ptr->tval) { /* Some objects are easy to describe */ case TV_SKELETON: case TV_BOTTLE: case TV_JUNK: case TV_SPIKE: case TV_FLASK: case TV_CHEST: { break; } /* Figurines/Statues */ case TV_FIGURINE: case TV_STATUE: { cptr tmp = r_name + r_ptr->name; if (!(r_ptr->flags1 & RF1_UNIQUE)) { sprintf(tmp_val2, "%s%s", (is_a_vowel(*tmp) ? "an " : "a "), tmp); modstr = tmp_val2; } else { modstr = tmp; } break; } /* Missiles/ Bows/ Weapons */ case TV_SHOT: case TV_BOLT: case TV_ARROW: case TV_BOW: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_DIGGING: { show_weapon = TRUE; break; } /* Armour */ 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: { show_armour = TRUE; break; } /* Lites (including a few "Specials") */ case TV_LITE: { break; } /* Amulets (including a few "Specials") */ case TV_AMULET: { /* Known artifacts */ if ((o_ptr->flags3 & TR3_INSTA_ART) && aware) break; /* Color the object */ modstr = amulet_adj[indexx]; break; } /* Rings (including a few "Specials") */ case TV_RING: { /* Known artifacts */ if ((o_ptr->flags3 & TR3_INSTA_ART) && aware) break; /* Color the object */ modstr = ring_adj[indexx]; /* Hack -- The One Ring */ /*if (!aware && (o_ptr->sval == SV_RING_POWER)) modstr = "Plain Gold";*/ break; } case TV_STAFF: { /* Color the object */ modstr = staff_adj[indexx]; break; } case TV_WAND: { /* Color the object */ modstr = wand_adj[indexx]; break; } case TV_ROD: { /* Color the object */ modstr = rod_adj[indexx]; break; } case TV_SCROLL: { /* Color the object */ modstr = scroll_adj[indexx]; break; } case TV_POTION: { /* Color the object */ modstr = potion_adj[indexx]; break; } case TV_FOOD: { /* Ordinary food is "boring" */ if (o_ptr->sval >= SV_FOOD_MIN_FOOD) break; /* Color the object */ modstr = food_adj[indexx]; break; } /* Magic Books */ case TV_SPELL_BOOK: { modstr = basenm; break; } /* Hack -- Gold/Gems */ case TV_GOLD: { strcpy(buf, basenm); return; } /* Used in the "inventory" routine */ default: { strcpy(buf, "(nothing)"); return; } } /* Start dumping the result */ t = tmp_val; /* Durability Check */ durable = (o_ptr->C_Durability / (o_ptr->weight * 3)); if (durable > 7) durable = 7; if (durable == 0) t = object_desc_str(t, "(J) "); if (durable == 1) t = object_desc_str(t, "(B) "); if (durable == 2) t = object_desc_str(t, "(P) "); if (durable == 3) t = object_desc_str(t, "(N) "); if (durable == 4) t = object_desc_str(t, "(G) "); if (durable == 5) t = object_desc_str(t, "(E) "); if (durable == 6) t = object_desc_str(t, "(W) "); if (durable == 7) t = object_desc_str(t, "(M) "); /* The object "expects" a "number" */ if (basenm[0] == '&') { /* Skip the ampersand (and space) */ s = basenm + 2; /* No prefix */ if (!pref) { /* Nothing */ } /* Hack -- None left */ else if (o_ptr->number <= 0) { t = object_desc_str(t, "no more "); } /* Extract the number */ else if (o_ptr->number > 1) { t = object_desc_num(t, o_ptr->number); t = object_desc_chr(t, ' '); } /* Hack -- The only one of its kind */ else if (known && (o_ptr->flags3 & TR3_INSTA_ART)) { t = object_desc_str(t, "The "); } /* A single one, with a vowel in the modifier */ else if ((*s == '#') && (is_a_vowel(modstr[0]))) { t = object_desc_str(t, "an "); } /* A single one, with a vowel */ else if (is_a_vowel(*s)) { t = object_desc_str(t, "an "); } /* A single one, without a vowel */ else { t = object_desc_str(t, "a "); } } /* Hack -- objects that "never" take an article */ else { /* No ampersand */ s = basenm; /* No pref */ if (!pref) { /* Nothing */ } /* Hack -- all gone */ else if (o_ptr->number <= 0) { t = object_desc_str(t, "no more "); } /* Prefix a number if required */ else if (o_ptr->number > 1) { t = object_desc_num(t, o_ptr->number); t = object_desc_chr(t, ' '); } /* Hack -- The only one of its kind */ else if (known && (o_ptr->flags3 & TR3_INSTA_ART)) { t = object_desc_str(t, "The "); } /* Hack -- single items get no prefix */ else { /* Nothing */ } } /* Paranoia -- skip illegal tildes */ /* while (*s == '~') s++; */ /* Copy the string */ for (; *s; s++) { /* Pluralizer */ if (*s == '~') { /* Add a plural if needed */ if (o_ptr->number != 1) { char k = t[-1]; /* XXX XXX XXX Mega-Hack */ /* Hack -- "Cutlass-es" and "Torch-es" */ if ((k == 's') || (k == 'h')) *t++ = 'e'; /* Add an 's' */ *t++ = 's'; } } /* Modifier */ else if (*s == '#') { /* Insert the modifier */ for (u = modstr; *u; u++) *t++ = *u; } /* Normal */ else { /* Copy */ *t++ = *s; } } /* Terminate */ *t = '\0'; /* Append the "kind name" to the "base name" */ if (append_name) { t = object_desc_str(t, " of "); t = object_desc_str(t, get_object_name(o_ptr)); } /* Hack -- Append "Artifact" or "Special" names */ if (known) { if (o_ptr->inscription && strchr(quark_str(o_ptr->inscription), '#')) { /* Find the '#' */ cptr str = strchr(quark_str(o_ptr->inscription), '#'); /* Add the false name */ t = object_desc_chr(t, ' '); t = object_desc_str(t, &str[1]); } /* Is it a new artifact or ego item? */ else if (o_ptr->xtra_name) { t = object_desc_chr(t, ' '); t = object_desc_str(t, quark_str(o_ptr->xtra_name)); } } /* No more details wanted */ if (mode < 1) goto copyback; /* Hack -- Chests must be described in detail */ if (o_ptr->tval == TV_CHEST) { /* Not searched yet */ if (!known) { /* Nothing */ } /* May be "empty" */ else if (!o_ptr->pval) { t = object_desc_str(t, " (empty)"); } /* May be "disarmed" */ else if (o_ptr->pval < 0) { if (chest_traps[0 - o_ptr->pval]) { t = object_desc_str(t, " (disarmed)"); } else { t = object_desc_str(t, " (unlocked)"); } } /* Describe the traps, if any */ else { /* Describe the traps */ switch (chest_traps[o_ptr->pval]) { case 0: { t = object_desc_str(t, " (Locked)"); break; } case CHEST_LOSE_STR: { t = object_desc_str(t, " (Poison Needle)"); break; } case CHEST_LOSE_CON: { t = object_desc_str(t, " (Poison Needle)"); break; } case CHEST_POISON: { t = object_desc_str(t, " (Gas Trap)"); break; } case CHEST_PARALYZE: { t = object_desc_str(t, " (Gas Trap)"); break; } case CHEST_EXPLODE: { t = object_desc_str(t, " (Explosion Device)"); break; } case CHEST_SUMMON: { t = object_desc_str(t, " (Summoning Runes)"); break; } default: { t = object_desc_str(t, " (Multiple Traps)"); break; } } } } /* Display the item like a weapon */ if (f3 & (TR3_SHOW_MODS)) show_weapon = TRUE; /* Display the item like a weapon */ if (o_ptr->to_h && o_ptr->to_d) show_weapon = TRUE; /* Display the item like armour */ if ((o_ptr->ac) && (o_ptr->tval != TV_WAND)) show_armour = TRUE; /* Dump base weapon info */ switch (o_ptr->tval) { /* Missiles and Weapons */ case TV_SHOT: case TV_BOLT: case TV_ARROW: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_DIGGING: /* Append a "damage" string */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_num(t, o_ptr->dd); t = object_desc_chr(t, 'd'); t = object_desc_num(t, o_ptr->ds); t = object_desc_chr(t, p2); /* All done */ break; /* Bows get a special "damage string" */ case TV_BOW: /* Extract the "base power" */ switch (o_ptr->sval) { case SV_SLING: power = 2; break; case SV_SHORT_BOW: power = 2; break; case SV_LONG_BOW: if (p_ptr->stat_use[A_STR] >= 16) { power = 3; } else { /* hack- weak players cannot use a longbow well */ power = 2; } break; case SV_LIGHT_XBOW: power = 4; break; case SV_HEAVY_XBOW: power = 5; break; default: msg_print("Unknown firing multiplier."); power = 0; } /* Apply the "Extra Might" flag */ if (f3 & (TR3_XTRA_MIGHT)) power++; /* Append a special "damage" string */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_chr(t, 'x'); t = object_desc_num(t, power); t = object_desc_chr(t, p2); /* All done */ break; } /* Add the weapon bonuses */ if (known) { /* Show the tohit/todam on request */ if (show_weapon) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_int(t, o_ptr->to_h); t = object_desc_chr(t, ','); t = object_desc_int(t, o_ptr->to_d); t = object_desc_chr(t, p2); } /* Show the tohit if needed */ else if (o_ptr->to_h) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_int(t, o_ptr->to_h); t = object_desc_chr(t, p2); } /* Show the todam if needed */ else if (o_ptr->to_d) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_int(t, o_ptr->to_d); t = object_desc_chr(t, p2); } } bow_ptr = &inventory[INVEN_BOW]; /* if have a firing weapon + ammo matches bow */ if (bow_ptr->k_idx && (p_ptr->ammo_tval == o_ptr->tval)) { /* See if the bow is "known" - then set damage bonus */ if (object_known_p(bow_ptr)) { db = bow_ptr->to_d; } else { db = 0; } /* effect of player */ db += p_ptr->dis_to_d; /* effect of ammo */ if (known) db += o_ptr->to_d; dd = o_ptr->dd; ds = o_ptr->ds; /* avgdam = deadliness_calc(db);*/ /* effect of damage dice x2 */ avgdam = dd * (ds + 1); avgdam += db; /* Bow properties */ energy_use = p_ptr->bow_energy; tmul = p_ptr->ammo_mult; /* Get extra "power" from "extra might" */ if (p_ptr->xtra_might) tmul++; /* launcher multiplier */ avgdam *= tmul; /* display (shot damage/ avg damage) */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); t = object_desc_num(t, avgdam / 2/*00*/); t = object_desc_chr(t, '/'); tmul = p_ptr->num_fire; if (tmul == 0) { t = object_desc_chr(t, '-'); } else { /* calc effects of energy x2 */ avgdam *= (1 + p_ptr->num_fire); /* rescale */ avgdam /= ((int)(4 * (int)(energy_use / 100.0))); t = object_desc_num(t, avgdam); } t = object_desc_chr(t, p2); } /* Add the armor bonuses */ if (known) { /* Show the armor class info */ if (show_armour) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, b1); t = object_desc_num(t, o_ptr->ac); t = object_desc_chr(t, ','); t = object_desc_int(t, o_ptr->to_a); t = object_desc_chr(t, b2); } /* No base armor, but does increase armor */ else if (o_ptr->to_a) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, b1); t = object_desc_int(t, o_ptr->to_a); t = object_desc_chr(t, b2); } } /* Hack -- always show base armor */ else if (show_armour) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, b1); t = object_desc_num(t, o_ptr->ac); t = object_desc_chr(t, b2); } /* No more details wanted */ if (mode < 2) goto copyback; /* * Hack -- Wands and Staffs have charges. Make certain how many charges * a stack of staffs really has is clear. -LM- */ if (known && ((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND))) { /* Dump " (N charges)" */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); /* Clear explaination for staffs. */ if ((o_ptr->tval == TV_STAFF) && (o_ptr->number > 1)) { t = object_desc_num(t, o_ptr->number); t = object_desc_str(t, "x "); } t = object_desc_num(t, o_ptr->pval); t = object_desc_str(t, " charge"); if (o_ptr->pval != 1) { t = object_desc_chr(t, 's'); } t = object_desc_chr(t, p2); } /* Hack -- Rods have a "charging" indicator. Now that stacks of rods may * be in any state of charge or discharge, this now includes a number. -LM- */ else if (known && (o_ptr->tval == TV_ROD)) { /* Hack -- Dump " (# charging)" if relevant */ if ((o_ptr->timeout) && (o_ptr->tval != TV_LITE)) { /* Stacks of rods display an exact count of charging rods. */ if (o_ptr->number > 1) { /* Paranoia. */ if (k_ptr->pval == 0) k_ptr->pval = 1; /* Find out how many rods are charging, by dividing * current timeout by each rod's maximum timeout. * Ensure that any remainder is rounded up. Display * very discharged stacks as merely fully discharged. */ power = (o_ptr->timeout + (k_ptr->pval - 1)) / k_ptr->pval; if (power > o_ptr->number) power = o_ptr->number; /* Display prettily. */ t = object_desc_str(t, " ("); t = object_desc_num(t, power); t = object_desc_str(t, " charging)"); } /* "one Rod of Perception (1 charging)" would look tacky. */ else { t = object_desc_str(t, " (charging)"); } } } /* Hack -- Process Lanterns/Torches */ else if ((o_ptr->tval == TV_LITE) && (!(o_ptr->flags3 & TR3_LITE))) { /* Hack -- Turns of light for normal lites */ t = object_desc_str(t, " (with "); t = object_desc_num(t, o_ptr->timeout); t = object_desc_str(t, " turns of light)"); } /* Dump "pval" flags for wearable items */ if (known && (f1 & (TR1_PVAL_MASK))) { if (o_ptr->tval != TV_STAFF && o_ptr->tval != TV_ROD && o_ptr->tval != TV_POTION && o_ptr->tval != TV_FOOD && o_ptr->tval != TV_WAND && o_ptr->tval != TV_SCROLL) { /* Start the display */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, p1); /* Dump the "pval" itself */ t = object_desc_int(t, o_ptr->pval); /* Do not display the "pval" flags */ if (f3 & (TR3_HIDE_TYPE)) { /* Nothing */ } /* Speed */ else if (f1 & (TR1_SPEED)) { /* Dump " to speed" */ t = object_desc_str(t, " to speed"); } /* Attack speed */ else if (f1 & (TR1_BLOWS)) { /* Add " attack" */ t = object_desc_str(t, " attack"); /* Add "attacks" */ if (ABS(o_ptr->pval) != 1) t = object_desc_chr(t, 's'); } /* Stealth */ else if (f1 & (TR1_STEALTH)) { /* Dump " to stealth" */ t = object_desc_str(t, " to stealth"); } /* Search */ else if (f1 & (TR1_SEARCH)) { /* Dump " to searching" */ t = object_desc_str(t, " to searching"); } /* Infravision */ else if (f1 & (TR1_INFRA)) { /* Dump " to infravision" */ t = object_desc_str(t, " to infravision"); } /* Finish the display */ t = object_desc_chr(t, p2); } } if (known && o_ptr->pval2) { t = object_desc_chr(t, ' '); t = object_desc_chr(t, pv1); t = object_desc_num(t, o_ptr->pval2); t = object_desc_chr(t, pv2); } /* Indicate charging objects, but not rods. */ if (known && o_ptr->timeout && o_ptr->tval != TV_ROD && o_ptr->tval != TV_LITE) { /* Hack -- Dump " (charging)" if relevant */ t = object_desc_str(t, " (charging)"); } /* No more details wanted */ if (mode < 3) goto copyback; /* No inscription yet */ tmp_val2[0] = '\0'; /* Use the standard inscription if available */ if (o_ptr->inscription) { char *tmp = tmp_val2; strcpy(tmp_val2, quark_str(o_ptr->inscription)); for (; *tmp && (*tmp != '#'); tmp++); *tmp = '\0'; } /* Use the game-generated "feeling" otherwise, if available */ else if (o_ptr->feeling) { strcpy(tmp_val2, game_inscriptions[o_ptr->feeling]); } /* Note "cursed" if the item is known to be cursed */ else if (cursed_p(o_ptr) && (known || (o_ptr->ident & (IDENT_SENSE)))) { strcpy(tmp_val2, "cursed"); } /* Mega-Hack -- note empty wands/staffs */ else if (!known && (o_ptr->ident & (IDENT_EMPTY))) { strcpy(tmp_val2, "empty"); } /* Note "tried" if the object has been tested unsuccessfully */ else if (!aware && object_tried_p(o_ptr)) { strcpy(tmp_val2, "tried"); } /* Note the discount, if any */ else if (o_ptr->discount) { (void)object_desc_num(tmp_val2, o_ptr->discount); strcat(tmp_val2, "% off"); } /* Append the inscription, if any */ if (tmp_val2[0]) { int n; /* Hack -- How much so far */ n = (t - tmp_val); /* Paranoia -- do not be stupid */ if (n > 75) n = 75; /* Hack -- shrink the inscription */ tmp_val2[75 - n] = '\0'; /* Append the inscription */ t = object_desc_chr(t, ' '); t = object_desc_chr(t, c1); t = object_desc_str(t, tmp_val2); t = object_desc_chr(t, c2); } copyback: /* Here's where we dump the built string into buf. */ tmp_val[79] = '\0'; t = tmp_val; while ((*(buf++) = *(t++))); /* copy the string over */ }
/* * Copy 'src' into 'buf, replacing '#' with 'modstr' (if found), putting a plural * in the place indicated by '~' if required, or using alterate... */ static size_t obj_desc_name(char *buf, size_t max, size_t end, const object_type * o_ptr, bool prefix, odesc_detail_t mode, bool spoil) { object_kind *k_ptr = &k_info[o_ptr->k_idx]; bool known = object_known_p(o_ptr) || spoil; bool aware = object_aware_p(o_ptr) || spoil; const char *basename = obj_desc_get_basename(o_ptr, aware); const char *modstr = obj_desc_get_modstr(o_ptr); bool pluralise = (mode & ODESC_PLURAL) ? TRUE : FALSE; if (aware && !k_ptr->everseen) k_ptr->everseen = TRUE; if (o_ptr->number > 1) pluralise = TRUE; if (mode & ODESC_SINGULAR) pluralise = FALSE; /* Add a pseudo-numerical prefix if desired */ if (prefix) { if (o_ptr->number <= 0) { strnfcat(buf, max, &end, "no more "); /* Pluralise for grammatical correctness */ pluralise = TRUE; } else if (o_ptr->number > 1) strnfcat(buf, max, &end, "%d ", o_ptr->number); else if ((known) && artifact_p(o_ptr)) strnfcat(buf, max, &end, "The "); else if (*basename == '&') { bool an = FALSE; const char *lookahead = basename + 1; while (*lookahead == ' ') lookahead++; if (*lookahead == '#') { if (modstr && is_a_vowel(*modstr)) an = TRUE; } else if (is_a_vowel(*lookahead)) { an = TRUE; } if (an) strnfcat(buf, max, &end, "an "); else strnfcat(buf, max, &end, "a "); } } /* * Names have the following elements: * * '~' indicates where to place an 's' or an 'es'. Other plural forms should * be handled with the syntax '|singular|plural|', e.g. "kni|fe|ves|". * * '#' indicates the position of the "modifier", e.g. the flavour or spellbook * name. */ /* Copy the string */ while (*basename) { if (*basename == '&') { while (*basename == ' ' || *basename == '&') basename++; continue; } /* Pluralizer (regular English plurals) */ else if (*basename == '~') { char prev = *(basename - 1); if (!pluralise) { basename++; continue; } /* e.g. cutlass-e-s, torch-e-s, box-e-s */ if (prev == 's' || prev == 'h' || prev == 'x') strnfcat(buf, max, &end, "es"); else strnfcat(buf, max, &end, "s"); } /* Special plurals */ else if (*basename == '|') { /* e.g. & Wooden T|o|e|rch~ ^ ^^ */ const char *singular = basename + 1; const char *plural = strchr(singular, '|'); const char *endmark = NULL; if (plural) { plural++; endmark = strchr(plural, '|'); } if (!singular || !plural || !endmark) return end; if (!pluralise) strnfcat(buf, max, &end, "%.*s", plural - singular - 1, singular); else strnfcat(buf, max, &end, "%.*s", endmark - plural, plural); basename = endmark; } /* Handle pluralisation in the modifier XXX */ else if (*basename == '#') { const char *basename = modstr; while (basename && *basename && (end < max - 1)) { /* Special plurals */ if (*basename == '|') { /* e.g. & Wooden T|o|e|rch~ ^ ^^ */ const char *singular = basename + 1; const char *plural = strchr(singular, '|'); const char *endmark = NULL; if (plural) { plural++; endmark = strchr(plural, '|'); } if (!singular || !plural || !endmark) return end; if (!pluralise) strnfcat(buf, max, &end, "%.*s", plural - singular - 1, singular); else strnfcat(buf, max, &end, "%.*s", endmark - plural, plural); basename = endmark; } else buf[end++] = *basename; basename++; } } else buf[end++] = *basename; basename++; } /* 0-terminate, just in case XXX */ buf[end] = 0; /** Append extra names of various kinds **/ if ((known) && o_ptr->name1) strnfcat(buf, max, &end, " %s", a_info[o_ptr->name1].name); else if ((spoil && o_ptr->name2) || has_ego_properties(o_ptr)) strnfcat(buf, max, &end, " %s", e_info[o_ptr->name2].name); else if (aware && !artifact_p(o_ptr) && (k_ptr->flavor || k_ptr->tval == TV_SCROLL) && ((k_ptr->tval != TV_FOOD) || (k_ptr->sval < SV_FOOD_MIN_FOOD))) strnfcat(buf, max, &end, " of %s", k_ptr->name); return end; }
static void do_cmd_eat_food_aux(int item) { int ident, lev; object_type *o_ptr; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Sound */ sound(SOUND_EAT); /* Take a turn */ energy_use = 100; /* Identity not known yet */ ident = FALSE; /* Object level */ lev = get_object_level(o_ptr); /* Analyze the food */ switch (o_ptr->sval) { #ifdef JP /* それぞれの食べ物の感想をオリジナルより細かく表現 */ case SV_FOOD_SLIME_MOLD: { msg_print("これはなんとも形容しがたい味だ。"); ident = TRUE; break; } case SV_FOOD_RATION: { msg_print("これはおいしい。"); ident = TRUE; break; } #else case SV_FOOD_RATION: case SV_FOOD_SLIME_MOLD: { msg_print("That tastes good."); ident = TRUE; break; } #endif case SV_FOOD_WAYBREAD: { #ifdef JP msg_print("これはひじょうに美味だ。"); #else msg_print("That tastes good."); #endif (void)set_poisoned(0); (void)hp_player(damroll(4, 8)); ident = TRUE; break; } } /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* We have tried it */ object_tried(o_ptr); /* The player is now aware of the object */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); }
/* * Display an object. Each object may be prefixed with a label. * Used by show_inven(), show_equip(), and show_floor(). Mode flags are * documented in object.h */ static void show_obj(int onum, size_t max_len, char label[80], const object_type *object, bool cursor, olist_detail_t mode) { int row = 0, col = 0; int ex_width = 0, ex_offset, ex_offset_ctr; object_type *o_ptr = (object_type *) object; char o_name[160]; char tmp_val[80]; bool in_term; byte attr = proc_list_color_hack(o_ptr); /* Highlight */ if (cursor) attr = get_color(attr, ATTR_HIGH, 1); in_term = (mode & OLIST_WINDOW) ? TRUE : FALSE; /* Object name */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Width of extra fields */ if (mode & OLIST_WEIGHT) ex_width += 9; if (mode & OLIST_PRICE) ex_width += 9; if (mode & OLIST_FAIL) ex_width += 10; /* Determine beginning row and column */ if (in_term) { /* Term window */ row = offset; col = 0; } else { /* Main window */ row = 1; col = Term->wid - 3 - max_len - ex_width; col = MIN(col, COL_MAP + tile_width); if (col < 3) col = 0; } /* Column offset of the first extra field */ ex_offset = MIN(max_len, (size_t) (Term->wid - 1 - ex_width - col)); /* Clear the line */ prt("", row + onum, MAX(col - 2, 0)); /* Print the label */ put_str(label, row + onum, col); /* Print the object */ if (o_ptr != NULL) { /* Limit object name */ if (strlen(label) + strlen(o_name) > (size_t) ex_offset) { int truncate = ex_offset - strlen(label); if (truncate < 0) truncate = 0; if ((size_t) truncate > sizeof(o_name) - 1) truncate = sizeof(o_name) - 1; o_name[truncate] = '\0'; } /* Object name */ c_put_str(attr, o_name, row + onum, col + strlen(label)); /* Extra fields */ ex_offset_ctr = ex_offset; if (mode & OLIST_PRICE) { int price = price_item(o_ptr, TRUE, o_ptr->number); strnfmt(tmp_val, sizeof(tmp_val), "%6d au", price); put_str(tmp_val, row + onum, col + ex_offset_ctr); ex_offset_ctr += 9; } if (mode & OLIST_FAIL) { int fail = (9 + get_use_device_chance(o_ptr)) / 10; if (object_aware_p(o_ptr)) strnfmt(tmp_val, sizeof(tmp_val), "%4d%% fail", fail); else my_strcpy(tmp_val, " ? fail", sizeof(tmp_val)); put_str(tmp_val, row + onum, col + ex_offset_ctr); ex_offset_ctr += 10; } if (mode & OLIST_WEIGHT) { int weight = o_ptr->weight * o_ptr->number; strnfmt(tmp_val, sizeof(tmp_val), "%4d.%1d lb", weight / 10, weight % 10); put_str(tmp_val, row + onum, col + ex_offset_ctr); ex_offset_ctr += 9; } } }
/* * Quaff a potion (from the pack or the floor) */ void do_cmd_quaff_potion(void) { int item, lev; bool ident; object_type *o_ptr; cptr q, s; /* Restrict choices to potions */ item_tester_tval = TV_POTION; /* Get an item */ q = "Quaff which potion? "; s = "You have no potions to quaff."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Sound */ sound(MSG_QUAFF); /* Take a turn */ p_ptr->energy_use = 100; /* Not identified yet */ ident = FALSE; /* Object level */ lev = k_info[o_ptr->k_idx].level; /* Quaff the potion */ use_object(o_ptr, &ident); /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* The item has been tried */ object_tried(o_ptr); /* An identification was made */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); } /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP); /* Destroy a potion in the pack */ if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Destroy a potion on the floor */ else { floor_item_increase(0 - item, -1); floor_item_describe(0 - item); floor_item_optimize(0 - item); } }
/* * Eat some food (from the pack or floor) */ void do_cmd_eat_food(void) { int item, ident, lev; /* Must be true to let us cancel */ bool cancel = TRUE; object_type *o_ptr; cptr q, s; int power; /* Restrict choices to food */ item_tester_tval = TV_FOOD; /* Get an item */ q = "Eat which item? "; s = "You have nothing to eat."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR | USE_FEATU))) return; /* Get the feature */ if (item >= INVEN_TOTAL+1) { object_type object_type_body; o_ptr = &object_type_body; if (!make_feat(o_ptr, cave_feat[p_ptr->py][p_ptr->px])) return; } /* Get the item (in the pack) */ else if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Sound */ sound(MSG_EAT); /* Take a (partial) turn */ if ((variant_fast_floor) && (item < 0)) p_ptr->energy_use = 50; else if ((variant_fast_equip) && (item >= INVEN_WIELD)) p_ptr->energy_use = 50; else p_ptr->energy_use = 100; /* Identity not known yet */ ident = FALSE; /* Object level */ lev = k_info[o_ptr->k_idx].level; /* Get food effect */ get_spell(&power, "use", o_ptr, FALSE); /* Paranoia */ if (power < 0) return; /* Apply food effect */ if (process_spell_eaten(power,0,&cancel)) ident = TRUE; /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* We have tried it */ object_tried(o_ptr); /* The player is now aware of the object */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev); }
/* * Read a scroll (from the pack or floor). * * Certain scrolls can be "aborted" without losing the scroll. These * include scrolls with no effects but recharge or identify, which are * cancelled before use. XXX Reading them still takes a turn, though. */ void do_cmd_read_scroll(void) { int item, used_up, lev; bool ident; object_type *o_ptr; cptr q, s; /* Check some conditions */ if (p_ptr->blind) { msg_print("You can't see anything."); return; } if (no_lite()) { msg_print("You have no light to read by."); return; } if (p_ptr->confused) { msg_print("You are too confused!"); return; } /* Restrict choices to scrolls */ item_tester_tval = TV_SCROLL; /* Get an item */ q = "Read which scroll? "; s = "You have no scrolls to read."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Take a turn */ p_ptr->energy_use = 100; /* Not identified yet */ ident = FALSE; /* Object level */ lev = k_info[o_ptr->k_idx].level; /* Read the scroll */ used_up = use_object(o_ptr, &ident); /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* The item was tried */ object_tried(o_ptr); /* An identification was made */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); } /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP); /* Hack -- allow certain scrolls to be "preserved" */ if (!used_up) return; /* Destroy a scroll in the pack */ if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Destroy a scroll on the floor */ else { floor_item_increase(0 - item, -1); floor_item_describe(0 - item); floor_item_optimize(0 - item); } }
static bool zap_rod(object_type *o_ptr, bool *ident) { int chance, dir, lev; /* Get a direction (unless KNOWN not to need it) */ if ((o_ptr->sval >= SV_ROD_MIN_DIRECTION) || !object_aware_p(o_ptr)) { /* Get a direction, allow cancel */ if (!get_aim_dir(&dir)) return FALSE; } /* Take a turn */ p_ptr->energy_use = 100; /* Not identified yet */ *ident = FALSE; /* Extract the item level */ lev = k_info[o_ptr->k_idx].level; /* Base chance of success */ chance = p_ptr->skill_dev; /* Confusion hurts skill */ if (p_ptr->confused) chance = chance / 2; /* High level objects are harder */ chance = chance - ((lev > 50) ? 50 : lev); /* Give everyone a (slight) chance */ if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) { chance = USE_DEVICE; } /* Roll for usage */ if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) { if (flush_failure) flush(); msg_print("You failed to use the rod properly."); return FALSE; } /* Still charging */ if (o_ptr->pval) { if (flush_failure) flush(); msg_print("The rod is still charging."); return FALSE; } /* Sound */ sound(MSG_ZAP); /* Analyze the rod */ switch (o_ptr->sval) { case SV_ROD_DETECT_TRAP: { if (detect_traps()) *ident = TRUE; o_ptr->pval = 50; break; } case SV_ROD_DETECT_DOOR: { if (detect_doors()) *ident = TRUE; if (detect_stairs()) *ident = TRUE; o_ptr->pval = 70; break; } case SV_ROD_IDENTIFY: { *ident = TRUE; if (ident_spell()) o_ptr->pval = 10; break; } case SV_ROD_RECALL: { set_recall(); *ident = TRUE; o_ptr->pval = 60; break; } case SV_ROD_ILLUMINATION: { if (lite_area(damroll(2, 8), 2)) *ident = TRUE; o_ptr->pval = 30; break; } case SV_ROD_MAPPING: { map_area(); *ident = TRUE; o_ptr->pval = 99; break; } case SV_ROD_DETECTION: { detect_all(); *ident = TRUE; o_ptr->pval = 99; break; } case SV_ROD_PROBING: { probing(); *ident = TRUE; o_ptr->pval = 50; break; } case SV_ROD_CURING: { if (set_blind(0)) *ident = TRUE; if (set_poisoned(0)) *ident = TRUE; if (set_confused(0)) *ident = TRUE; if (set_stun(0)) *ident = TRUE; if (set_cut(0)) *ident = TRUE; o_ptr->pval = 999; break; } case SV_ROD_HEALING: { if (hp_player(500)) *ident = TRUE; if (set_stun(0)) *ident = TRUE; if (set_cut(0)) *ident = TRUE; o_ptr->pval = 999; break; } case SV_ROD_RESTORATION: { if (restore_level()) *ident = TRUE; if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_INT)) *ident = TRUE; if (do_res_stat(A_WIS)) *ident = TRUE; if (do_res_stat(A_DEX)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (do_res_stat(A_CHR)) *ident = TRUE; o_ptr->pval = 999; break; } case SV_ROD_SPEED: { if (!p_ptr->fast) { if (set_fast(randint(30) + 15)) *ident = TRUE; } else { (void)set_fast(p_ptr->fast + 5); } o_ptr->pval = 99; break; } case SV_ROD_TELEPORT_AWAY: { if (teleport_monster(dir)) *ident = TRUE; o_ptr->pval = 25; break; } case SV_ROD_DISARMING: { if (disarm_trap(dir)) *ident = TRUE; o_ptr->pval = 30; break; } case SV_ROD_LITE: { msg_print("A line of blue shimmering light appears."); lite_line(dir); *ident = TRUE; o_ptr->pval = 9; break; } case SV_ROD_SLEEP_MONSTER: { if (sleep_monster(dir)) *ident = TRUE; o_ptr->pval = 18; break; } case SV_ROD_SLOW_MONSTER: { if (slow_monster(dir)) *ident = TRUE; o_ptr->pval = 20; break; } case SV_ROD_DRAIN_LIFE: { if (drain_life(dir, 150)) *ident = TRUE; o_ptr->pval = 23; break; } case SV_ROD_POLYMORPH: { if (poly_monster(dir)) *ident = TRUE; o_ptr->pval = 25; break; } case SV_ROD_ACID_BOLT: { fire_bolt_or_beam(10, GF_ACID, dir, damroll(12, 8)); *ident = TRUE; o_ptr->pval = 12; break; } case SV_ROD_ELEC_BOLT: { fire_bolt_or_beam(10, GF_ELEC, dir, damroll(6, 6)); *ident = TRUE; o_ptr->pval = 11; break; } case SV_ROD_FIRE_BOLT: { fire_bolt_or_beam(10, GF_FIRE, dir, damroll(16, 8)); *ident = TRUE; o_ptr->pval = 15; break; } case SV_ROD_COLD_BOLT: { fire_bolt_or_beam(10, GF_COLD, dir, damroll(10, 8)); *ident = TRUE; o_ptr->pval = 13; break; } case SV_ROD_ACID_BALL: { fire_ball(GF_ACID, dir, 120, 2); *ident = TRUE; o_ptr->pval = 27; break; } case SV_ROD_ELEC_BALL: { fire_ball(GF_ELEC, dir, 64, 2); *ident = TRUE; o_ptr->pval = 23; break; } case SV_ROD_FIRE_BALL: { fire_ball(GF_FIRE, dir, 144, 2); *ident = TRUE; o_ptr->pval = 30; break; } case SV_ROD_COLD_BALL: { fire_ball(GF_COLD, dir, 96, 2); *ident = TRUE; o_ptr->pval = 25; break; } } return TRUE; }
/* * Use a staff * * One charge of one staff disappears. * * Hack -- staffs of identify can be "cancelled". */ void do_cmd_use_staff(void) { int item, chance, lev; bool ident; object_type *o_ptr; bool use_charge; cptr q, s; /* Restrict choices to staves */ item_tester_tval = TV_STAFF; /* Get an item */ q = "Use which staff? "; s = "You have no staff to use."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Mega-Hack -- refuse to use a pile from the ground */ if ((item < 0) && (o_ptr->number > 1)) { msg_print("You must first pick up the staffs."); return; } /* Take a turn */ p_ptr->energy_use = 100; /* Not identified yet */ ident = FALSE; /* Extract the item level */ lev = k_info[o_ptr->k_idx].level; /* Base chance of success */ chance = p_ptr->skill_dev; /* Confusion hurts skill */ if (p_ptr->confused) chance = chance / 2; /* High level objects are harder */ chance = chance - ((lev > 50) ? 50 : lev); /* Give everyone a (slight) chance */ if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) { chance = USE_DEVICE; } /* Roll for usage */ if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) { if (flush_failure) flush(); msg_print("You failed to use the staff properly."); return; } /* Notice empty staffs */ if (o_ptr->pval <= 0) { if (flush_failure) flush(); msg_print("The staff has no charges left."); o_ptr->ident |= (IDENT_EMPTY); p_ptr->notice |= (PN_COMBINE | PN_REORDER); p_ptr->window |= (PW_INVEN); return; } /* Sound */ sound(MSG_ZAP); /* Use the staff */ use_charge = use_object(o_ptr, &ident); /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* Tried the item */ object_tried(o_ptr); /* An identification was made */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); } /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP); /* Hack -- some uses are "free" */ if (!use_charge) return; /* Use a single charge */ o_ptr->pval--; /* XXX Hack -- unstack if necessary */ if ((item >= 0) && (o_ptr->number > 1)) { object_type *i_ptr; object_type object_type_body; /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Restore the charges */ o_ptr->pval++; /* Unstack the used item */ o_ptr->number--; p_ptr->total_weight -= i_ptr->weight; item = inven_carry(i_ptr); /* Message */ msg_print("You unstack your staff."); } /* Describe charges in the pack */ if (item >= 0) { inven_item_charges(item); } /* Describe charges on the floor */ else { floor_item_charges(0 - item); } }
/* * Creates a description of the item "o_ptr", and stores it in "out_val". * * One can choose the "verbosity" of the description, including whether * or not the "number" of items should be described, and how much detail * should be used when describing the item. * * The given "buf" must be 80 chars long to hold the longest possible * description, which can get pretty long, including incriptions, such as: * "no more Maces of Disruption (Defender) (+10,+10) [+5] (+3 to stealth)". * Note that the inscription will be clipped to keep the total description * under size - 1 chars (plus a terminator). * * Note the use of "object_desc_num()" and "object_desc_int()" as * hyper-efficient, portable, versions of some common "sprintf()" commands. * * Note that all ego-items (when known) append an "Ego-Item Name", unless * the item is also an artifact, which should NEVER happen. * * Note that all artifacts (when known) append an "Artifact Name", so we * have special processing for "Specials" (artifact Lites, Rings, Amulets). * The "Specials" never use "modifiers" if they are "known", since they * have special "descriptions", such as "The Necklace of the Dwarves". * * Special Lite's use the "k_info" base-name (Phial, Star, or Arkenstone), * plus the artifact name, just like any other artifact, if known. * * Special Ring's and Amulet's, if not "aware", use the same code as normal * rings and amulets, and if "aware", use the "k_info" base-name (Ring or * Amulet or Necklace). They will NEVER "append" the "k_info" name. But, * they will append the artifact name, just like any artifact, if known. * * None of the Special Rings/Amulets are "EASY_KNOW", though they could be, * at least, those which have no "pluses", such as the three artifact lites. * * Hack -- Display "The One Ring" as "a Plain Gold Ring" until aware. * * If "pref" then a "numeric" prefix will be pre-pended. * * Mode: * 0 -- The Cloak of Death * 1 -- The Cloak of Death [1,+3] * 2 -- The Cloak of Death [1,+3] (+2 to Stealth) * 3 -- The Cloak of Death [1,+3] (+2 to Stealth) {nifty} */ void object_desc(char *buf, const object_type *o_ptr, int pref, int mode, int max) { cptr basenm, modstr; int power; bool aware = FALSE; bool known = FALSE; bool append_name = FALSE; bool show_weapon = FALSE; bool show_armour = FALSE; cptr s; object_type *bow_ptr; /* damage dice, damage sides, damage bonus, energy */ int dd, ds, db, energy_use; int tmul; long avgdam; int len = 0; object_kind *k_ptr = &k_info[o_ptr->k_idx]; monster_race *r_ptr = &r_info[o_ptr->pval]; /* See if the object is "aware" */ if (object_aware_p(o_ptr)) aware = TRUE; /* See if the object is "known" */ if (object_known_p(o_ptr)) known = TRUE; /* Artifacts are not "aware' unless "known" */ if ((FLAG(o_ptr, TR_INSTA_ART)) && !known) aware = FALSE; /* Extract default "base" string */ basenm = get_object_name(o_ptr); /* Assume no "modifier" string */ modstr = ""; /* Empty description */ buf[0] = '\0'; /* Analyze the object */ switch (o_ptr->tval) { case TV_SKELETON: case TV_BOTTLE: case TV_JUNK: case TV_SPIKE: case TV_FLASK: case TV_CHEST: { /* Some objects are easy to describe */ break; } case TV_FIGURINE: case TV_STATUE: { /* Figurines/Statues */ cptr tmp = mon_race_name(r_ptr); char idol_name[512]; if (!FLAG(r_ptr, RF_UNIQUE)) { strnfmt(idol_name, 512, "%s%s", (is_a_vowel(*tmp) ? "an " : "a "), tmp); modstr = idol_name; } else { modstr = tmp; } break; } case TV_SHOT: case TV_BOLT: case TV_ARROW: case TV_BOW: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_DIGGING: { /* Missiles/ Bows/ Weapons */ show_weapon = TRUE; break; } 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: { /* Armour */ show_armour = TRUE; break; } case TV_LITE: { /* Lites (including a few "Specials") */ break; } case TV_AMULET: { /* Amulets (including a few "Specials") */ /* Known artifacts */ if ((FLAG(k_ptr, TR_INSTA_ART)) && aware) break; /* Color the object */ modstr = amulet_adj[o_ptr->sval]; if (aware) append_name = TRUE; if (((plain_descriptions) && (aware)) || (o_ptr->info & OB_STOREB)) basenm = "& Amulet~"; else basenm = "& # Amulet~"; break; } case TV_RING: { /* Rings (including a few "Specials") */ /* Known artifacts */ if ((FLAG(k_ptr, TR_INSTA_ART)) && aware) break; /* Color the object */ modstr = ring_adj[o_ptr->sval]; if (aware) append_name = TRUE; if (((plain_descriptions) && (aware)) || (o_ptr->info & OB_STOREB)) basenm = "& Ring~"; else basenm = "& # Ring~"; /* Hack -- The One Ring */ if (!aware && (o_ptr->sval == SV_RING_POWER)) modstr = "Plain Gold"; break; } case TV_STAFF: { /* Color the object */ modstr = staff_adj[o_ptr->sval]; if (aware) append_name = TRUE; if (((plain_descriptions) && (aware)) || (o_ptr->info & OB_STOREB)) basenm = "& Staff~"; else basenm = "& # Staff~"; break; } case TV_WAND: { /* Color the object */ modstr = wand_adj[o_ptr->sval]; if (aware) append_name = TRUE; if (((plain_descriptions) && (aware)) || (o_ptr->info & OB_STOREB)) basenm = "& Wand~"; else basenm = "& # Wand~"; break; } case TV_ROD: { /* Color the object */ modstr = rod_adj[o_ptr->sval]; if (aware) append_name = TRUE; if (((plain_descriptions) && (aware)) || (o_ptr->info & OB_STOREB)) basenm = "& Rod~"; else basenm = "& # Rod~"; break; } case TV_SCROLL: { /* Color the object */ modstr = scroll_adj[o_ptr->sval]; if (aware) append_name = TRUE; if (((plain_descriptions) && (aware)) || (o_ptr->info & OB_STOREB)) basenm = "& Scroll~"; else basenm = "& Scroll~ titled \"#\""; break; } case TV_POTION: { /* Color the object */ modstr = potion_adj[o_ptr->sval]; if (aware) append_name = TRUE; if (((plain_descriptions) && (aware)) || (o_ptr->info & OB_STOREB)) basenm = "& Potion~"; else basenm = "& # Potion~"; break; } case TV_FOOD: { /* Ordinary food is "boring" */ if (o_ptr->sval >= SV_FOOD_MIN_FOOD) break; /* Color the object */ modstr = food_adj[o_ptr->sval]; if (aware) append_name = TRUE; if (((plain_descriptions) && (aware)) || (o_ptr->info & OB_STOREB)) basenm = "& Mushroom~"; else basenm = "& # Mushroom~"; break; } /*** Magic Books ***/ case TV_LIFE_BOOK: { modstr = basenm; if (mp_ptr->spell_book == TV_LIFE_BOOK) basenm = "& Book~ of Life Magic #"; else basenm = "& Life Spellbook~ #"; break; } case TV_SORCERY_BOOK: { modstr = basenm; if (mp_ptr->spell_book == TV_LIFE_BOOK) basenm = "& Book~ of Sorcery #"; else basenm = "& Sorcery Spellbook~ #"; break; } case TV_NATURE_BOOK: { modstr = basenm; if (mp_ptr->spell_book == TV_LIFE_BOOK) basenm = "& Book~ of Nature Magic #"; else basenm = "& Nature Spellbook~ #"; break; } case TV_CHAOS_BOOK: { modstr = basenm; if (mp_ptr->spell_book == TV_LIFE_BOOK) basenm = "& Book~ of Chaos Magic #"; else basenm = "& Chaos Spellbook~ #"; break; } case TV_DEATH_BOOK: { modstr = basenm; if (mp_ptr->spell_book == TV_LIFE_BOOK) basenm = "& Book~ of Death Magic #"; else basenm = "& Death Spellbook~ #"; break; } case TV_TRUMP_BOOK: { modstr = basenm; if (mp_ptr->spell_book == TV_LIFE_BOOK) basenm = "& Book~ of Trump Magic #"; else basenm = "& Trump Spellbook~ #"; break; } case TV_ARCANE_BOOK: { modstr = basenm; if (mp_ptr->spell_book == TV_LIFE_BOOK) basenm = "& Book~ of Arcane Magic #"; else basenm = "& Arcane Spellbook~ #"; break; } case TV_GOLD: { /* Hack -- Gold/Gems */ strcpy(buf, basenm); return; } default: { /* Used in the "inventory" routine */ strcpy(buf, "(nothing)"); return; } } /* The object "expects" a "number" */ if (basenm[0] == '&') { /* Skip the ampersand (and space) */ s = basenm + 2; /* No prefix */ if (!pref) { /* Nothing */ } /* Hack -- None left */ else if (o_ptr->number <= 0) { strnfcat(buf, max, &len, "no more "); } /* Extract the number */ else if (o_ptr->number > 1) { strnfcat(buf, max, &len, "%d ", o_ptr->number); } /* Hack -- The only one of its kind */ else if (known && (FLAG(o_ptr, TR_INSTA_ART))) { strnfcat(buf, max, &len, "The "); } /* A single one, with a vowel in the modifier */ else if ((*s == '#') && (is_a_vowel(modstr[0]))) { strnfcat(buf, max, &len, "an "); } /* A single one, with a vowel */ else if (is_a_vowel(*s)) { strnfcat(buf, max, &len, "an "); } /* A single one, without a vowel */ else { strnfcat(buf, max, &len, "a "); } } /* Hack -- objects that "never" take an article */ else { /* No ampersand */ s = basenm; /* No pref */ if (!pref) { /* Nothing */ } /* Hack -- all gone */ else if (o_ptr->number <= 0) { strnfcat(buf, max, &len, "no more "); } /* Prefix a number if required */ else if (o_ptr->number > 1) { strnfcat(buf, max, &len, "%d ", o_ptr->number); } /* Hack -- The only one of its kind */ else if (known && (FLAG(o_ptr, TR_INSTA_ART))) { strnfcat(buf, max, &len, "The "); } /* Hack -- single items get no prefix */ else { /* Nothing */ } } /* Copy the string */ while (*s) { /* Pluralizer */ if (*s == '~') { /* Add a plural if needed */ if (o_ptr->number != 1) { /* Get previous character */ char k = s[-1]; /* XXX XXX XXX Mega-Hack */ /* Hack -- "Cutlass-es" and "Torch-es" */ if ((k == 's') || (k == 'h')) { strnfcat(buf, max, &len, "es"); } else { /* Add an 's' */ strnfcat(buf, max, &len, "s"); } } } /* Modifier */ else if (*s == '#') { /* Insert the modifier */ strnfcat(buf, max, &len, "%s", modstr); } /* Normal */ else { /* Copy character */ strnfcat(buf, max, &len, "%c", *s); } s++; } /* Append the "kind name" to the "base name" */ if (append_name) { strnfcat(buf, max, &len, " of %s", get_object_name(o_ptr)); } /* Hack -- Append "Artifact" or "Special" names */ if (known) { if (o_ptr->inscription && strchr(quark_str(o_ptr->inscription), '#')) { /* Find the '#' */ cptr str = strchr(quark_str(o_ptr->inscription), '#'); /* Add the false name */ strnfcat(buf, max, &len, " %s" CLR_DEFAULT, &str[1]); } /* Is it a new artifact or ego item? */ else if (o_ptr->xtra_name) { strnfcat(buf, max, &len, " %s", quark_str(o_ptr->xtra_name)); } } /* No more details wanted */ if (mode < 1) return; /* Hack -- Chests must be described in detail */ if (o_ptr->tval == TV_CHEST) { /* Not searched yet */ if (!known) { /* Nothing */ } /* May be "empty" */ else if (!o_ptr->pval) { strnfcat(buf, max, &len, " (empty)"); } /* May be "disarmed" */ else if (o_ptr->pval < 0) { if (chest_traps[0 - o_ptr->pval]) { strnfcat(buf, max, &len, " (disarmed)"); } else { strnfcat(buf, max, &len, " (unlocked)"); } } /* Describe the traps, if any */ else { /* Describe the traps */ switch (chest_traps[o_ptr->pval]) { case 0: { strnfcat(buf, max, &len, " (Locked)"); break; } case CHEST_LOSE_STR: { strnfcat(buf, max, &len, " (Poison Needle)"); break; } case CHEST_LOSE_CON: { strnfcat(buf, max, &len, " (Poison Needle)"); break; } case CHEST_POISON: { strnfcat(buf, max, &len, " (Gas Trap)"); break; } case CHEST_PARALYZE: { strnfcat(buf, max, &len, " (Gas Trap)"); break; } case CHEST_EXPLODE: { strnfcat(buf, max, &len, " (Explosion Device)"); break; } case CHEST_SUMMON: { strnfcat(buf, max, &len, " (Summoning Runes)"); break; } default: { strnfcat(buf, max, &len, " (Multiple Traps)"); break; } } } } /* Display the item like a weapon */ if (FLAG(o_ptr, TR_SHOW_MODS)) show_weapon = TRUE; /* Display the item like a weapon */ if (o_ptr->to_h && o_ptr->to_d) show_weapon = TRUE; /* Display the item like armour */ if ((o_ptr->ac) && (o_ptr->tval != TV_WAND)) show_armour = TRUE; /* Dump base weapon info */ switch (o_ptr->tval) { case TV_SHOT: case TV_BOLT: case TV_ARROW: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: case TV_DIGGING: { /* Missiles and Weapons */ /* Append a "damage" string */ strnfcat(buf, max, &len, " (%dd%d)", o_ptr->dd, o_ptr->ds); /* All done */ break; } case TV_BOW: { /* Bows get a special "damage string" */ /* Extract the "base power" */ switch (o_ptr->sval) { case SV_SLING: { power = 2; break; } case SV_SHORT_BOW: { power = 2; break; } case SV_LONG_BOW: { if (p_ptr->stat[A_STR].use >= 160) { power = 3; } else { /* hack- weak players cannot use a longbow well */ power = 2; } break; } case SV_LIGHT_XBOW: { power = 4; break; } case SV_HEAVY_XBOW: { power = 5; break; } default: { msgf("Unknown firing multiplier."); power = 0; } } /* Apply the "Extra Might" flag */ if (FLAG(o_ptr, TR_XTRA_MIGHT)) power++; /* Append a special "damage" string */ strnfcat(buf, max, &len, " (x%d)", power); /* All done */ break; } } /* Add the weapon bonuses */ if (known) { /* Show the tohit/todam on request */ if (show_weapon) { strnfcat(buf, max, &len, " (%+d,%+d%%)", o_ptr->to_h, deadliness_calc(o_ptr->to_d) - 100); } /* Show the tohit if needed */ else if (o_ptr->to_h) { strnfcat(buf, max, &len, " (%+d)", o_ptr->to_h); } /* Show the todam if needed */ else if (o_ptr->to_d) { strnfcat(buf, max, &len, " (%+d%%)", o_ptr->to_d * 5); } } bow_ptr = &p_ptr->equipment[EQUIP_BOW]; /* if have a firing weapon + ammo matches bow */ if (bow_ptr->k_idx && (p_ptr->ammo_tval == o_ptr->tval)) { /* See if the bow is "known" - then set damage bonus */ if (object_known_p(bow_ptr)) { db = bow_ptr->to_d; } else { db = 0; } /* effect of player */ db += p_ptr->dis_to_d; /* effect of ammo */ if (known) db += o_ptr->to_d; dd = o_ptr->dd; ds = o_ptr->ds; /* effect of damage dice x2 */ avgdam = avg_dam(db, dd, ds); /* Bow properties */ energy_use = p_ptr->bow_energy; tmul = p_ptr->ammo_mult; /* Get extra "power" from "extra might" */ if (FLAG(p_ptr, TR_XTRA_MIGHT)) tmul++; /* launcher multiplier */ avgdam *= tmul; /* display (shot damage/ avg damage) */ strnfcat(buf, max, &len, " (%d/", avgdam / 200); tmul = p_ptr->num_fire; if (tmul == 0) { strnfcat(buf, max, &len, "0)"); } else { /* calc effects of energy x2 */ avgdam *= (1 + p_ptr->num_fire); /* rescale */ avgdam /= 4 * energy_use; strnfcat(buf, max, &len, "%d)", avgdam); } } /* Add the armor bonuses */ if (known) { /* Show the armor class info */ if (show_armour) { strnfcat(buf, max, &len, " [%d,%+d]", o_ptr->ac, o_ptr->to_a); } /* No base armor, but does increase armor */ else if (o_ptr->to_a) { strnfcat(buf, max, &len, " [%+d]", o_ptr->to_a); } } /* Hack -- always show base armor */ else if (show_armour) { strnfcat(buf, max, &len, " [%d]", o_ptr->ac); } /* No more details wanted */ if (mode < 2) return; /* * Hack -- Wands and Staffs have charges. Make certain how many charges * a stack of staffs really has is clear. -LM- */ if (known && ((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND))) { /* Dump " (N charges)" */ strnfcat(buf, max, &len, " ("); /* Clear explaination for staffs. */ if ((o_ptr->tval == TV_STAFF) && (o_ptr->number > 1)) { strnfcat(buf, max, &len, "%dx ", o_ptr->number); } if (o_ptr->pval == 1) { strnfcat(buf, max, &len, "%d charge)", o_ptr->pval); } else { strnfcat(buf, max, &len, "%d charges)", o_ptr->pval); } } /* Hack -- Rods have a "charging" indicator. Now that stacks of rods may * be in any state of charge or discharge, this now includes a number. -LM- */ else if (o_ptr->tval == TV_ROD) { /* Hack -- Dump " (# charging)" if relevant */ if (o_ptr->timeout) { /* Stacks of rods display an exact count of charging rods. */ if (o_ptr->number > 1) { /* Paranoia. */ if (k_ptr->pval == 0) k_ptr->pval = 1; /* * Find out how many rods are charging, by dividing * current timeout by each rod's maximum timeout. * Ensure that any remainder is rounded up. Display * very discharged stacks as merely fully discharged. */ power = (o_ptr->timeout + (k_ptr->pval - 1)) / k_ptr->pval; if (power > o_ptr->number) power = o_ptr->number; /* Display prettily. */ strnfcat(buf, max, &len, " (%d charging)", power); } /* "one Rod of Perception (1 charging)" would look tacky. */ else { strnfcat(buf, max, &len, " (charging)"); } } } /* Hack -- Process Lanterns/Torches */ else if (o_ptr->tval == TV_LITE) { if (FLAG(o_ptr, TR_LITE)) { /* Hack - tell us when lites of everburning are "empty" */ if ((o_ptr->sval <= SV_LITE_LANTERN) && !o_ptr->timeout) { strnfcat(buf, max, &len, " (empty)"); } } else { /* Hack -- Turns of light for normal lites */ strnfcat(buf, max, &len, " (with %d turns of light)", o_ptr->timeout); } } /* Dump "pval" flags for wearable items */ if (known && (FLAG(o_ptr, TR_PVAL_MASK))) { /* Start the display */ strnfcat(buf, max, &len, " (%+d", o_ptr->pval); /* Do not display the "pval" flags */ if (FLAG(o_ptr, TR_HIDE_TYPE)) { /* Nothing */ } /* Speed */ else if (FLAG(o_ptr, TR_SPEED)) { /* Dump " to speed" */ strnfcat(buf, max, &len, " to speed"); } /* Attack speed */ else if (FLAG(o_ptr, TR_BLOWS)) { if (ABS(o_ptr->pval) == 1) { /* Add " attack" */ strnfcat(buf, max, &len, " attack"); } else { /* Add "attacks" */ strnfcat(buf, max, &len, " attacks"); } } /* Finish the display */ strnfcat(buf, max, &len, ")"); } /* Indicate charging objects, but not rods. */ if (known && o_ptr->timeout && (o_ptr->tval != TV_ROD) && (o_ptr->tval != TV_LITE)) { /* Hack -- Dump " (charging)" if relevant */ strnfcat(buf, max, &len, " (charging)"); } /* No more details wanted */ if (mode < 3) return; /* Use the standard inscription if available */ if (o_ptr->inscription) { cptr tmp = quark_str(o_ptr->inscription); /* Append the inscription */ strnfcat(buf, max, &len, " {"); /* Scan for the '#' character which marks a fake name. */ while(*tmp && (*tmp != '#')) { strnfcat(buf, max, &len, "%c", *tmp); tmp++; } /* Finish the inscription */ strnfcat(buf, max, &len, CLR_DEFAULT "}"); } /* Use the game-generated "feeling" otherwise, if available */ else if (o_ptr->feeling) { /* Append the inscription */ strnfcat(buf, max, &len, " {%s" CLR_DEFAULT "}", game_inscriptions[o_ptr->feeling]); } /* Note "cursed" if the item is known to be cursed */ else if (cursed_p(o_ptr) && (known || (o_ptr->info & (OB_SENSE)))) { /* Append the inscription */ strnfcat(buf, max, &len, " {cursed}"); } /* Mega-Hack -- note empty wands/staffs */ else if (!known && (o_ptr->info & (OB_EMPTY))) { /* Append the inscription */ strnfcat(buf, max, &len, " {empty}"); } /* Note "tried" if the object has been tested unsuccessfully */ else if (!aware && object_tried_p(o_ptr)) { /* Append the inscription */ strnfcat(buf, max, &len, " {tried}"); } /* Note the discount, if any */ else if (o_ptr->discount) { /* Append the inscription */ strnfcat(buf, max, &len, " {%d%% off}", o_ptr->discount); } }
/* * Aim a wand (from the pack or floor). * * Use a single charge from a single item. * Handle "unstacking" in a logical manner. * * For simplicity, you cannot use a stack of items from the * ground. This would require too much nasty code. * * There are no wands which can "destroy" themselves, in the inventory * or on the ground, so we can ignore this possibility. Note that this * required giving "wand of wonder" the ability to ignore destruction * by electric balls. * * All wands can be "cancelled" at the "Direction?" prompt for free. * * Note that the basic "bolt" wands do slightly less damage than the * basic "bolt" rods, but the basic "ball" wands do the same damage * as the basic "ball" rods. */ void do_cmd_aim_wand(void) { int item, lev; bool ident; object_type *o_ptr; cptr q, s; /* Restrict choices to wands */ item_tester_tval = TV_WAND; /* Get an item */ q = "Aim which wand? "; s = "You have no wand to aim."; if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return; /* Get the item (in the pack) */ if (item >= 0) { o_ptr = &inventory[item]; } /* Get the item (on the floor) */ else { o_ptr = &o_list[0 - item]; } /* Mega-Hack -- refuse to aim a pile from the ground */ if ((item < 0) && (o_ptr->number > 1)) { msg_print("You must first pick up the wands."); return; } /* Aim the wand */ if (!use_object(o_ptr, &ident)) return; /* Combine / Reorder the pack (later) */ p_ptr->notice |= (PN_COMBINE | PN_REORDER); /* Mark it as tried */ object_tried(o_ptr); /* Object level */ lev = k_info[o_ptr->k_idx].level; /* Apply identification */ if (ident && !object_aware_p(o_ptr)) { object_aware(o_ptr); gain_exp((lev + (p_ptr->lev / 2)) / p_ptr->lev); } /* Window stuff */ p_ptr->window |= (PW_INVEN | PW_EQUIP); /* Use a single charge */ o_ptr->pval--; /* Hack -- unstack if necessary */ if ((item >= 0) && (o_ptr->number > 1)) { object_type *i_ptr; object_type object_type_body; /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Modify quantity */ i_ptr->number = 1; /* Restore the charges */ o_ptr->pval++; /* Unstack the used item */ o_ptr->number--; p_ptr->total_weight -= i_ptr->weight; item = inven_carry(i_ptr); /* Message */ msg_print("You unstack your wand."); } /* Describe the charges in the pack */ if (item >= 0) { inven_item_charges(item); } /* Describe the charges on the floor */ else { floor_item_charges(0 - item); } }
/* * Creates a description of the item "o_ptr", and stores it in "buf". * * The given "buf" should be at least 80 chars long to hold the longest * possible description, which can get pretty long, including inscriptions, * such as: * "no more Maces of Disruption (Defender) (+10,+10) [+5] (+3 to stealth)". * * Describes item `o_ptr` into buffer `buf` of size `max`. * * ODESC_PREFIX prepends a 'the', 'a' or number * ODESC_BASE results in a base description. * ODESC_COMBAT will add to-hit, to-dam and AC info. * ODESC_EXTRA will add pval/charge/inscription/squelch info. * ODESC_PLURAL will pluralise regardless of the number in the stack. * ODESC_STORE turns off squelch markers, for in-store display. * ODESC_SPOIL treats the object as fully identified. * * Setting 'prefix' to TRUE prepends a 'the', 'a' or the number in the stack, * respectively. * * \returns The number of bytes used of the buffer. */ size_t object_desc(char *buf, size_t max, const object_type *o_ptr, byte mode) { bool prefix = mode & ODESC_PREFIX; bool spoil = (mode & ODESC_SPOIL); size_t end = 0; bool aware; bool known; u32b f1, f2, f3, fn; object_kind *k_ptr = &k_info[o_ptr->k_idx]; /* Extract some flags */ object_flags(o_ptr, &f1, &f2, &f3, &fn); /* See if the object is "aware" */ aware = (object_aware_p(o_ptr) ? TRUE : FALSE); /* See if the object is "known" */ known = (object_known_p(o_ptr) ? TRUE : FALSE); /* Object is in the inventory of a store */ if (o_ptr->ident & IDENT_STORE) { /* Pretend known and aware */ aware = TRUE; known = TRUE; } /* Player has now seen the item * * This code must be exactly here to properly handle objects in * stores (fake assignment to "aware", see above) and unaware objects * in the dungeon. */ if (aware) k_ptr->everseen = TRUE; /* We've seen it at least once now we're aware of it */ if (known && o_ptr->ego_num) e_info[o_ptr->ego_num].everseen = TRUE; /*** Some things get really simple descriptions ***/ if (o_ptr->tval == TV_GOLD) { return strnfmt(buf, max, "%d gold pieces worth of %s", o_ptr->pval, k_name + k_ptr->name); } else if (!o_ptr->tval) { return strnfmt(buf, max, "(nothing)"); } /* Copy the base name to the buffer */ end = obj_desc_name(buf, max, end, o_ptr, prefix, mode, spoil); if (mode & ODESC_COMBAT) { if (o_ptr->tval == TV_CHEST) end = obj_desc_chest(o_ptr, buf, max, end); else if (o_ptr->tval == TV_LIGHT) end = obj_desc_light(o_ptr, buf, max, end); end = obj_desc_combat(o_ptr, buf, max, end, spoil); } if (mode & ODESC_EXTRA) { if (spoil || known) end = obj_desc_pval(o_ptr, buf, max, end); end = obj_desc_charges(o_ptr, buf, max, end); end = obj_desc_inscrip(o_ptr, buf, max, end); } return end; }
static bool zap_rod(object_type *o_ptr, bool *ident) { int chance, dir, lev; bool used_charge = TRUE; object_kind *k_ptr = &k_info[o_ptr->k_idx]; /* Get a direction (unless KNOWN not to need it) */ if ((o_ptr->sval >= SV_ROD_MIN_DIRECTION) || !object_aware_p(o_ptr)) { /* Get a direction, allow cancel */ if (!get_aim_dir(&dir)) return FALSE; } /* Take a turn */ p_ptr->energy_use = 100; /* Not identified yet */ *ident = FALSE; /* Extract the item level */ lev = k_info[o_ptr->k_idx].level; /* Base chance of success */ chance = p_ptr->skill_dev; /* Confusion hurts skill */ if (p_ptr->confused) chance = chance / 2; /* High level objects are harder */ chance = chance - ((lev > 50) ? 50 : lev); /* Give everyone a (slight) chance */ if ((chance < USE_DEVICE) && (rand_int(USE_DEVICE - chance + 1) == 0)) { chance = USE_DEVICE; } /* Roll for usage */ if ((chance < USE_DEVICE) || (randint(chance) < USE_DEVICE)) { if (flush_failure) flush(); msg_print("Вы не смогли использовать жезл."); return FALSE; } /* Still charging? */ if (o_ptr->timeout > (o_ptr->pval - k_ptr->pval)) { if (flush_failure) flush(); if (o_ptr->number == 1) msg_print("Жезл все еще заряжается."); else msg_print("Все жезлы все еще заряжаются."); return FALSE; } /* Sound */ sound(MSG_ZAP); /* Analyze the rod */ switch (o_ptr->sval) { case SV_ROD_DETECT_TRAP: { if (detect_traps()) *ident = TRUE; break; } case SV_ROD_DETECT_DOOR: { if (detect_doors()) *ident = TRUE; if (detect_stairs()) *ident = TRUE; break; } case SV_ROD_IDENTIFY: { *ident = TRUE; if (ident_spell()) used_charge = FALSE; break; } case SV_ROD_RECALL: { set_recall(); *ident = TRUE; break; } case SV_ROD_ILLUMINATION: { if (lite_area(damroll(2, 8), 2)) *ident = TRUE; break; } case SV_ROD_MAPPING: { map_area(); *ident = TRUE; break; } case SV_ROD_DETECTION: { detect_all(); *ident = TRUE; break; } case SV_ROD_PROBING: { probing(); *ident = TRUE; break; } case SV_ROD_CURING: { if (set_blind(0)) *ident = TRUE; if (set_poisoned(0)) *ident = TRUE; if (set_confused(0)) *ident = TRUE; if (set_stun(0)) *ident = TRUE; if (set_cut(0)) *ident = TRUE; break; } case SV_ROD_HEALING: { if (hp_player(500)) *ident = TRUE; if (set_stun(0)) *ident = TRUE; if (set_cut(0)) *ident = TRUE; break; } case SV_ROD_RESTORATION: { if (restore_level()) *ident = TRUE; if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_INT)) *ident = TRUE; if (do_res_stat(A_WIS)) *ident = TRUE; if (do_res_stat(A_DEX)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (do_res_stat(A_CHR)) *ident = TRUE; break; } case SV_ROD_SPEED: { if (!p_ptr->fast) { if (set_fast(randint(30) + 15)) *ident = TRUE; } else { (void)set_fast(p_ptr->fast + 5); } break; } case SV_ROD_TELEPORT_AWAY: { if (teleport_monster(dir)) *ident = TRUE; break; } case SV_ROD_DISARMING: { if (disarm_trap(dir)) *ident = TRUE; break; } case SV_ROD_LITE: { msg_print("Появляется коридор синего мерцающего света."); lite_line(dir); *ident = TRUE; break; } case SV_ROD_SLEEP_MONSTER: { if (sleep_monster(dir)) *ident = TRUE; break; } case SV_ROD_SLOW_MONSTER: { if (slow_monster(dir)) *ident = TRUE; break; } case SV_ROD_DRAIN_LIFE: { if (drain_life(dir, 150)) *ident = TRUE; break; } case SV_ROD_POLYMORPH: { if (poly_monster(dir)) *ident = TRUE; break; } case SV_ROD_ACID_BOLT: { fire_bolt_or_beam(10, GF_ACID, dir, damroll(12, 8)); *ident = TRUE; break; } case SV_ROD_ELEC_BOLT: { fire_bolt_or_beam(10, GF_ELEC, dir, damroll(6, 6)); *ident = TRUE; break; } case SV_ROD_FIRE_BOLT: { fire_bolt_or_beam(10, GF_FIRE, dir, damroll(16, 8)); *ident = TRUE; break; } case SV_ROD_COLD_BOLT: { fire_bolt_or_beam(10, GF_COLD, dir, damroll(10, 8)); *ident = TRUE; break; } case SV_ROD_ACID_BALL: { fire_ball(GF_ACID, dir, 120, 2); *ident = TRUE; break; } case SV_ROD_ELEC_BALL: { fire_ball(GF_ELEC, dir, 64, 2); *ident = TRUE; break; } case SV_ROD_FIRE_BALL: { fire_ball(GF_FIRE, dir, 144, 2); *ident = TRUE; break; } case SV_ROD_COLD_BALL: { fire_ball(GF_COLD, dir, 96, 2); *ident = TRUE; break; } } /* Drain the charge */ if (used_charge) o_ptr->timeout += k_ptr->pval; return TRUE; }