bool begins_with_vowel(QString line) { // Paranoia if (line.isEmpty()) return (FALSE); QChar first = line[0]; return (is_a_vowel(first)); }
/** * Describe an item's origin */ static bool describe_origin(textblock *tb, const struct object *obj, bool terse) { char loot_spot[80]; char name[80]; int origin; const char *dropper = NULL; const char *article; bool unique = false; /* Only give this info in chardumps if wieldable */ if (terse && !obj_can_wear(obj)) return false; /* Set the origin - care needed for mimics */ if ((obj->origin == ORIGIN_DROP_MIMIC) && (obj->mimicking_m_idx != 0)) origin = ORIGIN_FLOOR; else origin = obj->origin; /* Name the place of origin */ if (obj->origin_depth) strnfmt(loot_spot, sizeof(loot_spot), "at %d feet (level %d)", obj->origin_depth * 50, obj->origin_depth); else my_strcpy(loot_spot, "in town", sizeof(loot_spot)); /* Name the monster of origin */ if (obj->origin_race) { dropper = obj->origin_race->name; if (rf_has(obj->origin_race->flags, RF_UNIQUE)) { unique = true; } } else { dropper = "monster lost to history"; } article = is_a_vowel(dropper[0]) ? "an " : "a "; if (unique) my_strcpy(name, dropper, sizeof(name)); else { my_strcpy(name, article, sizeof(name)); my_strcat(name, dropper, sizeof(name)); } /* Print an appropriate description */ switch (origins[origin].args) { case -1: return false; case 0: textblock_append(tb, origins[origin].desc); break; case 1: textblock_append(tb, origins[origin].desc, loot_spot); break; case 2: textblock_append(tb, origins[origin].desc, name, loot_spot); break; } textblock_append(tb, "\n\n"); return true; }
/** * Start to description, indicating number/uniqueness (a, the, no more, 7, etc) */ static size_t obj_desc_name_prefix(char *buf, size_t max, size_t end, const struct object *obj, bool known, const char *basename, const char *modstr, bool terse) { if (obj->number == 0) strnfcat(buf, max, &end, "no more "); else if (obj->number > 1) strnfcat(buf, max, &end, "%d ", obj->number); else if ((object_name_is_visible(obj) || known) && obj->artifact) 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 (!terse) { if (an) strnfcat(buf, max, &end, "an "); else strnfcat(buf, max, &end, "a "); } } return end; }
/** * Describe an item's origin */ static bool describe_origin(textblock *tb, const struct object *obj, bool terse) { char loot_spot[80]; char name[80]; const char *droppee; const char *article; /* Only give this info in chardumps if wieldable */ if (terse && !obj_can_wear(obj)) return FALSE; /* Name the place of origin */ if (obj->origin_depth) strnfmt(loot_spot, sizeof(loot_spot), "at %d feet (level %d)", obj->origin_depth * 50, obj->origin_depth); else my_strcpy(loot_spot, "in town", sizeof(loot_spot)); /* Name the monster of origin */ if (r_info[obj->origin_xtra].ridx) droppee = r_info[obj->origin_xtra].name; else droppee = "monster lost to history"; article = is_a_vowel(droppee[0]) ? "an " : "a "; if (rf_has(r_info[obj->origin_xtra].flags, RF_UNIQUE)) my_strcpy(name, droppee, sizeof(name)); else { my_strcpy(name, article, sizeof(name)); my_strcat(name, droppee, sizeof(name)); } /* Print an appropriate description */ switch (origins[obj->origin].args) { case -1: return FALSE; case 0: textblock_append(tb, origins[obj->origin].desc); break; case 1: textblock_append(tb, origins[obj->origin].desc, loot_spot); break; case 2: textblock_append(tb, origins[obj->origin].desc, name, loot_spot); break; } textblock_append(tb, "\n\n"); return TRUE; }
void mimic_race(int new_race, const char *msg) { int old_race = p_ptr->mimic_form; if (p_ptr->prace != RACE_DOPPELGANGER) return; if (p_ptr->tim_mimic) return; if (new_race == old_race) return; if (msg) msg_print(msg); if (old_race == RACE_HUMAN || old_race == RACE_DEMIGOD) { int i, idx; for (i = 0; i < MAX_DEMIGOD_POWERS; i++) { idx = p_ptr->demigod_power[i]; if (idx >= 0) { mut_unlock(idx); mut_lose(idx); /* Lose the mutation, but not the choice! p_ptr->demigod_power[i] = -1; */ } } } /* Shifting form causes mutations to vanish! */ mut_lose_all(); if (new_race == MIMIC_NONE) msg_print("You resume your true form."); else { race_t *race_ptr = get_race_t_aux(new_race, 0); if (is_a_vowel(race_ptr->name[0])) msg_format("You turn into an %s!", race_ptr->name); else msg_format("You turn into a %s!", race_ptr->name); } p_ptr->mimic_form = new_race; p_ptr->expfact = calc_exp_factor(); check_experience(); if (new_race == RACE_HUMAN || new_race == RACE_DEMIGOD) { get_race_t()->gain_level(p_ptr->lev); /* This is OK ... Just make sure we get to choose racial powers on mimicry */ } if (new_race == RACE_BEASTMAN) { int i; mut_gain_random(mut_good_pred); for (i = 2; i <= p_ptr->lev; i++) { if (one_in_(5)) mut_gain_random(NULL); } } p_ptr->redraw |= (PR_BASIC | PR_STATUS | PR_MAP); p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA); equip_on_change_race(); reset_visuals(); handle_stuff(); }
static bool describe_origin(textblock *tb, const object_type *o_ptr) { char origin_text[80]; if (o_ptr->origin_depth) strnfmt(origin_text, sizeof(origin_text), "%d feet (level %d)", o_ptr->origin_depth * 50, o_ptr->origin_depth); else my_strcpy(origin_text, "town", sizeof(origin_text)); switch (o_ptr->origin) { case ORIGIN_NONE: case ORIGIN_MIXED: case ORIGIN_STOLEN: return FALSE; case ORIGIN_BIRTH: textblock_append(tb, "An inheritance from your family.\n"); break; case ORIGIN_STORE: textblock_append(tb, "Bought from a store.\n"); break; case ORIGIN_FLOOR: textblock_append(tb, "Found lying on the floor %s %s.\n", (o_ptr->origin_depth ? "at" : "in"), origin_text); break; case ORIGIN_PIT: textblock_append(tb, "Found lying on the floor in a pit at %s.\n", origin_text); break; case ORIGIN_VAULT: textblock_append(tb, "Found lying on the floor in a vault at %s.\n", origin_text); break; case ORIGIN_SPECIAL: textblock_append(tb, "Found lying on the floor of a special room at %s.\n", origin_text); break; case ORIGIN_LABYRINTH: textblock_append(tb, "Found lying on the floor of a labyrinth at %s.\n", origin_text); break; case ORIGIN_CAVERN: textblock_append(tb, "Found lying on the floor of a cavern at %s.\n", origin_text); break; case ORIGIN_RUBBLE: textblock_append(tb, "Found under some rubble at %s.\n", origin_text); break; case ORIGIN_DROP: case ORIGIN_DROP_SPECIAL: case ORIGIN_DROP_PIT: case ORIGIN_DROP_VAULT: case ORIGIN_DROP_SUMMON: case ORIGIN_DROP_BREED: case ORIGIN_DROP_POLY: case ORIGIN_DROP_WIZARD: { const char *name; if (r_info[o_ptr->origin_xtra].ridx) name = r_info[o_ptr->origin_xtra].name; else name = "monster lost to history"; textblock_append(tb, "Dropped by "); if (rf_has(r_info[o_ptr->origin_xtra].flags, RF_UNIQUE)) textblock_append(tb, "%s", name); else textblock_append(tb, "%s%s", is_a_vowel(name[0]) ? "an " : "a ", name); textblock_append(tb, " %s %s.\n", (o_ptr->origin_depth ? "at" : "in"), origin_text); break; } case ORIGIN_DROP_UNKNOWN: textblock_append(tb, "Dropped by an unknown monster %s %s.\n", (o_ptr->origin_depth ? "at" : "in"), origin_text); break; case ORIGIN_ACQUIRE: textblock_append(tb, "Conjured forth by magic %s %s.\n", (o_ptr->origin_depth ? "at" : "in"), origin_text); break; case ORIGIN_CHEAT: textblock_append(tb, "Created by debug option.\n"); break; case ORIGIN_CHEST: textblock_append(tb, "Found in a chest from %s.\n", origin_text); break; } textblock_append(tb, "\n"); return TRUE; }
/* * Use W. Sheldon Simms' random name generator algorithm (Markov Chain stylee). * * Generate a random word using the probability tables we built earlier. * Relies on the A2I and I2A macros (and so the ASCII character set) and * is_a_vowel (so the basic 5 English vowels). */ size_t randname_make(randname_type name_type, size_t min, size_t max, char *word_buf, size_t buflen, const char ***sections) { size_t lnum = 0; bool found_word = FALSE; static name_probs lprobs; static randname_type cached_type = RANDNAME_NUM_TYPES; assert(name_type > 0 && name_type < RANDNAME_NUM_TYPES); /* To allow for a terminating character */ assert(buflen > max); /* We cache one set of probabilities, only regenerate when the type changes. It's as good a way as any for now. Frankly, we could probably regenerate every time. */ if (cached_type != name_type) { cptr *wordlist = NULL; wordlist = sections[name_type]; build_prob(lprobs, wordlist); cached_type = name_type; } /* Generate the actual word wanted. */ while (!found_word) { char *cp = word_buf; int c_prev = S_WORD; int c_cur = S_WORD; int tries = 0; bool contains_vowel = FALSE; lnum = 0; /* We start the word again if we run out of space or have had to have 10 goes to find a word that satisfies the minimal conditions. */ while (tries < 10 && lnum <= max && !found_word) { /* Pick the next letter based on a simple weighting of which letters can follow the previous two */ int r; int c_next = 0; assert(c_prev >= 0 && c_prev <= S_WORD); assert(c_cur >= 0 && c_cur <= S_WORD); r = randint0(lprobs[c_prev][c_cur][TOTAL]); while (r >= lprobs[c_prev][c_cur][c_next]) { r -= lprobs[c_prev][c_cur][c_next]; c_next++; } assert(c_next <= E_WORD); assert(c_next >= 0); if (c_next == E_WORD) { /* If we've reached the end, we check if we've met the simple conditions, otherwise have another go at choosing a letter for this position. */ if (lnum >= min && contains_vowel) { *cp = '\0'; found_word = TRUE; } else { tries++; } } else { /* Add the letter to the word and move on. */ *cp = I2A(c_next); if (is_a_vowel(*cp)) contains_vowel = TRUE; cp++; lnum++; assert(c_next <= S_WORD); assert(c_next >= 0); c_prev = c_cur; c_cur = c_next; } } } return lnum; }
/* * 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); } }
//static struct keypress target_set_interactive_aux(int y, int x, int mode) static ui_event target_set_interactive_aux(int y, int x, int mode) { s16b this_o_idx = 0, next_o_idx = 0; const char *s1, *s2, *s3; bool boring; int floor_list[MAX_FLOOR_STACK]; int floor_num; //struct keypress query; ui_event press; char out_val[256]; char coords[20]; const char *name; /* Describe the square location */ coords_desc(coords, sizeof(coords), y, x); /* Repeat forever */ while (1) { /* Paranoia */ press.type = EVT_KBRD; press.key.code = ' '; press.key.mods = 0; /* Assume boring */ boring = TRUE; /* Default */ s1 = "You see "; s2 = ""; s3 = ""; /* The player */ if (cave->m_idx[y][x] < 0) { /* Description */ s1 = "You are "; /* Preposition */ s2 = "on "; } /* Hallucination messes things up */ if (p_ptr->timed[TMD_IMAGE]) { const char *name = "something strange"; /* Display a message */ if (p_ptr->wizard) strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x); else strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); prt(out_val, 0, 0); move_cursor_relative(y, x); //input = inkey_m(); //if ( press.key = inkey(); /* Stop on everything but "return" */ if (press.key.code == KC_ENTER) continue; return press; } /* Actual monsters */ if (cave->m_idx[y][x] > 0) { monster_type *m_ptr = cave_monster_at(cave, y, x); const monster_lore *l_ptr = get_lore(m_ptr->race); /* Visible */ if (m_ptr->ml && !m_ptr->unaware) { bool recall = FALSE; char m_name[80]; /* Not boring */ boring = FALSE; /* Get the monster name ("a kobold") */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND2); /* Hack -- track this monster race */ monster_race_track(m_ptr->race); /* Hack -- health bar for this monster */ health_track(p_ptr, m_ptr); /* Hack -- handle stuff */ handle_stuff(p_ptr); /* Interact */ while (1) { /* Recall */ if (recall) { /* Save screen */ screen_save(); /* Recall on screen */ screen_roff(m_ptr->race, l_ptr); /* Command */ press = inkey_m(); /* Load screen */ screen_load(); } /* Normal */ else { char buf[80]; /* Describe the monster */ look_mon_desc(buf, sizeof(buf), cave->m_idx[y][x]); /* Describe, and prompt for recall */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s (%d:%d).", s1, s2, s3, m_name, buf, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s.", s1, s2, s3, m_name, buf, coords); } prt(out_val, 0, 0); /* Place cursor */ move_cursor_relative(y, x); /* Command */ press = inkey_m(); } /* Normal commands */ if ((press.type == EVT_MOUSE) && (press.mouse.button == 1) && (KEY_GRID_X(press) == x) && (KEY_GRID_Y(press) == y)) recall = !recall; else if ((press.type == EVT_KBRD) && (press.key.code == 'r')) recall = !recall; else break; } if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button == 2) break; /* Sometimes stop at "space" key */ if (press.mouse.button && !(mode & (TARGET_LOOK))) break; } else { /* Stop on everything but "return"/"space" */ if (press.key.code != KC_ENTER && press.key.code != ' ') break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; } /* Take account of gender */ if (rf_has(m_ptr->race->flags, RF_FEMALE)) s1 = "She is "; else if (rf_has(m_ptr->race->flags, RF_MALE)) s1 = "He is "; else s1 = "It is "; /* Use a verb */ s2 = "carrying "; /* Scan all objects being carried */ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) { char o_name[80]; object_type *o_ptr; /* Get the object */ o_ptr = object_byid(this_o_idx); /* Get the next object */ next_o_idx = o_ptr->next_o_idx; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, o_name, coords, y, x); } /* Disabled since monsters now carry their drops else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, o_name, coords); } */ prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button == 2) break; /* Sometimes stop at "space" key */ if (press.mouse.button && !(mode & (TARGET_LOOK))) break; } else { /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; } /* Change the intro */ s2 = "also carrying "; } /* Double break */ if (this_o_idx) break; /* Use a preposition */ s2 = "on "; } } /* Assume not floored */ floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), y, x, 0x0A); /* Scan all marked objects in the grid */ if ((floor_num > 0) && (!(p_ptr->timed[TMD_BLIND]) || (y == p_ptr->py && x == p_ptr->px))) { /* Not boring */ boring = FALSE; track_object(-floor_list[0]); handle_stuff(p_ptr); /* If there is more than one item... */ if (floor_num > 1) while (1) { /* Describe the pile */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s (%d:%d).", s1, s2, s3, floor_num, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s.", s1, s2, s3, floor_num, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); /* Display objects */ if (((press.type == EVT_MOUSE) && (press.mouse.button == 1) && (KEY_GRID_X(press) == x) && (KEY_GRID_Y(press) == y)) || ((press.type == EVT_KBRD) && (press.key.code == 'r'))) { int rdone = 0; int pos; while (!rdone) { /* Save screen */ screen_save(); /* Display */ show_floor(floor_list, floor_num, (OLIST_WEIGHT | OLIST_GOLD)); /* Describe the pile */ prt(out_val, 0, 0); press = inkey_m(); /* Load screen */ screen_load(); if (press.type == EVT_MOUSE) { pos = press.mouse.y-1; } else { pos = press.key.code - 'a'; } if (0 <= pos && pos < floor_num) { track_object(-floor_list[pos]); handle_stuff(p_ptr); continue; } rdone = 1; } /* Now that the user's done with the display loop, let's */ /* the outer loop over again */ continue; } /* Done */ break; } /* Only one object to display */ else { char o_name[80]; /* Get the single object in the list */ object_type *o_ptr = object_byid(floor_list[0]); /* Not boring */ boring = FALSE; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, o_name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, o_name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s1 = "It is "; /* Plurals */ if (o_ptr->number != 1) s1 = "They are "; /* Preposition */ s2 = "on "; } } /* Double break */ if (this_o_idx) break; name = cave_apparent_name(cave, p_ptr, y, x); /* Terrain feature if needed */ if (boring || cave_isinteresting(cave, y, x)) { /* Hack -- handle unknown grids */ /* Pick a prefix */ if (*s2 && cave_isdoor(cave, y, x)) s2 = "in "; /* Pick proper indefinite article */ s3 = (is_a_vowel(name[0])) ? "an " : "a "; /* Hack -- special introduction for store doors */ if (cave_isshop(cave, y, x)) { s3 = "the entrance to the "; } /* Display a message */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button == 2) break; } else { /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; } } /* Stop on everything but "return" */ if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button != 2) break; } else { if (press.key.code != KC_ENTER) break; } } /* Keep going */ return (press); }
bool describe_origin(textblock *tb, const object_type *o_ptr) { char origin_text[80]; if (stage_map[o_ptr->origin_stage][DEPTH]) strnfmt(origin_text, sizeof(origin_text), "%s Level %d", locality_name[stage_map[o_ptr->origin_stage][LOCALITY]], stage_map[o_ptr->origin_stage][DEPTH]); else strnfmt(origin_text, sizeof(origin_text), "%s %s", locality_name[stage_map[o_ptr->origin_stage][LOCALITY]], "Town"); switch (o_ptr->origin) { case ORIGIN_NONE: case ORIGIN_MIXED: return FALSE; case ORIGIN_BIRTH: textblock_append(tb, "An inheritance from your family.\n"); break; case ORIGIN_STORE: textblock_append(tb, "Bought from a store.\n"); break; case ORIGIN_FLOOR: textblock_append(tb, "Found lying on the ground in %s.\n", origin_text); break; case ORIGIN_DROP: { const char *name = r_info[o_ptr->origin_xtra].name; textblock_append(tb, "Dropped by "); if (rf_has(r_info[o_ptr->origin_xtra].flags, RF_UNIQUE)) textblock_append(tb, "%s", name); else textblock_append(tb, "%s%s", is_a_vowel(name[0]) ? "an " : "a ", name); textblock_append(tb, " in %s.\n", origin_text); break; } case ORIGIN_DROP_UNKNOWN: textblock_append(tb, "Dropped by an unknown monster in %s.\n", origin_text); break; case ORIGIN_ACQUIRE: textblock_append(tb, "Conjured forth by magic in %s.\n", origin_text); break; case ORIGIN_CHEAT: textblock_append(tb, "Created by debug option.\n"); break; case ORIGIN_CHEST: textblock_append(tb, "Found in a chest from %s.\n", origin_text); break; } //textblock_append(tb, "\n"); return TRUE; }
/* * 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, byte mode, bool spoil) { object_kind *k_ptr = &k_info[o_ptr->k_idx]; bool known = object_is_known(o_ptr) || (o_ptr->ident & IDENT_STORE) || spoil; bool aware = object_flavor_is_aware(o_ptr) || (o_ptr->ident & IDENT_STORE) || 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 (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 "); } } /* Perfectly balanced throwing weapons are indicated. */ if ((known) && (o_ptr->ident & IDENT_PERFECT_BALANCE)) { strnfcat(buf, max, &end, "Well-balanced "); } /* * 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->art_num) strnfcat(buf, max, &end, " %s", a_info[o_ptr->art_num].name); else if ((o_ptr->ego_num) && (known || spoil)) { strnfcat(buf, max, &end, " %s", e_name + e_info[o_ptr->ego_num].name); } else if (aware && !artifact_p(o_ptr) && (k_ptr->flavor || k_ptr->tval == TV_SCROLL)) strnfcat(buf, max, &end, " of %s", k_name + k_ptr->name); return end; }
int context_menu_cave(struct cave *c, int y, int x, int adjacent, int mx, int my) { menu_type *m; region r; int selected; char *labels; bool allowed = TRUE; int mode = OPT(rogue_like_commands) ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG; unsigned char cmdkey; m = menu_dynamic_new(); if (!m) { return 0; } labels = string_make(lower_case); m->selections = labels; /* Looking has different keys, but we don't have a way to look them up (see cmd-process.c). */ cmdkey = (mode == KEYMAP_MODE_ORIG) ? 'l' : 'x'; menu_dynamic_add_label(m, "Look At", cmdkey, MENU_VALUE_LOOK, labels); if (c->m_idx[y][x]) { /* '/' is used for recall in both keymaps. */ menu_dynamic_add_label(m, "Recall Info", '/', MENU_VALUE_RECALL, labels); } ADD_LABEL("Use Item On", CMD_USE_ANY, MN_ROW_VALID); if (player_can_cast(p_ptr, FALSE)) { ADD_LABEL("Cast On", CMD_CAST, MN_ROW_VALID); } if (adjacent) { ADD_LABEL((c->m_idx[y][x]) ? "Attack" : "Alter", CMD_ALTER, MN_ROW_VALID); if (c->o_idx[y][x]) { s16b o_idx = chest_check(y,x, CHEST_ANY); if (o_idx) { object_type *o_ptr = object_byid(o_idx); if (!squelch_item_ok(o_ptr)) { if (object_is_known(o_ptr)) { if (is_locked_chest(o_ptr)) { ADD_LABEL("Disarm Chest", CMD_DISARM, MN_ROW_VALID); ADD_LABEL("Open Chest", CMD_OPEN, MN_ROW_VALID); } else { ADD_LABEL("Open Disarmed Chest", CMD_OPEN, MN_ROW_VALID); } } else { ADD_LABEL("Open Chest", CMD_OPEN, MN_ROW_VALID); } } } } if (cave_istrap(c, y, x)) { ADD_LABEL("Disarm", CMD_DISARM, MN_ROW_VALID); ADD_LABEL("Jump Onto", CMD_JUMP, MN_ROW_VALID); } if (cave_isopendoor(c, y, x)) { ADD_LABEL("Close", CMD_CLOSE, MN_ROW_VALID); } else if (cave_iscloseddoor(c, y, x)) { ADD_LABEL("Open", CMD_OPEN, MN_ROW_VALID); ADD_LABEL("Lock", CMD_DISARM, MN_ROW_VALID); } else if (cave_isdiggable(c, y, x)) { ADD_LABEL("Tunnel", CMD_TUNNEL, MN_ROW_VALID); } ADD_LABEL("Search", CMD_SEARCH, MN_ROW_VALID); ADD_LABEL("Walk Towards", CMD_WALK, MN_ROW_VALID); } else { /* ',' is used for squelch in rogue keymap, so we'll just swap letters. */ cmdkey = (mode == KEYMAP_MODE_ORIG) ? ',' : '.'; menu_dynamic_add_label(m, "Pathfind To", cmdkey, CMD_PATHFIND, labels); ADD_LABEL("Walk Towards", CMD_WALK, MN_ROW_VALID); ADD_LABEL("Run Towards", CMD_RUN, MN_ROW_VALID); } if (player_can_fire(p_ptr, FALSE)) { ADD_LABEL("Fire On", CMD_FIRE, MN_ROW_VALID); } ADD_LABEL("Throw To", CMD_THROW, MN_ROW_VALID); /* work out display region */ r.width = (int)menu_dynamic_longest_entry(m) + 3 + 2; /* +3 for tag, 2 for pad */ if (mx > Term->wid - r.width - 1) { r.col = Term->wid - r.width - 1; } else { r.col = mx + 1; } r.page_rows = m->count; if (my > Term->hgt - r.page_rows - 1) { if (my - r.page_rows - 1 <= 0) { /* menu has too many items, so put in upper right corner */ r.row = 1; r.col = Term->wid - r.width - 1; } else { r.row = Term->hgt - r.page_rows - 1; } } else { r.row = my + 1; } /* Hack -- no flush needed */ msg_flag = FALSE; screen_save(); menu_layout(m, &r); region_erase_bordered(&r); if (p_ptr->timed[TMD_IMAGE]) { prt("(Enter to select command, ESC to cancel) You see something strange:", 0, 0); } else if (c->m_idx[y][x]) { char m_name[80]; monster_type *m_ptr = cave_monster_at(c, y, x); /* Get the monster name ("a kobold") */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND_VIS); prt(format("(Enter to select command, ESC to cancel) You see %s:", m_name), 0, 0); } else if (c->o_idx[y][x] && !squelch_item_ok(object_byid(c->o_idx[y][x]))) { char o_name[80]; /* Get the single object in the list */ object_type *o_ptr = object_byid(c->o_idx[y][x]); /* Obtain an object description */ object_desc(o_name, sizeof (o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); prt(format("(Enter to select command, ESC to cancel) You see %s:", o_name), 0, 0); } else { /* Feature (apply mimic) */ const char *name = cave_apparent_name(c, p_ptr, y, x); /* Hack -- special introduction for store doors */ if (cave_isshop(cave, y, x)) { prt(format("(Enter to select command, ESC to cancel) You see the entrance to the %s:", name), 0, 0); } else { prt(format("(Enter to select command, ESC to cancel) You see %s %s:", (is_a_vowel(name[0])) ? "an" : "a", name), 0, 0); } } selected = menu_dynamic_select(m); menu_dynamic_free(m); string_free(labels); screen_load(); cmdkey = cmd_lookup_key(selected, mode); /* Check the command to see if it is allowed. */ switch (selected) { case -1: /* User cancelled the menu. */ return 3; case MENU_VALUE_LOOK: case MENU_VALUE_RECALL: case CMD_PATHFIND: allowed = TRUE; break; case CMD_SEARCH: case CMD_ALTER: case CMD_DISARM: case CMD_JUMP: case CMD_CLOSE: case CMD_OPEN: case CMD_TUNNEL: case CMD_WALK: case CMD_RUN: case CMD_CAST: case CMD_FIRE: case CMD_THROW: case CMD_USE_ANY: /* Only check for ^ inscriptions, since we don't have an object selected (if we need one). */ allowed = key_confirm_command(cmdkey); break; default: /* Invalid command; prevent anything from happening. */ bell("Invalid context menu command."); allowed = FALSE; break; } if (!allowed) return 1; /* Perform the command. */ switch (selected) { case MENU_VALUE_LOOK: /* look at the spot */ if (target_set_interactive(TARGET_LOOK, x, y)) { msg("Target Selected."); } break; case MENU_VALUE_RECALL: { /* recall monster Info */ monster_type *m_ptr = cave_monster_at(c, y, x); if (m_ptr) { monster_lore *lore = get_lore(m_ptr->race); lore_show_interactive(m_ptr->race, lore); } } break; case CMD_SEARCH: cmd_insert(selected); break; case CMD_PATHFIND: cmd_insert(selected); cmd_set_arg_point(cmd_get_top(), 0, x, y); break; case CMD_ALTER: case CMD_DISARM: case CMD_JUMP: case CMD_CLOSE: case CMD_OPEN: case CMD_TUNNEL: case CMD_WALK: case CMD_RUN: cmd_insert(selected); cmd_set_arg_direction(cmd_get_top(), 0, coords_to_dir(y,x)); break; case CMD_CAST: if (textui_obj_cast_ret() >= 0) { cmd_set_arg_target(cmd_get_top(), 1, DIR_TARGET); } break; case CMD_FIRE: case CMD_THROW: case CMD_USE_ANY: cmd_insert(selected); cmd_set_arg_target(cmd_get_top(), 1, DIR_TARGET); break; default: break; } return 1; }
bool describe_origin(textblock * tb, const object_type * o_ptr) { char origin_text[80]; /* Format location of origin */ if (stage_map[o_ptr->origin_stage][DEPTH]) strnfmt(origin_text, sizeof(origin_text), "%s Level %d", locality_name[stage_map[o_ptr->origin_stage][LOCALITY]], stage_map[o_ptr->origin_stage][DEPTH]); else strnfmt(origin_text, sizeof(origin_text), "%s %s", locality_name[stage_map[o_ptr->origin_stage][LOCALITY]], "Town"); switch (o_ptr->origin) { case ORIGIN_NONE: case ORIGIN_MIXED: return FALSE; case ORIGIN_BIRTH: textblock_append(tb, "An inheritance from your family.\n"); break; case ORIGIN_STORE: textblock_append(tb, "Bought from a store in %s.\n", origin_text); break; case ORIGIN_FLOOR: textblock_append(tb, "Found lying on the ground in %s.\n", origin_text); break; case ORIGIN_DROP: { const char *name = r_info[o_ptr->origin_xtra].name; textblock_append(tb, "Dropped by "); if (rf_has(r_info[o_ptr->origin_xtra].flags, RF_UNIQUE) && !rf_has(r_info[o_ptr->origin_xtra].flags, RF_PLAYER_GHOST)) textblock_append(tb, "%s", name); else textblock_append(tb, "%s%s", is_a_vowel(name[0]) ? "an " : "a ", name); textblock_append(tb, " in %s.\n", origin_text); break; } case ORIGIN_DROP_UNKNOWN: textblock_append(tb, "Dropped by an unknown monster in %s.\n", origin_text); break; case ORIGIN_ACQUIRE: textblock_append(tb, "Conjured forth by magic in %s.\n", origin_text); break; case ORIGIN_CHEAT: textblock_append(tb, "Created by debug option.\n"); break; case ORIGIN_CHEST: //if (o_ptr->origin_xtra) if (0) { /* Add in when player ghost issues are fixed */ const char *name = r_info[o_ptr->origin_xtra].name; textblock_append(tb, "Found in a chest dropped by "); if (rf_has(r_info[o_ptr->origin_xtra].flags, RF_UNIQUE) && !rf_has(r_info[o_ptr->origin_xtra].flags, RF_PLAYER_GHOST)) textblock_append(tb, "%s", name); else textblock_append(tb, "%s%s", is_a_vowel(name[0]) ? "an " : "a ", name); textblock_append(tb, " in %s.\n", origin_text); break; } textblock_append(tb, "Found in a chest from %s.\n", origin_text); break; case ORIGIN_RUBBLE: textblock_append(tb, "Found under some rubble in %s.\n", origin_text); break; case ORIGIN_VAULT: textblock_append(tb, "Found in a vault in %s.\n", origin_text); break; case ORIGIN_CHAOS: textblock_append(tb, "Created by the forces of chaos in %s.\n"); break; } return TRUE; }
static void describe_monster_drop(const monster_race *r_ptr, const monster_lore *l_ptr) { bool sin = FALSE; bool plu = TRUE; int n; cptr p; int msex = 0; int vn; cptr vp[64]; /* Extract a gender (if applicable) */ if (r_ptr->flags1 & RF1_FEMALE) msex = 2; else if (r_ptr->flags1 & RF1_MALE) msex = 1; /* Drops gold and/or items */ if (l_ptr->drop_gold || l_ptr->drop_item) { /* Count maximum drop */ n = MAX(l_ptr->drop_gold, l_ptr->drop_item); /* Intro */ text_out(format("%^s may carry", wd_he[msex])); /* One drop (may need an "n") */ if (n == 1) { text_out(" a"); sin = TRUE; plu = FALSE; } /* Two drops */ else if (n == 2) { text_out(" one or two"); } /* Many drops */ else { text_out(format(" up to %d", n)); } /* Great */ if (l_ptr->flags1 & RF1_DROP_GREAT) { p = " exceptional "; } /* Good (no "n" needed) */ else if (l_ptr->flags1 & RF1_DROP_GOOD) { p = " good "; sin = FALSE; } /* Okay */ else { p = " "; } /* Collect special abilities. */ vn = 0; /* Objects */ if (l_ptr->drop_item) { if (l_ptr->flags8 & (RF8_DROP_CHEST)) vp[vn++] = "chest"; if (l_ptr->flags8 & (RF8_DROP_WEAPON)) vp[vn++] = "weapon"; if (l_ptr->flags8 & (RF8_DROP_MISSILE)) vp[vn++] = "missile weapon"; if (l_ptr->flags8 & (RF8_DROP_ARMOR)) vp[vn++] = "armour"; if (l_ptr->flags8 & (RF8_DROP_CLOTHES)) vp[vn++] = "garment"; if (l_ptr->flags8 & (RF8_DROP_TOOL)) vp[vn++] = "tool"; if (l_ptr->flags8 & (RF8_DROP_LITE)) vp[vn++] = "lite"; if (l_ptr->flags8 & (RF8_DROP_JEWELRY)) vp[vn++] = "adornment"; if (l_ptr->flags8 & (RF8_DROP_RSW)) vp[vn++] = "magical device"; if (l_ptr->flags8 & (RF8_DROP_WRITING)) vp[vn++] = "written item"; if (l_ptr->flags8 & (RF8_DROP_MUSIC)) vp[vn++] = "musical item"; if (l_ptr->flags8 & (RF8_DROP_POTION)) vp[vn++] = "potion"; if (l_ptr->flags8 & (RF8_DROP_FOOD)) vp[vn++] = "edible item"; if (l_ptr->flags8 & (RF8_DROP_JUNK)) vp[vn++] = "junk item"; if (l_ptr->flags9 & (RF9_DROP_ESSENCE)) vp[vn++] = "essence"; /* Only drop mushrooms? */ if (l_ptr->flags9 & (RF9_DROP_MUSHROOM)) { vn = 0; vp[vn++] = "mushroom"; } if (!vn) vp[vn++] = "special object"; } /* Treasures */ if (l_ptr->drop_gold) { /* Dump "treasure(s)" */ if (l_ptr->flags9 & (RF9_DROP_MINERAL)) { int coin_type = get_coin_type(r_ptr); switch (k_info[coin_type + OBJ_GOLD_LIST].tval) { case TV_GOLD: vp[vn++] = "precious metal"; break; case TV_GEMS: vp[vn++] = "gem stone"; break; } } else vp[vn++] = "treasure"; } /* Fix up singular */ if ((vn) && !(is_a_vowel(vp[0][0]))) sin = FALSE; /* Describe special abilities. */ if (vn) { /* Scan */ for (n = 0; n < vn; n++) { /* Intro */ if (n == 0) { if (sin) text_out("n"); text_out(p); } else if (n < vn-1) text_out(", "); else text_out(" or "); /* Dump */ text_out(format("%s%s", vp[n], (plu ? "s" : ""))); } /* End */ text_out(". "); } } }
/** * Builds a string describing a monster in some way. * * We can correctly describe monsters based on their visibility. * We can force all monsters to be treated as visible or invisible. * We can build nominatives, objectives, possessives, or reflexives. * We can selectively pronominalize hidden, visible, or all monsters. * We can use definite or indefinite descriptions for hidden monsters. * We can use definite or indefinite descriptions for visible monsters. * * Pronominalization involves the gender whenever possible and allowed, * so that by cleverly requesting pronominalization / visibility, you * can get messages like "You hit someone. She screams in agony!". * * Reflexives are acquired by requesting Objective plus Possessive. * * I am assuming that no monster name is more than 65 characters long, * so that "char desc[80];" is sufficiently large for any result, even * when the "offscreen" notation is added. * * Note that the "possessive" for certain unique monsters will look * really silly, as in "Morgoth, King of Darkness's". We should * perhaps add a flag to "remove" any "descriptives" in the name. * * Note that "offscreen" monsters will get a special "(offscreen)" * notation in their name if they are visible but offscreen. This * may look silly with possessives, as in "the rat's (offscreen)". * Perhaps the "offscreen" descriptor should be abbreviated. * * Mode Flags: * 0x01 --> Objective (or Reflexive) * 0x02 --> Possessive (or Reflexive) * 0x04 --> Use indefinites for hidden monsters ("something") * 0x08 --> Use indefinites for visible monsters ("a kobold") * 0x10 --> Pronominalize hidden monsters * 0x20 --> Pronominalize visible monsters * 0x40 --> Assume the monster is hidden * 0x80 --> Assume the monster is visible * 0x100 --> Capitalise monster name * * Useful Modes: * 0x00 --> Full nominative name ("the kobold") or "it" * 0x04 --> Full nominative name ("the kobold") or "something" * 0x80 --> Banishment resistance name ("the kobold") * 0x88 --> Killing name ("a kobold") * 0x22 --> Possessive, genderized if visable ("his") or "its" * 0x23 --> Reflexive, genderized if visable ("himself") or "itself" */ void monster_desc(char *desc, size_t max, const struct monster *mon, int mode) { const char *choice; bool seen, use_pronoun; assert(mon); /* Can we "see" it (forced, or not hidden + visible) */ seen = ((mode & (MDESC_SHOW)) || (!(mode & (MDESC_HIDE)) && mflag_has(mon->mflag, MFLAG_VISIBLE))); /* Sexed Pronouns (seen and forced, or unseen and allowed) */ use_pronoun = ((seen && (mode & (MDESC_PRO_VIS))) || (!seen && (mode & (MDESC_PRO_HID)))); /* First, try using pronouns, or describing hidden monsters */ if (!seen || use_pronoun) { /* an encoding of the monster "sex" */ int msex = 0x00; /* Extract the gender (if applicable) */ if (rf_has(mon->race->flags, RF_FEMALE)) msex = 0x20; else if (rf_has(mon->race->flags, RF_MALE)) msex = 0x10; /* Ignore the gender (if desired) */ if (!mon || !use_pronoun) msex = 0x00; /* Assume simple result */ choice = "it"; /* Brute force: split on the possibilities */ switch (msex + (mode & 0x07)) { /* Neuter, or unknown */ case 0x00: choice = "it"; break; case 0x01: choice = "it"; break; case 0x02: choice = "its"; break; case 0x03: choice = "itself"; break; case 0x04: choice = "something"; break; case 0x05: choice = "something"; break; case 0x06: choice = "something's"; break; case 0x07: choice = "itself"; break; /* Male (assume human if vague) */ case 0x10: choice = "he"; break; case 0x11: choice = "him"; break; case 0x12: choice = "his"; break; case 0x13: choice = "himself"; break; case 0x14: choice = "someone"; break; case 0x15: choice = "someone"; break; case 0x16: choice = "someone's"; break; case 0x17: choice = "himself"; break; /* Female (assume human if vague) */ case 0x20: choice = "she"; break; case 0x21: choice = "her"; break; case 0x22: choice = "her"; break; case 0x23: choice = "herself"; break; case 0x24: choice = "someone"; break; case 0x25: choice = "someone"; break; case 0x26: choice = "someone's"; break; case 0x27: choice = "herself"; break; } /* Copy the result */ my_strcpy(desc, choice, max); } else if ((mode & MDESC_POSS) && (mode & MDESC_OBJE)) { /* The monster is visible, so use its gender */ if (rf_has(mon->race->flags, RF_FEMALE)) my_strcpy(desc, "herself", max); else if (rf_has(mon->race->flags, RF_MALE)) my_strcpy(desc, "himself", max); else my_strcpy(desc, "itself", max); } else { /* Unique, indefinite or definite */ if (rf_has(mon->race->flags, RF_UNIQUE)) { /* Start with the name (thus nominative and objective) */ my_strcpy(desc, mon->race->name, max); } else if (mode & MDESC_IND_VIS) { /* XXX Check plurality for "some" */ /* Indefinite monsters need an indefinite article */ my_strcpy(desc, is_a_vowel(mon->race->name[0]) ? "an " : "a ", max); my_strcat(desc, mon->race->name, max); } else { /* Definite monsters need a definite article */ my_strcpy(desc, "the ", max); my_strcat(desc, mon->race->name, max); } /* Handle the Possessive as a special afterthought */ if (mode & MDESC_POSS) { /* XXX Check for trailing "s" */ /* Simply append "apostrophe" and "s" */ my_strcat(desc, "'s", max); } /* Mention "offscreen" monsters XXX XXX */ if (!panel_contains(mon->fy, mon->fx)) { /* Append special notation */ my_strcat(desc, " (offscreen)", max); } } if (mode & MDESC_CAPITAL) my_strcap(desc); }
bool describe_origin(textblock *tb, const object_type *o_ptr) { char origin_text[80]; if (o_ptr->origin_depth) strnfmt(origin_text, sizeof(origin_text), "%d feet (level %d)", o_ptr->origin_depth * 50, o_ptr->origin_depth); else my_strcpy(origin_text, "town", sizeof(origin_text)); switch (o_ptr->origin) { case ORIGIN_NONE: case ORIGIN_MIXED: return FALSE; case ORIGIN_BIRTH: textblock_append(tb, "An inheritance from your family.\n"); break; case ORIGIN_STORE: textblock_append(tb, "Bought from a store.\n"); break; case ORIGIN_FLOOR: textblock_append(tb, "Found lying on the floor %s %s.\n", (o_ptr->origin_depth ? "at" : "in"), origin_text); break; case ORIGIN_DROP: { const char *name = r_info[o_ptr->origin_xtra].name; textblock_append(tb, "Dropped by "); if (rf_has(r_info[o_ptr->origin_xtra].flags, RF_UNIQUE)) textblock_append(tb, "%s", name); else textblock_append(tb, "%s%s", is_a_vowel(name[0]) ? "an " : "a ", name); textblock_append(tb, " %s %s.\n", (o_ptr->origin_depth ? "at" : "in"), origin_text); break; } case ORIGIN_DROP_UNKNOWN: textblock_append(tb, "Dropped by an unknown monster %s %s.\n", (o_ptr->origin_depth ? "at" : "in"), origin_text); break; case ORIGIN_ACQUIRE: textblock_append(tb, "Conjured forth by magic %s %s.\n", (o_ptr->origin_depth ? "at" : "in"), origin_text); break; case ORIGIN_CHEAT: textblock_append(tb, "Created by debug option.\n"); break; case ORIGIN_CHEST: textblock_append(tb, "Found in a chest from %s.\n", origin_text); break; } textblock_append(tb, "\n"); return TRUE; }
/** * Examine a grid, return a keypress. * * The "mode" argument contains the "TARGET_LOOK" bit flag, which * indicates that the "space" key should scan through the contents * of the grid, instead of simply returning immediately. This lets * the "look" command get complete information, without making the * "target" command annoying. * * The "info" argument contains the "commands" which should be shown * inside the "[xxx]" text. This string must never be empty, or grids * containing monsters will be displayed with an extra comma. * * Note that if a monster is in the grid, we update both the monster * recall info and the health bar info to track that monster. * * This function correctly handles multiple objects per grid, and objects * and terrain features in the same grid, though the latter never happens. * * This function must handle blindness/hallucination. */ static ui_event target_set_interactive_aux(int y, int x, int mode) { struct object *obj = NULL; const char *s1, *s2, *s3; bool boring; int floor_max = z_info->floor_size; struct object **floor_list = mem_zalloc(floor_max * sizeof(*floor_list)); int floor_num; ui_event press; char out_val[TARGET_OUT_VAL_SIZE]; char coords[20]; const char *name; /* Describe the square location */ coords_desc(coords, sizeof(coords), y, x); /* Repeat forever */ while (1) { /* Paranoia */ press.type = EVT_KBRD; press.key.code = ' '; press.key.mods = 0; /* Assume boring */ boring = TRUE; /* Default */ s1 = "You see "; s2 = ""; s3 = ""; /* The player */ if (cave->squares[y][x].mon < 0) { /* Description */ s1 = "You are "; /* Preposition */ s2 = "on "; } /* Hallucination messes things up */ if (player->timed[TMD_IMAGE]) { const char *name = "something strange"; /* Display a message */ if (player->wizard) strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, name, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); else strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); prt(out_val, 0, 0); move_cursor_relative(y, x); press.key = inkey(); /* Stop on everything but "return" */ if (press.key.code == KC_ENTER) continue; mem_free(floor_list); return press; } /* Actual monsters */ if (cave->squares[y][x].mon > 0) { monster_type *m_ptr = square_monster(cave, y, x); const monster_lore *l_ptr = get_lore(m_ptr->race); /* Visible */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE) && !mflag_has(m_ptr->mflag, MFLAG_UNAWARE)) { bool recall = FALSE; char m_name[80]; /* Not boring */ boring = FALSE; /* Get the monster name ("a kobold") */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND_VIS); /* Hack -- track this monster race */ monster_race_track(player->upkeep, m_ptr->race); /* Hack -- health bar for this monster */ health_track(player->upkeep, m_ptr); /* Hack -- handle stuff */ handle_stuff(player); /* Interact */ while (1) { /* Recall or target */ if (recall) { lore_show_interactive(m_ptr->race, l_ptr); press = inkey_m(); } else { char buf[80]; /* Describe the monster */ look_mon_desc(buf, sizeof(buf), cave->squares[y][x].mon); /* Describe, and prompt for recall */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, m_name, buf, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s.", s1, s2, s3, m_name, buf, coords); } prt(out_val, 0, 0); /* Place cursor */ move_cursor_relative(y, x); /* Command */ press = inkey_m(); } /* Normal commands */ if ((press.type == EVT_MOUSE) && (press.mouse.button == 1) && (KEY_GRID_X(press) == x) && (KEY_GRID_Y(press) == y)) recall = !recall; else if ((press.type == EVT_KBRD) && (press.key.code == 'r')) recall = !recall; else break; } if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button == 2) break; /* Sometimes stop at "space" key */ if (press.mouse.button && !(mode & (TARGET_LOOK))) break; } else { /* Stop on everything but "return"/"space" */ if (press.key.code != KC_ENTER && press.key.code != ' ') break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; } /* Take account of gender */ if (rf_has(m_ptr->race->flags, RF_FEMALE)) s1 = "She is "; else if (rf_has(m_ptr->race->flags, RF_MALE)) s1 = "He is "; else s1 = "It is "; /* Use a verb */ s2 = "carrying "; /* Scan all objects being carried */ for (obj = m_ptr->held_obj; obj; obj = obj->next) { char o_name[80]; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, o_name, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button == 2) break; /* Sometimes stop at "space" key */ if (press.mouse.button && !(mode & (TARGET_LOOK))) break; } else { /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; } /* Change the intro */ s2 = "also carrying "; } /* Double break */ if (obj) break; /* Use a preposition */ s2 = "on "; } } /* A trap */ if (square_isvisibletrap(cave, y, x)) { struct trap *trap = cave->squares[y][x].trap; /* Not boring */ boring = FALSE; /* Interact */ while (1) { /* Change the intro */ if (cave->squares[y][x].mon < 0) { s1 = "You are "; s2 = "on "; } else { s1 = "You see "; s2 = ""; } /* Pick proper indefinite article */ s3 = (is_a_vowel(trap->kind->desc[0])) ? "an " : "a "; /* Describe, and prompt for recall */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, trap->kind->name, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, trap->kind->desc, coords); } prt(out_val, 0, 0); /* Place cursor */ move_cursor_relative(y, x); /* Command */ press = inkey_m(); /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; } } /* Double break */ if (square_isvisibletrap(cave, y, x)) break; /* Assume not floored */ floor_num = scan_floor(floor_list, floor_max, y, x, 0x0A, NULL); /* Scan all marked objects in the grid */ if ((floor_num > 0) && (!(player->timed[TMD_BLIND]) || (y == player->py && x == player->px))) { /* Not boring */ boring = FALSE; track_object(player->upkeep, floor_list[0]); handle_stuff(player); /* If there is more than one item... */ if (floor_num > 1) while (1) { /* Describe the pile */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, floor_num, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } else { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s.", s1, s2, s3, floor_num, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); /* Display objects */ if (((press.type == EVT_MOUSE) && (press.mouse.button == 1) && (KEY_GRID_X(press) == x) && (KEY_GRID_Y(press) == y)) || ((press.type == EVT_KBRD) && (press.key.code == 'r'))) { int rdone = 0; int pos; while (!rdone) { /* Save screen */ screen_save(); /* Display */ show_floor(floor_list, floor_num, (OLIST_WEIGHT | OLIST_GOLD), NULL); /* Describe the pile */ prt(out_val, 0, 0); press = inkey_m(); /* Load screen */ screen_load(); if (press.type == EVT_MOUSE) { pos = press.mouse.y-1; } else { pos = press.key.code - 'a'; } if (0 <= pos && pos < floor_num) { track_object(player->upkeep, floor_list[pos]); handle_stuff(player); continue; } rdone = 1; } /* Now that the user's done with the display loop, * let's do the outer loop over again */ continue; } /* Done */ break; } /* Only one object to display */ else { /* Get the single object in the list */ struct object *obj = floor_list[0]; /* Allow user to recall an object */ press = target_recall_loop_object(obj, y, x, out_val, s1, s2, s3, coords); /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; /* Sometimes stop at "space" key */ if ((press.key.code == ' ') && !(mode & (TARGET_LOOK))) break; /* Plurals */ s1 = VERB_AGREEMENT(obj->number, "It is ", "They are "); /* Preposition */ s2 = "on "; } } /* Double break */ if (obj) break; name = square_apparent_name(cave, player, y, x); /* Terrain feature if needed */ if (boring || square_isinteresting(cave, y, x)) { /* Hack -- handle unknown grids */ /* Pick a prefix */ if (*s2 && square_isdoor(cave, y, x)) s2 = "in "; /* Pick proper indefinite article */ s3 = (is_a_vowel(name[0])) ? "an " : "a "; /* Hack -- special introduction for store doors */ if (square_isshop(cave, y, x)) s3 = "the entrance to the "; /* Display a message */ if (player->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d, cost=%d, when=%d).", s1, s2, s3, name, coords, y, x, (int)cave->squares[y][x].cost, (int)cave->squares[y][x].when); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); press = inkey_m(); if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button == 2) break; } else { /* Stop on everything but "return"/"space" */ if ((press.key.code != KC_ENTER) && (press.key.code != ' ')) break; } } /* Stop on everything but "return" */ if (press.type == EVT_MOUSE) { /* Stop on right click */ if (press.mouse.button != 2) break; } else { if (press.key.code != KC_ENTER) break; } } mem_free(floor_list); /* Keep going */ return (press); }
/* * 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 */ }
/* * Examine a grid, return a keypress. * * The "mode" argument contains the "TARGET_LOOK" bit flag, which * indicates that the "space" key should scan through the contents * of the grid, instead of simply returning immediately. This lets * the "look" command get complete information, without making the * "target" command annoying. * * The "info" argument contains the "commands" which should be shown * inside the "[xxx]" text. This string must never be empty, or grids * containing monsters will be displayed with an extra comma. * * Note that if a monster is in the grid, we update both the monster * recall info and the health bar info to track that monster. * * This function correctly handles multiple objects per grid, and objects * and terrain features in the same grid, though the latter never happens. * * This function must handle blindness/hallucination. */ static ui_event_data target_set_interactive_aux(int y, int x, int mode) { s16b this_o_idx = 0, next_o_idx = 0; cptr s1, s2, s3; bool boring; bool floored; int feat; int floor_list[MAX_FLOOR_STACK]; int floor_num; ui_event_data query; char out_val[256]; char coords[20]; /* Describe the square location */ coords_desc(coords, sizeof(coords), y, x); /* Repeat forever */ while (1) { /* Paranoia */ query.key = ' '; /* Assume boring */ boring = TRUE; /* Default */ s1 = "You see "; s2 = ""; s3 = ""; /* The player */ if (cave_m_idx[y][x] < 0) { /* Description */ s1 = "You are "; /* Preposition */ s2 = "on "; } /* Hack -- hallucination */ if (p_ptr->timed[TMD_IMAGE]) { cptr name = "something strange"; /* Display a message */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return" */ if ((query.key != '\n') && (query.key != '\r')) break; /* Repeat forever */ continue; } /* Actual monsters */ if (cave_m_idx[y][x] > 0) { monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; /* Visible */ if (m_ptr->ml) { bool recall = FALSE; char m_name[80]; /* Not boring */ boring = FALSE; /* Get the monster name ("a kobold") */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND2); /* Hack -- track this monster race */ monster_race_track(m_ptr->r_idx); /* Hack -- health bar for this monster */ health_track(cave_m_idx[y][x]); /* Hack -- handle stuff */ handle_stuff(); /* Interact */ while (1) { /* Recall */ if (recall) { /* Save screen */ screen_save(); /* Recall on screen */ screen_roff(m_ptr->r_idx); /* Command */ query = inkey_ex(); /* Load screen */ screen_load(); } /* Normal */ else { char buf[80]; /* Describe the monster */ look_mon_desc(buf, sizeof(buf), cave_m_idx[y][x]); /* Describe, and prompt for recall */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s (%d:%d).", s1, s2, s3, m_name, buf, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s (%s), %s.", s1, s2, s3, m_name, buf, coords); } prt(out_val, 0, 0); /* Place cursor */ move_cursor_relative(y, x); /* Command */ query = inkey_ex(); } /* Normal commands */ if (query.key != 'r') break; /* Toggle recall */ recall = !recall; } /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s1 = "It is "; /* Hack -- take account of gender */ if (rf_has(r_ptr->flags, RF_FEMALE)) s1 = "She is "; else if (rf_has(r_ptr->flags, RF_MALE)) s1 = "He is "; /* Use a preposition */ s2 = "carrying "; /* Scan all objects being carried */ for (this_o_idx = m_ptr->hold_o_idx; this_o_idx; this_o_idx = next_o_idx) { char o_name[80]; object_type *o_ptr; /* Get the object */ o_ptr = &o_list[this_o_idx]; /* Get the next object */ next_o_idx = o_ptr->next_o_idx; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, o_name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, o_name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s2 = "also carrying "; } /* Double break */ if (this_o_idx) break; /* Use a preposition */ s2 = "on "; } } /* Assume not floored */ floored = FALSE; floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), y, x, 0x02); /* Scan all marked objects in the grid */ if ((floor_num > 0) && (!(p_ptr->timed[TMD_BLIND]) || (y == p_ptr->py && x == p_ptr->px))) { /* Not boring */ boring = FALSE; track_object(-floor_list[0]); handle_stuff(); /* If there is more than one item... */ if (floor_num > 1) while (1) { floored = TRUE; /* Describe the pile */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s (%d:%d).", s1, s2, s3, floor_num, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%sa pile of %d objects, %s.", s1, s2, s3, floor_num, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Display objects */ if (query.key == 'r') { int rdone = 0; int pos; while (!rdone) { /* Save screen */ screen_save(); /* Display */ show_floor(floor_list, floor_num, (OLIST_WEIGHT | OLIST_GOLD)); /* Describe the pile */ prt(out_val, 0, 0); query = inkey_ex(); /* Load screen */ screen_load(); pos = query.key - 'a'; if (0 <= pos && pos < floor_num) { track_object(-floor_list[pos]); handle_stuff(); continue; } rdone = 1; } /* Now that the user's done with the display loop, let's */ /* the outer loop over again */ continue; } /* Done */ break; } /* Only one object to display */ else { char o_name[80]; /* Get the single object in the list */ object_type *o_ptr = &o_list[floor_list[0]]; /* Not boring */ boring = FALSE; /* Obtain an object description */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); /* Describe the object */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, o_name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, o_name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; /* Sometimes stop at "space" key */ if ((query.key == ' ') && !(mode & (TARGET_LOOK))) break; /* Change the intro */ s1 = "It is "; /* Plurals */ if (o_ptr->number != 1) s1 = "They are "; /* Preposition */ s2 = "on "; } } /* Double break */ if (this_o_idx) break; /* Feature (apply "mimic") */ feat = f_info[cave_feat[y][x]].mimic; /* Require knowledge about grid, or ability to see grid */ if (!(cave_info[y][x] & (CAVE_MARK)) && !player_can_see_bold(y,x)) { /* Forget feature */ feat = FEAT_NONE; } /* Terrain feature if needed */ if (boring || (feat > FEAT_INVIS)) { cptr name = f_info[feat].name; /* Hack -- handle unknown grids */ if (feat == FEAT_NONE) name = "unknown grid"; /* Pick a prefix */ if (*s2 && (feat >= FEAT_DOOR_HEAD)) s2 = "in "; /* Pick proper indefinite article */ s3 = (is_a_vowel(name[0])) ? "an " : "a "; /* Hack -- special introduction for store doors */ if ((feat >= FEAT_SHOP_HEAD) && (feat <= FEAT_SHOP_TAIL)) { s3 = "the entrance to the "; } /* Display a message */ if (p_ptr->wizard) { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s (%d:%d).", s1, s2, s3, name, coords, y, x); } else { strnfmt(out_val, sizeof(out_val), "%s%s%s%s, %s.", s1, s2, s3, name, coords); } prt(out_val, 0, 0); move_cursor_relative(y, x); query = inkey_ex(); /* Stop on everything but "return"/"space" */ if ((query.key != '\n') && (query.key != '\r') && (query.key != ' ')) break; } /* Stop on everything but "return" */ if ((query.key != '\n') && (query.key != '\r')) break; } /* Keep going */ return (query); }
/* * 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); }