/* * Display the objects in a group. */ static void display_object(int col, int row, bool cursor, int oid) { object_kind *kind = &k_info[oid]; const char *inscrip = get_autoinscription(kind); char o_name[80]; /* Choose a color */ bool aware = (!kind->flavor || kind->aware); byte attr = curs_attrs[(int)aware][(int)cursor]; /* Find graphics bits -- versions of the object_char and object_attr defines */ bool use_flavour = (kind->flavor) && !(aware && kind->tval == TV_SCROLL); byte a = use_flavour ? kind->flavor->x_attr : kind->x_attr; byte c = use_flavour ? kind->flavor->x_char : kind->x_char; /* Display known artifacts differently */ if (of_has(kind->flags, OF_INSTA_ART) && artifact_is_known(get_artifact_from_kind(kind))) get_artifact_display_name(o_name, sizeof(o_name), get_artifact_from_kind(kind)); else object_kind_name(o_name, sizeof(o_name), kind, OPT(cheat_know)); /* If the type is "tried", display that */ if (kind->tried && !aware) my_strcat(o_name, " {tried}", sizeof(o_name)); /* Display the name */ c_prt(attr, o_name, row, col); /* Show squelch status */ if ((aware && kind_is_squelched_aware(kind)) || (!aware && kind_is_squelched_unaware(kind))) c_put_str(attr, "Yes", row, 46); /* Show autoinscription if around */ if (aware && inscrip) c_put_str(TERM_YELLOW, inscrip, row, 55); if (tile_height == 1) { big_pad(76, row, a, c); } }
static bool wiz_create_item_action(menu_type *m, const ui_event *e, int oid) { ui_event ret; menu_type *menu; char buf[80]; object_kind *choice[60]; int n_choices; int i; if (e->type != EVT_SELECT) return TRUE; for (n_choices = 0, i = 1; (n_choices < 60) && (i < z_info->k_max); i++) { object_kind *kind = &k_info[i]; if (kind->tval != oid || of_has(kind->flags, OF_INSTA_ART)) continue; choice[n_choices++] = kind; } screen_save(); clear_from(0); menu = menu_new(MN_SKIN_COLUMNS, &wiz_create_item_submenu); menu->selections = all_letters; object_base_name(buf, sizeof buf, oid, TRUE); menu->title = string_make(format("What kind of %s?", buf)); menu_setpriv(menu, n_choices, choice); menu_layout(menu, &wiz_create_item_area); ret = menu_select(menu, 0, FALSE); screen_load(); string_free((char *)menu->title); return (ret.type == EVT_ESCAPE); }
/* * Describe stat modifications. */ static bool describe_stats(textblock *tb, const object_type *o_ptr, bitflag flags[MAX_PVALS][OF_SIZE], oinfo_detail_t mode) { const char *descs[N_ELEMENTS(pval_flags)]; size_t count, i; bool full = mode & OINFO_FULL; bool dummy = mode & OINFO_DUMMY; bool search = FALSE; if (!o_ptr->num_pvals && !dummy) return FALSE; for (i = 0; i < o_ptr->num_pvals; i++) { count = info_collect(tb, pval_flags, N_ELEMENTS(pval_flags), flags[i], descs); if (count) { if ((object_this_pval_is_visible(o_ptr, i) || full) && !dummy) textblock_append_c(tb, (o_ptr->pval[i] > 0) ? TERM_L_GREEN : TERM_RED, "%+i ", o_ptr->pval[i]); else textblock_append(tb, "Affects your "); info_out_list(tb, descs, count); } if (of_has(flags[i], OF_SEARCH)) search = TRUE; } if (search) { if ((object_this_pval_is_visible(o_ptr, which_pval(o_ptr, OF_SEARCH)) || full) && !dummy) { textblock_append_c(tb, (o_ptr->pval[which_pval(o_ptr, OF_SEARCH)] > 0) ? TERM_L_GREEN : TERM_RED, "%+i%% ", o_ptr->pval[which_pval(o_ptr, OF_SEARCH)] * 5); textblock_append(tb, "to searching.\n"); } else if (count) textblock_append(tb, "Also affects your searching skill.\n"); else textblock_append(tb, "Affects your searching skill.\n"); } return TRUE; }
/* * Describe miscellaneous powers. */ static bool describe_misc_magic(textblock *tb, const bitflag flags[OF_SIZE]) { size_t i; bool printed = FALSE; for (i = 0; i < N_ELEMENTS(misc_flags); i++) { if (of_has(flags, misc_flags[i].flag)) { textblock_append(tb, "%s. ", misc_flags[i].name); printed = TRUE; } } if (printed) textblock_append(tb, "\n"); return printed; }
/** * Turn off spells with a side effect or a gf_type that is resisted by * something in flags, subject to intelligence and chance. * * \param spells is the set of spells we're pruning * \param flags is the set of object flags we're testing * \param pflags is the set of player flags we're testing * \param el is what we know about the monster's elemental resists * \param race is the monster type we're operating on */ void unset_spells(bitflag *spells, bitflag *flags, bitflag *pflags, struct element_info *el, const struct monster_race *race) { const struct mon_spell_info *info; bool smart = rf_has(race->flags, RF_SMART); for (info = mon_spell_types; info->index < RSF_MAX; info++) { const struct monster_spell *spell = monster_spell_by_index(info->index); const struct effect *effect; /* Ignore missing spells */ if (!spell) continue; if (!rsf_has(spells, info->index)) continue; /* Get the effect */ effect = spell->effect; /* First we test the elemental spells */ if (info->type & (RST_BOLT | RST_BALL | RST_BREATH)) { int element = effect->params[0]; int learn_chance = el[element].res_level * (smart ? 50 : 25); if (randint0(100) < learn_chance) rsf_off(spells, info->index); } else { /* Now others with resisted effects */ while (effect) { /* Timed effects */ if ((smart || !one_in_(3)) && (effect->index == EF_TIMED_INC) && of_has(flags, timed_protect_flag(effect->params[0]))) break; /* Mana drain */ if ((smart || one_in_(2)) && (effect->index == EF_DRAIN_MANA) && pf_has(pflags, PF_NO_MANA)) break; effect = effect->next; } if (effect) rsf_off(spells, info->index); } } }
/* * Describe fake object */ static void desc_obj_fake(int k_idx) { object_kind *kind = &k_info[k_idx]; object_type object_type_body; object_type *o_ptr = &object_type_body; char header[120]; textblock *tb; region area = { 0, 0, 0, 0 }; /* Check for known artifacts, display them as artifacts */ if (of_has(kind->flags, OF_INSTA_ART) && artifact_is_known(get_artifact_from_kind(kind))) { desc_art_fake(get_artifact_from_kind(kind)); return; } /* Update the object recall window */ track_object_kind(k_idx); handle_stuff(p_ptr); /* Wipe the object */ object_wipe(o_ptr); /* Create the artifact */ object_prep(o_ptr, kind, 0, EXTREMIFY); /* Hack -- its in the store */ if (kind->aware) o_ptr->ident |= (IDENT_STORE); /* It's fully know */ if (!kind->flavor) object_notice_everything(o_ptr); /* Hack -- Handle stuff */ handle_stuff(p_ptr); tb = object_info(o_ptr, OINFO_NONE); object_desc(header, sizeof(header), o_ptr, ODESC_PREFIX | ODESC_FULL); textui_textblock_show(tb, area, format("%^s", header)); textblock_free(tb); }
/* * Looks up an artifact idx given an object_kind *that's already known * to be an artifact*. Behaviour is distinctly unfriendly if passed * flavours which don't correspond to an artifact. */ static int get_artifact_from_kind(object_kind *kind) { int i; assert(of_has(kind->flags, OF_INSTA_ART)); /* Look for the corresponding artifact */ for (i = 0; i < z_info->a_max; i++) { if (kind->tval == a_info[i].tval && kind->sval == a_info[i].sval) { break; } } assert(i < z_info->a_max); return i; }
/** * Describe stat sustains. */ static bool describe_sustains(textblock *tb, const bitflag flags[OF_SIZE]) { const char *descs[STAT_MAX]; int i, count = 0; for (i = 0; i < STAT_MAX; i++) { struct obj_property *prop = lookup_obj_property(OBJ_PROPERTY_STAT, i); if (of_has(flags, sustain_flag(prop->index))) descs[count++] = prop->name; } if (!count) return false; textblock_append(tb, "Sustains "); info_out_list(tb, descs, count); return true; }
/** * Collect all tvals in the big squelch_choice array */ static int squelch_collect_kind(int tval, squelch_choice **ch) { squelch_choice *choice; int num = 0; int i; /* Create the array, with entries both for aware and unaware squelch */ choice = mem_alloc(2 * z_info.k_max * sizeof *choice); for (i = 1; i < z_info.k_max; i++) { object_kind *k_ptr = &k_info[i]; /* Skip empty objects, unseen objects, and incorrect tvals */ if (!k_ptr.name || k_ptr.tval != tval) continue; if (!k_ptr.aware) { /* can unaware squelch anything */ choice[num].kind = k_ptr; choice[num++].aware = false; } if ((k_ptr.everseen && !of_has(k_ptr.flags, OF_INSTA_ART)) || k_ptr.tval == TV_GOLD) { /* Do not display the artifact base kinds in this list */ /* aware squelch requires everseen */ /* do not require awareness for aware squelch, so people can set at game start */ choice[num].kind = k_ptr; choice[num++].aware = true; } } if (num == 0) mem_free(choice); else *ch = choice; return num; }
/** * Describe miscellaneous powers. */ static bool describe_misc_magic(textblock *tb, const bitflag flags[OF_SIZE]) { int i; bool printed = false; for (i = 1; i < OF_MAX; i++) { struct obj_property *prop = lookup_obj_property(OBJ_PROPERTY_FLAG, i); if ((prop->subtype != OFT_MISC) && (prop->subtype != OFT_MELEE) && (prop->subtype != OFT_BAD)) continue; if (of_has(flags, prop->index)) { textblock_append(tb, "%s. ", prop->desc); printed = true; } } if (printed) textblock_append(tb, "\n"); return printed; }
/* * Prepare an object based on an object kind. * Use the specified randomization aspect */ void object_prep(object_type *o_ptr, int k_idx, int lev, aspect rand_aspect) { object_kind *k_ptr = &k_info[k_idx]; /* Clear the record */ (void)WIPE(o_ptr, object_type); /* Save the kind index */ o_ptr->k_idx = k_idx; /* Efficiency -- tval/sval */ o_ptr->tval = k_ptr->tval; o_ptr->sval = k_ptr->sval; /* Default number */ o_ptr->number = 1; /* Default "pval" */ o_ptr->pval = randcalc(k_ptr->pval, lev, rand_aspect); /* Default weight */ o_ptr->weight = k_ptr->weight; /* Assign charges (wands/staves only) */ if (o_ptr->tval == TV_WAND || o_ptr->tval == TV_STAFF) o_ptr->pval = randcalc(k_ptr->charge, lev, rand_aspect); /* Default magic */ o_ptr->to_h = randcalc(k_ptr->to_h, lev, rand_aspect); o_ptr->to_d = randcalc(k_ptr->to_d, lev, rand_aspect); o_ptr->to_a = randcalc(k_ptr->to_a, lev, rand_aspect); /* Default power */ o_ptr->ac = k_ptr->ac; o_ptr->dd = k_ptr->dd; o_ptr->ds = k_ptr->ds; /* Hack -- cursed items are always "cursed" */ if (of_has(k_ptr->flags, OF_LIGHT_CURSE)) of_on(o_ptr->flags, OF_LIGHT_CURSE); }
bool wiz_create_item_action(menu_type *m, const ui_event_data *e, int oid) { ui_event_data ret; menu_type *menu; int choice[60]; int n_choices; int i; if (e->type != EVT_SELECT) return TRUE; for (n_choices = 0, i = 1; (n_choices < 60) && (i < z_info->k_max); i++) { object_kind *kind = &k_info[i]; if (kind->tval != tvals[oid].tval || of_has(kind->flags, OF_INSTA_ART)) continue; choice[n_choices++] = i; } screen_save(); clear_from(0); menu = menu_new(MN_SKIN_COLUMNS, &wiz_create_item_submenu); menu->selections = all_letters; menu->title = format("What kind of %s?", tvals[oid].desc); menu_setpriv(menu, n_choices, choice); menu_layout(menu, &wiz_create_item_area); ret = menu_select(menu, 0); screen_load(); return (ret.type == EVT_ESCAPE); }
void do_cmd_refill(cmd_code code, cmd_arg args[]) { object_type *j_ptr = &p_ptr->inventory[INVEN_LIGHT]; bitflag f[OF_SIZE]; int item = args[0].item; object_type *o_ptr = object_from_item_idx(item); if (!item_is_available(item, NULL, USE_INVEN | USE_FLOOR)) { msg("You do not have that item to refill with it."); return; } /* Check what we're wielding. */ object_flags(j_ptr, f); if (j_ptr->tval != TV_LIGHT) { msg("You are not wielding a light."); return; } else if (of_has(f, OF_NO_FUEL)) { msg("Your light cannot be refilled."); return; } /* It's a lamp */ if (j_ptr->sval == SV_LIGHT_LANTERN) refill_lamp(j_ptr, o_ptr, item); /* It's a torch */ else if (j_ptr->sval == SV_LIGHT_TORCH) refuel_torch(j_ptr, o_ptr, item); p_ptr->energy_use = 50; }
/** * Describe protections granted by an object. */ static bool describe_protects(textblock *tb, const bitflag flags[OF_SIZE]) { const char *p_descs[OF_MAX]; int i, count = 0; /* Protections */ for (i = 1; i < OF_MAX; i++) { struct obj_property *prop = lookup_obj_property(OBJ_PROPERTY_FLAG, i); if (prop->subtype != OFT_PROT) continue; if (of_has(flags, prop->index)) { p_descs[count++] = prop->desc; } } if (!count) return false; textblock_append(tb, "Provides protection from "); info_out_list(tb, p_descs, count); return true; }
/* * Describe things that look like lights. */ static bool describe_light(textblock *tb, const object_type *o_ptr, const bitflag flags[OF_SIZE], oinfo_detail_t mode) { bool artifact = o_ptr->artifact ? TRUE : FALSE; bool no_fuel = of_has(flags, OF_NO_FUEL) ? TRUE : FALSE; bool is_light = (o_ptr->tval == TV_LIGHT) ? TRUE : FALSE; bool terse = mode & OINFO_TERSE; if (no_fuel && !artifact) textblock_append(tb, "No fuel required. "); if (!terse && is_light && !no_fuel && o_ptr->sval != SV_LIGHT_TORCH) { const char *name = (o_ptr->sval == SV_LIGHT_TORCH) ? "torches" : "lanterns"; int turns = (o_ptr->sval == SV_LIGHT_TORCH) ? FUEL_TORCH : FUEL_LAMP; textblock_append(tb, "Refills other %s up to %d turns of fuel.", name, turns); } textblock_append(tb, "\n"); return TRUE; }
/** * Melee effect handler: Absorb the player's light. */ static void melee_effect_handler_EAT_LIGHT(melee_effect_handler_context_t *context) { int light_slot = slot_by_name(player, "light"); struct object *obj = slot_object(player, light_slot); /* Take damage */ take_hit(context->p, context->damage, context->ddesc); /* Drain fuel where applicable */ if (obj && !of_has(obj->flags, OF_NO_FUEL) && (obj->timeout > 0)) { /* Reduce fuel */ obj->timeout -= (250 + randint1(250)); if (obj->timeout < 1) obj->timeout = 1; /* Notice */ if (!context->p->timed[TMD_BLIND]) { msg("Your light dims."); context->obvious = TRUE; } /* Redraw stuff */ context->p->upkeep->redraw |= (PR_EQUIP); } }
/** * Return the real price of a known (or partly known) item. * * Wand and staffs get cost for each charge. * * Wearable items (weapons, launchers, jewelry, lights, armour) and ammo * are priced according to their power rating. All ammo, and normal (non-ego) * torches are scaled down by AMMO_RESCALER to reflect their impermanence. */ s32b object_value_real(const object_type *obj, int qty, int verbose, bool known) { s32b value, total_value; s32b power; int a = 1; int b = 5; static file_mode pricing_mode = MODE_WRITE; /* Wearables and ammo have prices that vary by individual item properties */ if (tval_has_variable_power(obj)) { char buf[1024]; ang_file *log_file = NULL; /* Logging */ if (verbose) { path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "pricing.log"); log_file = file_open(buf, pricing_mode, FTYPE_TEXT); if (!log_file) { msg("Error - can't open pricing.log for writing."); exit(1); } pricing_mode = MODE_APPEND; } file_putf(log_file, "object is %s\n", obj->kind->name); /* Calculate power and value */ power = object_power(obj, verbose, log_file, known); value = SGN(power) * ((a * power * power) + (b * power)); /* Rescale for expendables */ if ((tval_is_light(obj) && of_has(obj->flags, OF_BURNS_OUT) && !obj->ego) || tval_is_ammo(obj)) { value = value / AMMO_RESCALER; if (value < 1) value = 1; } /* More logging */ file_putf(log_file, "a is %d and b is %d\n", a, b); file_putf(log_file, "value is %d\n", value); if (verbose) { if (!file_close(log_file)) { msg("Error - can't close pricing.log file."); exit(1); } } /* Get the total value */ total_value = value * qty; if (total_value < 0) total_value = 0; } else { /* Worthless items */ if (!obj->kind->cost) return (0L); /* Base cost */ value = obj->kind->cost; /* Analyze the item type and quantity */ if (tval_can_have_charges(obj)) { int charges; total_value = value * qty; /* Calculate number of charges, rounded up */ charges = obj->pval * qty / obj->number; if ((obj->pval * qty) % obj->number != 0) charges++; /* Pay extra for charges, depending on standard number of charges */ total_value += value * charges / 20; } else total_value = value * qty; /* No negative value */ if (total_value < 0) total_value = 0; } /* Return the value */ return (total_value); }
/* * Describe objects that can be used for digging. */ static bool describe_digger(textblock *tb, const object_type *o_ptr, oinfo_detail_t mode) { bool full = mode & OINFO_FULL; player_state st; object_type inven[INVEN_TOTAL]; int sl = wield_slot(o_ptr); int i; bitflag f[OF_SIZE]; int chances[4]; /* These are out of 1600 */ static const char *names[4] = { "rubble", "magma veins", "quartz veins", "granite" }; /* abort if we are a dummy object */ if (mode & OINFO_DUMMY) return FALSE; if (full) object_flags(o_ptr, f); else object_flags_known(o_ptr, f); if (sl < 0 || (sl != INVEN_WIELD && !of_has(f, OF_TUNNEL))) return FALSE; memcpy(inven, p_ptr->inventory, INVEN_TOTAL * sizeof(object_type)); /* * Hack -- if we examine a ring that is worn on the right finger, * we shouldn't put a copy of it on the left finger before calculating * digging skills. */ if (o_ptr != &p_ptr->inventory[INVEN_RIGHT]) inven[sl] = *o_ptr; calc_bonuses(inven, &st, TRUE); chances[0] = st.skills[SKILL_DIGGING] * 8; chances[1] = (st.skills[SKILL_DIGGING] - 10) * 4; chances[2] = (st.skills[SKILL_DIGGING] - 20) * 2; chances[3] = (st.skills[SKILL_DIGGING] - 40) * 1; for (i = 0; i < 4; i++) { int chance = MAX(0, MIN(1600, chances[i])); int decis = chance ? (16000 / chance) : 0; if (i == 0 && chance > 0) { if (sl == INVEN_WIELD) textblock_append(tb, "Clears "); else textblock_append(tb, "With this item, your current weapon clears "); } if (i == 3 || (i != 0 && chance == 0)) textblock_append(tb, "and "); if (chance == 0) { textblock_append_c(tb, TERM_L_RED, "doesn't affect "); textblock_append(tb, "%s.\n", names[i]); break; } textblock_append(tb, "%s in ", names[i]); if (chance == 1600) { textblock_append_c(tb, TERM_L_GREEN, "1 "); } else if (decis < 100) { textblock_append_c(tb, TERM_GREEN, "%d.%d ", decis/10, decis%10); } else { textblock_append_c(tb, (decis < 1000) ? TERM_YELLOW : TERM_RED, "%d ", (decis+5)/10); } textblock_append(tb, "turn%s%s", decis == 10 ? "" : "s", (i == 3) ? ".\n" : ", "); } return TRUE; }
/* * Describe combat advantages. */ static bool describe_combat(textblock *tb, const object_type *o_ptr, oinfo_detail_t mode) { bool full = mode & OINFO_FULL; const char *desc[SL_MAX] = { 0 }; int i; int mult[SL_MAX]; int cnt, dam, total_dam, plus = 0; int xtra_postcrit = 0, xtra_precrit = 0; int crit_mult, crit_div, crit_add; int str_plus, dex_plus, old_blows = 0, new_blows, extra_blows; int str_faster = -1, str_done = -1; object_type *bow = &p_ptr->inventory[INVEN_BOW]; bitflag f[OF_SIZE], tmp_f[OF_SIZE], mask[OF_SIZE]; bool weapon = (wield_slot(o_ptr) == INVEN_WIELD); bool ammo = (p_ptr->state.ammo_tval == o_ptr->tval) && (bow->kind); int multiplier = 1; /* Create the "all slays" mask */ create_mask(mask, FALSE, OFT_SLAY, OFT_KILL, OFT_BRAND, OFT_MAX); /* Abort if we've nothing to say */ if (mode & OINFO_DUMMY) return FALSE; if (!weapon && !ammo) { /* Potions can have special text */ if (o_ptr->tval != TV_POTION || o_ptr->dd == 0 || o_ptr->ds == 0 || !object_flavor_is_aware(o_ptr)) return FALSE; textblock_append(tb, "It can be thrown at creatures with damaging effect.\n"); return TRUE; } if (full) { object_flags(o_ptr, f); } else { object_flags_known(o_ptr, f); } textblock_append_c(tb, TERM_L_WHITE, "Combat info:\n"); if (weapon) { /* * Get the player's hypothetical state, were they to be * wielding this item. */ player_state state; int dex_plus_bound; int str_plus_bound; object_type inven[INVEN_TOTAL]; memcpy(inven, p_ptr->inventory, INVEN_TOTAL * sizeof(object_type)); inven[INVEN_WIELD] = *o_ptr; if (full) object_know_all_flags(&inven[INVEN_WIELD]); calc_bonuses(inven, &state, TRUE); dex_plus_bound = STAT_RANGE - state.stat_ind[A_DEX]; str_plus_bound = STAT_RANGE - state.stat_ind[A_STR]; dam = ((o_ptr->ds + 1) * o_ptr->dd * 5); xtra_postcrit = state.dis_to_d * 10; if (object_attack_plusses_are_visible(o_ptr)) { xtra_precrit += o_ptr->to_d * 10; plus += o_ptr->to_h; } calculate_melee_crits(&state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); /* Warn about heavy weapons */ if (adj_str_hold[state.stat_ind[A_STR]] < o_ptr->weight / 10) textblock_append_c(tb, TERM_L_RED, "You are too weak to use this weapon.\n"); textblock_append_c(tb, TERM_L_GREEN, "%d.%d ", state.num_blows / 100, (state.num_blows / 10) % 10); textblock_append(tb, "blow%s/round.\n", (state.num_blows > 100) ? "s" : ""); /* Check to see if extra STR or DEX would yield extra blows */ old_blows = state.num_blows; extra_blows = 0; /* First we need to look for extra blows on other items, as * state does not track these */ for (i = INVEN_BOW; i < INVEN_TOTAL; i++) { if (!p_ptr->inventory[i].kind) continue; object_flags_known(&p_ptr->inventory[i], tmp_f); if (of_has(tmp_f, OF_BLOWS)) extra_blows += p_ptr->inventory[i].pval[which_pval(&p_ptr->inventory[i], OF_BLOWS)]; } /* Then we add blows from the weapon being examined */ if (of_has(f, OF_BLOWS)) extra_blows += o_ptr->pval[which_pval(o_ptr, OF_BLOWS)]; /* Then we check for extra "real" blows */ for (dex_plus = 0; dex_plus < dex_plus_bound; dex_plus++) { for (str_plus = 0; str_plus < str_plus_bound; str_plus++) { state.stat_ind[A_STR] += str_plus; state.stat_ind[A_DEX] += dex_plus; new_blows = calc_blows(o_ptr, &state, extra_blows); /* Test to make sure that this extra blow is a * new str/dex combination, not a repeat */ if ((new_blows - new_blows % 10) > (old_blows - old_blows % 10) && (str_plus < str_done || str_done == -1)) { textblock_append(tb, "With +%d STR and +%d DEX you would get %d.%d blows\n", str_plus, dex_plus, (new_blows / 100), (new_blows / 10) % 10); state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; str_done = str_plus; break; } /* If the combination doesn't increment * the displayed blows number, it might still * take a little less energy */ if (new_blows > old_blows && (str_plus < str_faster || str_faster == -1) && (str_plus < str_done || str_done == -1)) { textblock_append(tb, "With +%d STR and +%d DEX you would attack a bit faster\n", str_plus, dex_plus); state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; str_faster = str_plus; continue; } state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; } } } else { int tdis = 6 + 2 * p_ptr->state.ammo_mult; if (object_attack_plusses_are_visible(o_ptr)) plus += o_ptr->to_h; calculate_missile_crits(&p_ptr->state, o_ptr->weight, plus, &crit_mult, &crit_add, &crit_div); /* Calculate damage */ dam = ((o_ptr->ds + 1) * o_ptr->dd * 5); if (object_attack_plusses_are_visible(o_ptr)) dam += (o_ptr->to_d * 10); if (object_attack_plusses_are_visible(bow)) dam += (bow->to_d * 10); /* Apply brands/slays from the shooter to the ammo, but only if known * Note that this is not dependent on mode, so that viewing shop-held * ammo (fully known) does not leak information about launcher */ object_flags_known(bow, tmp_f); of_union(f, tmp_f); textblock_append(tb, "Hits targets up to "); textblock_append_c(tb, TERM_L_GREEN, format("%d", tdis * 10)); textblock_append(tb, " feet away.\n"); } /* Collect slays */ /* Melee weapons get slays and brands from other items now */ if (weapon) { bool nonweap = FALSE; for (i = INVEN_LEFT; i < INVEN_TOTAL; i++) { if (!p_ptr->inventory[i].kind) continue; object_flags_known(&p_ptr->inventory[i], tmp_f); of_inter(tmp_f, mask); /* strip out non-slays */ if (of_union(f, tmp_f)) nonweap = TRUE; } if (nonweap) textblock_append(tb, "This weapon may benefit from one or more off-weapon brands or slays.\n"); } textblock_append(tb, "Average damage/round: "); if (ammo) multiplier = p_ptr->state.ammo_mult; cnt = list_slays(f, mask, desc, NULL, mult, TRUE); for (i = 0; i < cnt; i++) { int melee_adj_mult = ammo ? 0 : 1; /* ammo mult adds fully, melee mult is times 1, so adds 1 less */ /* Include bonus damage and slay in stated average */ total_dam = dam * (multiplier + mult[i] - melee_adj_mult) + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); textblock_append(tb, " vs. %s, ", desc[i]); } if (cnt) textblock_append(tb, "and "); /* Include bonus damage in stated average */ total_dam = dam * multiplier + xtra_precrit; total_dam = (total_dam * crit_mult + crit_add) / crit_div; total_dam += xtra_postcrit; if (weapon) total_dam = (total_dam * old_blows) / 100; else total_dam *= p_ptr->state.num_shots; if (total_dam <= 0) textblock_append_c(tb, TERM_L_RED, "%d", 0); else if (total_dam % 10) textblock_append_c(tb, TERM_L_GREEN, "%d.%d", total_dam / 10, total_dam % 10); else textblock_append_c(tb, TERM_L_GREEN, "%d", total_dam / 10); if (cnt) textblock_append(tb, " vs. others"); textblock_append(tb, ".\n"); /* Note the impact flag */ if (of_has(f, OF_IMPACT)) textblock_append(tb, "Sometimes creates earthquakes on impact.\n"); /* Add breakage chance */ if (ammo) { int chance = breakage_chance(o_ptr, TRUE); textblock_append_c(tb, TERM_L_GREEN, "%d%%", chance); textblock_append(tb, " chance of breaking upon contact.\n"); } /* You always have something to say... */ return TRUE; }
/* * Describe an item's curses. */ static bool describe_curses(textblock * tb, const object_type * o_ptr, oinfo_detail_t mode) { size_t i; bool printed = FALSE; bool full = mode & OINFO_FULL; bool terse = mode & OINFO_TERSE; bool dummy = mode & OINFO_DUMMY; for (i = 0; i < N_ELEMENTS(curses); i++) { if (cf_has (full ? o_ptr->flags_curse : o_ptr->id_curse, curses[i].flag)) { if (!printed) textblock_append(tb, "\nCurses: "); textblock_append(tb, "%s. ", curses[i].name); printed = TRUE; } } if (printed) { textblock_append(tb, "\n"); /* Say if the curse is permanent */ if (of_has(o_ptr->id_obj, OF_PERMA_CURSE)) textblock_append(tb, "It cannot be uncursed. "); /* Say if curse removal has been tried */ if (of_has(o_ptr->flags_obj, OF_FRAGILE)) textblock_append(tb, "Attempting to uncurse it may destroy it.\n"); } if (terse || dummy) return printed; /* Only look at wieldables */ if (wield_slot(o_ptr) >= INVEN_WIELD) { /* All normal properties known */ if (o_ptr->ident & IDENT_KNOWN) { /* Everything known */ if (o_ptr->ident & (IDENT_KNOW_CURSES | IDENT_UNCURSED)) { textblock_append(tb, "You know all about this object.\n"); printed = TRUE; } /* Some unknown curses */ else { textblock_append(tb, "You know all the enchantments on this object.\n"); printed = TRUE; } } /* Curses known */ else { /* Known uncursed */ if (o_ptr->ident & IDENT_UNCURSED) { textblock_append(tb, "It is not cursed.\n"); printed = TRUE; } /* Say if all curses are known */ else if (o_ptr->ident & IDENT_KNOW_CURSES) { textblock_append(tb, "You know all the curses on this object.\n"); printed = TRUE; } } } return printed; }
/** * Special display, part 2c * * How to print out the modifications and sustains. * Positive mods with no sustain will be light green. * Positive mods with a sustain will be dark green. * Sustains (with no modification) will be a dark green 's'. * Negative mods (from a curse) will be red. * Huge mods (>9), like from MICoMorgoth, will be a '*' * No mod, no sustain, will be a slate '.' */ static void display_player_sust_info(void) { int i, row, col, stat; struct object *obj; bitflag f[OF_SIZE]; byte a; char c; /* Row */ row = 2; /* Column */ col = 26; /* Header */ c_put_str(COLOUR_WHITE, "abcdefghijkl@", row-1, col); /* Process equipment */ for (i = 0; i < player->body.count; ++i) { /* Get the object */ obj = slot_object(player, i); if (!obj) { col++; continue; } /* Get the "known" flags */ object_flags_known(obj, f); /* Initialize color based on sign of modifier. */ for (stat = OBJ_MOD_MIN_STAT; stat < OBJ_MOD_MIN_STAT + STAT_MAX; stat++) { /* Default */ a = COLOUR_SLATE; c = '.'; /* Boosted or reduced */ if (obj->modifiers[stat] > 0) { /* Good */ a = COLOUR_L_GREEN; /* Label boost */ if (obj->modifiers[stat] < 10) c = I2D(obj->modifiers[stat]); } else if (obj->modifiers[stat] < 0) { /* Bad */ a = COLOUR_RED; /* Label boost */ if (obj->modifiers[stat] > -10) c = I2D(-(obj->modifiers[stat])); } /* Sustain */ if (of_has(f, sustain_flag(stat))) { /* Dark green */ a = COLOUR_GREEN; /* Convert '.' to 's' */ if (c == '.') c = 's'; } if ((c == '.') && obj && !object_flag_is_known(obj, sustain_flag(stat))) c = '?'; /* Dump proper character */ Term_putch(col, row+stat, a, c); } /* Advance */ col++; } /* Player flags */ player_flags(player, f); /* Check stats */ for (stat = 0; stat < STAT_MAX; ++stat) { /* Default */ a = COLOUR_SLATE; c = '.'; /* Sustain */ if (of_has(f, sustain_flag(stat))) { /* Dark green "s" */ a = COLOUR_GREEN; c = 's'; } /* Dump */ Term_putch(col, row+stat, a, c); } /* Column */ col = 26; /* Footer */ c_put_str(COLOUR_WHITE, "abcdefghijkl@", row+6, col); /* Equippy */ display_player_equippy(row+7, col); }
static void display_resistance_panel(const struct player_flag_record *rec, size_t size, const region *bounds) { size_t i; int j; int col = bounds->col; int row = bounds->row; int res_cols = 5 + 2 + player->body.count; Term_putstr(col, row++, res_cols, COLOUR_WHITE, " abcdefghijkl@"); for (i = 0; i < size - 3; i++, row++) { byte name_attr = COLOUR_WHITE; Term_gotoxy(col + 6, row); /* Repeated extraction of flags is inefficient but more natural */ for (j = 0; j <= player->body.count; j++) { bitflag f[OF_SIZE]; byte attr = COLOUR_WHITE | (j % 2) * 8; /* alternating columns */ char sym = '.'; bool res = false, imm = false, vul = false, rune = false; bool timed = false; bool known = false; /* Object or player info? */ if (j < player->body.count) { int index = 0; struct object *obj = slot_object(player, j); struct curse_data *curse = obj ? obj->curses : NULL; while (obj) { /* Wipe flagset */ of_wipe(f); /* Get known properties */ object_flags_known(obj, f); if (rec[i].element != -1) { known = object_element_is_known(obj, rec[i].element); } else if (rec[i].flag != -1) { known = object_flag_is_known(obj, rec[i].flag); } else { known = true; } /* Get resistance, immunity and vulnerability info */ if (rec[i].mod != -1) { if (obj->modifiers[rec[i].mod] != 0) { res = true; } rune = (player->obj_k->modifiers[rec[i].mod] == 1); } else if (rec[i].flag != -1) { if (of_has(f, rec[i].flag)) { res = true; } rune = of_has(player->obj_k->flags, rec[i].flag); } else if (rec[i].element != -1) { if (known) { if (obj->el_info[rec[i].element].res_level == 3) { imm = true; } if (obj->el_info[rec[i].element].res_level == 1) { res = true; } if (obj->el_info[rec[i].element].res_level == -1) { vul = true; } } rune = (player->obj_k->el_info[rec[i].element].res_level == 1); } /* Move to any unprocessed curse object */ if (curse) { index++; obj = NULL; while (index < z_info->curse_max) { if (curse[index].power) { obj = curses[index].obj; break; } else { index++; } } } else { obj = NULL; } } } else { player_flags(player, f); known = true; /* Timed flags only in the player column */ if (rec[i].tmd_flag >= 0) { timed = player->timed[rec[i].tmd_flag] ? true : false; /* There has to be one special case... */ if ((rec[i].tmd_flag == TMD_AFRAID) && (player->timed[TMD_TERROR])) timed = true; } /* Set which (if any) symbol and color are used */ if (rec[i].mod != -1) { int k; /* Shape modifiers */ for (k = 0; k < OBJ_MOD_MAX; k++) { res = (player->shape->modifiers[i] > 0); vul = (player->shape->modifiers[i] > 0); } /* Messy special cases */ if (rec[i].mod == OBJ_MOD_INFRA) res |= (player->race->infra > 0); if (rec[i].mod == OBJ_MOD_TUNNEL) res |= (player->race->r_skills[SKILL_DIGGING] > 0); } else if (rec[i].flag != -1) { res = of_has(f, rec[i].flag); res |= (of_has(player->shape->flags, rec[i].flag) && of_has(player->obj_k->flags, rec[i].flag)); } else if (rec[i].element != -1) { int el = rec[i].element; imm = (player->race->el_info[el].res_level == 3) || ((player->shape->el_info[el].res_level == 3) && (player->obj_k->el_info[el].res_level)); res = (player->race->el_info[el].res_level == 1) || ((player->shape->el_info[el].res_level == 1) && (player->obj_k->el_info[el].res_level)); vul = (player->race->el_info[el].res_level == -1) || ((player->shape->el_info[el].res_level == -1) && (player->obj_k->el_info[el].res_level)); } } /* Colour the name appropriately */ if (imm) { name_attr = COLOUR_GREEN; } else if (res && (name_attr != COLOUR_GREEN)) { name_attr = COLOUR_L_BLUE; } else if (vul && (name_attr != COLOUR_GREEN)) { name_attr = COLOUR_RED; } /* Set the symbols and print them */ if (vul) { sym = '-'; } else if (imm) { sym = '*'; } else if (res) { sym = '+'; } else if (timed) { sym = '!'; attr = COLOUR_L_GREEN; } else if ((j < player->body.count) && slot_object(player, j) && !known && !rune) { sym = '?'; } Term_addch(attr, sym); } /* Check if the rune is known */ if (((rec[i].mod >= 0) && (player->obj_k->modifiers[rec[i].mod] == 0)) || ((rec[i].flag >= 0) && !of_has(player->obj_k->flags, rec[i].flag)) || ((rec[i].element >= 0) && (player->obj_k->el_info[rec[i].element].res_level == 0))) { name_attr = COLOUR_SLATE; } Term_putstr(col, row, 6, name_attr, format("%5s:", rec[i].name)); } Term_putstr(col, row++, res_cols, COLOUR_WHITE, " abcdefghijkl@"); /* Equippy */ display_player_equippy(row++, col + 6); }
/* * Describe combat advantages. */ static bool describe_combat(textblock *tb, const object_type *o_ptr, oinfo_detail_t mode) { bool full = mode & OINFO_FULL; object_type *bow = &p_ptr->inventory[INVEN_BOW]; bitflag f[OF_SIZE]; bool weapon = (wield_slot(o_ptr) == INVEN_WIELD); bool ammo = (p_ptr->state.ammo_tval == o_ptr->tval) && (bow->kind); /* The player's hypothetical state, were they to wield this item */ player_state state; /* Abort if we've nothing to say */ if (mode & OINFO_DUMMY) return FALSE; if (!weapon && !ammo) { /* Potions can have special text */ if (o_ptr->tval != TV_POTION || o_ptr->dd == 0 || o_ptr->ds == 0 || !object_flavor_is_aware(o_ptr)) return FALSE; textblock_append(tb, "It can be thrown at creatures with damaging effect.\n"); return TRUE; } if (full) object_flags(o_ptr, f); else object_flags_known(o_ptr, f); textblock_append_c(tb, TERM_L_WHITE, "Combat info:\n"); if (weapon) { object_type inven[INVEN_TOTAL]; memcpy(inven, p_ptr->inventory, INVEN_TOTAL * sizeof(object_type)); inven[INVEN_WIELD] = *o_ptr; if (full) object_know_all_flags(&inven[INVEN_WIELD]); /* Calculate the player's hypothetical state */ calc_bonuses(inven, &state, TRUE); /* Warn about heavy weapons */ if (adj_str_hold[state.stat_ind[A_STR]] < o_ptr->weight / 10) textblock_append_c(tb, TERM_L_RED, "You are too weak to use this weapon.\n"); /* Describe blows */ describe_blows(tb, o_ptr, state, f); } else { /* Ammo */ /* Range of the weapon */ int tdis = 6 + 2 * p_ptr->state.ammo_mult; /* Output the range */ textblock_append(tb, "Hits targets up to "); textblock_append_c(tb, TERM_L_GREEN, format("%d", tdis * 10)); textblock_append(tb, " feet away.\n"); } /* Describe damage */ describe_damage(tb, o_ptr, state, f, mode); /* Note the impact flag */ if (of_has(f, OF_IMPACT)) textblock_append(tb, "Sometimes creates earthquakes on impact.\n"); /* Add breakage chance */ if (ammo) { int chance = breakage_chance(o_ptr, TRUE); textblock_append_c(tb, TERM_L_GREEN, "%d%%", chance); textblock_append(tb, " chance of breaking upon contact.\n"); } /* Something has been said */ return TRUE; }
/* * Set a timed event (except timed resists, cutting and stunning). */ bool player_set_timed(struct player *p, int idx, int v, bool notify) { timed_effect *effect; /* Hack -- Force good values */ v = (v > 10000) ? 10000 : (v < 0) ? 0 : v; if ((idx < 0) || (idx > TMD_MAX)) return FALSE; /* No change */ if (p->timed[idx] == v) return FALSE; /* Hack -- call other functions */ if (idx == TMD_STUN) return set_stun(p, v); else if (idx == TMD_CUT) return set_cut(p, v); /* Don't mention effects which already match the player state. */ if (idx == TMD_OPP_ACID && check_state(p, OF_IM_ACID, p->state.flags)) notify = FALSE; else if (idx == TMD_OPP_ELEC && check_state(p, OF_IM_ELEC, p->state.flags)) notify = FALSE; else if (idx == TMD_OPP_FIRE && check_state(p, OF_IM_FIRE, p->state.flags)) notify = FALSE; else if (idx == TMD_OPP_COLD && check_state(p, OF_IM_COLD, p->state.flags)) notify = FALSE; else if (idx == TMD_OPP_CONF && of_has(p->state.flags, OF_RES_CONFU)) notify = FALSE; /* Find the effect */ effect = &effects[idx]; /* Turning off, always mention */ if (v == 0) { msgt(MSG_RECOVER, "%s", effect->on_end); notify = TRUE; } /* Turning on, always mention */ else if (p->timed[idx] == 0) { msgt(effect->msg, "%s", effect->on_begin); notify = TRUE; } else if (notify) { /* Decrementing */ if (p->timed[idx] > v && effect->on_decrease) msgt(effect->msg, "%s", effect->on_decrease); /* Incrementing */ else if (v > p->timed[idx] && effect->on_increase) msgt(effect->msg, "%s", effect->on_increase); } /* Use the value */ p->timed[idx] = v; /* Sort out the sprint effect */ if (idx == TMD_SPRINT && v == 0) player_inc_timed(p, TMD_SLOW, 100, TRUE, FALSE); /* Nothing to notice */ if (!notify) return FALSE; /* Disturb */ disturb(p, 0, 0); /* Update the visuals, as appropriate. */ p->update |= effect->flag_update; p->redraw |= (PR_STATUS | effect->flag_redraw); /* Handle stuff */ handle_stuff(p); /* Result */ return TRUE; }
/* * Describe blows. */ static bool describe_blows(textblock *tb, const object_type *o_ptr, player_state state, bitflag f[OF_SIZE]) { int str_plus, dex_plus, old_blows = 0, new_blows, extra_blows; int str_faster = -1, str_done = -1; int dex_plus_bound; int str_plus_bound; int i; bitflag tmp_f[OF_SIZE]; dex_plus_bound = STAT_RANGE - state.stat_ind[A_DEX]; str_plus_bound = STAT_RANGE - state.stat_ind[A_STR]; /* Write to the text block */ textblock_append_c(tb, TERM_L_GREEN, "%d.%d ", state.num_blows / 100, (state.num_blows / 10) % 10); textblock_append(tb, "blow%s/round.\n", (state.num_blows > 100) ? "s" : ""); /* Check to see if extra STR or DEX would yield extra blows */ old_blows = state.num_blows; extra_blows = 0; /* First we need to look for extra blows on other items, as * state does not track these */ for (i = INVEN_BOW; i < INVEN_TOTAL; i++) { if (!p_ptr->inventory[i].kind) continue; object_flags_known(&p_ptr->inventory[i], tmp_f); if (of_has(tmp_f, OF_BLOWS)) extra_blows += p_ptr->inventory[i].pval[which_pval(&p_ptr->inventory[i], OF_BLOWS)]; } /* Then we add blows from the weapon being examined */ if (of_has(f, OF_BLOWS)) extra_blows += o_ptr->pval[which_pval(o_ptr, OF_BLOWS)]; /* Then we check for extra "real" blows */ for (dex_plus = 0; dex_plus < dex_plus_bound; dex_plus++) { for (str_plus = 0; str_plus < str_plus_bound; str_plus++) { state.stat_ind[A_STR] += str_plus; state.stat_ind[A_DEX] += dex_plus; new_blows = calc_blows(o_ptr, &state, extra_blows); /* Test to make sure that this extra blow is a * new str/dex combination, not a repeat */ if ((new_blows - new_blows % 10) > (old_blows - old_blows % 10) && (str_plus < str_done || str_done == -1)) { textblock_append(tb, "With +%d STR and +%d DEX you would get %d.%d blows\n", str_plus, dex_plus, (new_blows / 100), (new_blows / 10) % 10); state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; str_done = str_plus; break; } /* If the combination doesn't increment * the displayed blows number, it might still * take a little less energy */ if (new_blows > old_blows && (str_plus < str_faster || str_faster == -1) && (str_plus < str_done || str_done == -1)) { textblock_append(tb, "With +%d STR and +%d DEX you would attack a bit faster\n", str_plus, dex_plus); state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; str_faster = str_plus; continue; } state.stat_ind[A_STR] -= str_plus; state.stat_ind[A_DEX] -= dex_plus; } } return TRUE; }
/* * Print an item's flavour text. * * \param tb is the textblock to which we are adding. * \param o_ptr is the object we are describing. * \param ego is whether we're describing an ego template (as opposed to a * real object) */ static void describe_flavor_text(textblock *tb, const object_type *o_ptr, oinfo_detail_t mode) { int i, count = 0; bool ego = mode & OINFO_EGO; bool subj = mode & OINFO_SUBJ; /* Display the known artifact description */ if (!OPT(birth_randarts) && o_ptr->artifact && object_is_known(o_ptr) && o_ptr->artifact->text) textblock_append(tb, "%s\n\n", o_ptr->artifact->text); else if (o_ptr->theme && o_ptr->theme->text && object_theme_is_known(o_ptr)) textblock_append(tb, "%s\n\n", o_ptr->theme->text); /* Display the known object description */ else if (object_flavor_is_aware(o_ptr) || object_is_known(o_ptr) || ego) { bool did_desc = FALSE; if (!ego && o_ptr->kind->text) { textblock_append(tb, "%s", o_ptr->kind->text); did_desc = TRUE; } /* Display additional affix descriptions */ for (i = 0; i < MAX_AFFIXES && o_ptr->affix[i]; i++) if (o_ptr->affix[i]->text && (ego || object_affix_is_known(o_ptr, o_ptr->affix[i]->eidx))) { if (did_desc) textblock_append(tb, " "); textblock_append(tb, "%s", o_ptr->affix[i]->text); did_desc = TRUE; } if (did_desc) textblock_append(tb, "\n\n"); } /* List the affixes on the item */ for (i = 0; i < MAX_AFFIXES && o_ptr->affix[i]; i++) if (object_affix_is_known(o_ptr, o_ptr->affix[i]->eidx)) { if (count == 0) textblock_append(tb, "This item's known properties are: "); else textblock_append(tb, ", "); textblock_append(tb, "%s", o_ptr->affix[i]->name); count++; } if (count) textblock_append(tb, ".\n\n"); if (!ego && subj && o_ptr->origin != ORIGIN_STORE) { /* List the item's known runes */ count = 0; for (i = 0; i < OF_MAX; i++) if (of_has(o_ptr->flags, i) && of_has(p_ptr->known_runes, i) && obj_flag_type(i) != OFT_INT && obj_flag_type(i) != OFT_NONE) { if (count == 0) textblock_append(tb, "This item's known runes are: "); else textblock_append(tb, ", "); textblock_append(tb, "%s", flag_name(i)); count++; } if (count) textblock_append(tb, ".\n\n"); /* List the item's unknown runes */ count = 0; for (i = 0; i < OF_MAX; i++) if (of_has(o_ptr->flags, i) && !of_has(p_ptr->known_runes, i) && obj_flag_type(i) != OFT_INT && obj_flag_type(i) != OFT_NONE) { if (count == 0) textblock_append(tb, "This item's unknown runes are: "); else textblock_append(tb, ", "); textblock_append(tb, "%s", flag_rune(i)); count++; } if (count) textblock_append(tb, ".\n\n"); } }
/* * Do an effect, given an object. * Boost is the extent to which skill surpasses difficulty, used as % boost. It * ranges from 0 to 138. */ bool effect_do(effect_type effect, bool *ident, bool aware, int dir, int beam, int boost) { int py = p_ptr->py; int px = p_ptr->px; int dam, chance, dur; if (effect < 1 || effect > EF_MAX) { msg("Bad effect passed to do_effect(). Please report this bug."); return FALSE; } switch (effect) { case EF_POISON: { inc_timed(TMD_POISONED, damroll(2, 7) + 10, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_BLIND: { inc_timed(TMD_BLIND, damroll(4, 25) + 75, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_SCARE: { inc_timed(TMD_AFRAID, randint0(10) + 10, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_CONFUSE: { inc_timed(TMD_CONFUSED, damroll(4, 5) + 10, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_HALLUC: { inc_timed(TMD_IMAGE, randint0(250) + 250, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_PARALYZE: { inc_timed(TMD_PARALYZED, randint0(5) + 5, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_SLOW: { if (inc_timed(TMD_SLOW, randint1(25) + 15, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_POISON: { if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_BLINDNESS: { if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_PARANOIA: { if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_CONFUSION: { if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_MIND: { if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; if (clear_timed(TMD_IMAGE, TRUE)) *ident = TRUE; if (!of_has(p_ptr->state.flags, OF_RES_CONFU) && inc_timed(TMD_OPP_CONF, damroll(4, 10), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_BODY: { if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_LIGHT: { if (hp_player(20)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (dec_timed(TMD_CUT, 20, TRUE)) *ident = TRUE; if (dec_timed(TMD_CONFUSED, 20, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_SERIOUS: { if (hp_player(40)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_CRITICAL: { if (hp_player(60)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(TMD_AMNESIA, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_FULL: { int amt = (p_ptr->mhp * 35) / 100; if (amt < 300) amt = 300; if (hp_player(amt)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(TMD_AMNESIA, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_FULL2: { if (hp_player(1200)) *ident = TRUE; if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; if (clear_timed(TMD_AMNESIA, TRUE)) *ident = TRUE; return TRUE; } case EF_CURE_TEMP: { if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_CONFUSED, TRUE)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_HEAL1: { if (hp_player(500)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_HEAL2: { if (hp_player(1000)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_HEAL3: { if (hp_player(500)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_GAIN_EXP: { if (p_ptr->exp < PY_MAX_EXP) { msg("You feel more experienced."); player_exp_gain(p_ptr, 100000L); *ident = TRUE; } return TRUE; } case EF_LOSE_EXP: { if (!check_state(OF_HOLD_LIFE, p_ptr->state.flags) && (p_ptr->exp > 0)) { msg("You feel your memories fade."); player_exp_lose(p_ptr, p_ptr->exp / 4, FALSE); *ident = TRUE; } *ident = TRUE; wieldeds_notice_flag(OF_HOLD_LIFE); return TRUE; } case EF_RESTORE_EXP: { if (restore_level()) *ident = TRUE; return TRUE; } case EF_RESTORE_MANA: { if (p_ptr->csp < p_ptr->msp) { p_ptr->csp = p_ptr->msp; p_ptr->csp_frac = 0; msg("Your feel your head clear."); p_ptr->redraw |= (PR_MANA); *ident = TRUE; } return TRUE; } case EF_GAIN_STR: case EF_GAIN_INT: case EF_GAIN_WIS: case EF_GAIN_DEX: case EF_GAIN_CON: case EF_GAIN_CHR: { int stat = effect - EF_GAIN_STR; if (do_inc_stat(stat)) *ident = TRUE; return TRUE; } case EF_GAIN_ALL: { if (do_inc_stat(A_STR)) *ident = TRUE; if (do_inc_stat(A_INT)) *ident = TRUE; if (do_inc_stat(A_WIS)) *ident = TRUE; if (do_inc_stat(A_DEX)) *ident = TRUE; if (do_inc_stat(A_CON)) *ident = TRUE; if (do_inc_stat(A_CHR)) *ident = TRUE; return TRUE; } case EF_BRAWN: { /* Pick a random stat to decrease other than strength */ int stat = randint0(A_MAX-1) + 1; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_STR); *ident = TRUE; } return TRUE; } case EF_INTELLECT: { /* Pick a random stat to decrease other than intelligence */ int stat = randint0(A_MAX-1); if (stat >= A_INT) stat++; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_INT); *ident = TRUE; } return TRUE; } case EF_CONTEMPLATION: { /* Pick a random stat to decrease other than wisdom */ int stat = randint0(A_MAX-1); if (stat >= A_WIS) stat++; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_WIS); *ident = TRUE; } return TRUE; } case EF_TOUGHNESS: { /* Pick a random stat to decrease other than constitution */ int stat = randint0(A_MAX-1); if (stat >= A_CON) stat++; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_CON); *ident = TRUE; } return TRUE; } case EF_NIMBLENESS: { /* Pick a random stat to decrease other than dexterity */ int stat = randint0(A_MAX-1); if (stat >= A_DEX) stat++; if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_DEX); *ident = TRUE; } return TRUE; } case EF_PLEASING: { /* Pick a random stat to decrease other than charisma */ int stat = randint0(A_MAX-1); if (do_dec_stat(stat, TRUE)) { do_inc_stat(A_CHR); *ident = TRUE; } return TRUE; } case EF_LOSE_STR: case EF_LOSE_INT: case EF_LOSE_WIS: case EF_LOSE_DEX: case EF_LOSE_CON: case EF_LOSE_CHR: { int stat = effect - EF_LOSE_STR; take_hit(damroll(5, 5), "stat drain"); (void)do_dec_stat(stat, FALSE); *ident = TRUE; return TRUE; } case EF_LOSE_CON2: { take_hit(damroll(10, 10), "poisonous food"); (void)do_dec_stat(A_CON, FALSE); *ident = TRUE; return TRUE; } case EF_RESTORE_STR: case EF_RESTORE_INT: case EF_RESTORE_WIS: case EF_RESTORE_DEX: case EF_RESTORE_CON: case EF_RESTORE_CHR: { int stat = effect - EF_RESTORE_STR; if (do_res_stat(stat)) *ident = TRUE; return TRUE; } case EF_CURE_NONORLYBIG: { msg("You feel life flow through your body!"); restore_level(); (void)clear_timed(TMD_POISONED, TRUE); (void)clear_timed(TMD_BLIND, TRUE); (void)clear_timed(TMD_CONFUSED, TRUE); (void)clear_timed(TMD_IMAGE, TRUE); (void)clear_timed(TMD_STUN, TRUE); (void)clear_timed(TMD_CUT, TRUE); (void)clear_timed(TMD_AMNESIA, TRUE); if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_INT)) *ident = TRUE; if (do_res_stat(A_WIS)) *ident = TRUE; if (do_res_stat(A_DEX)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (do_res_stat(A_CHR)) *ident = TRUE; /* Recalculate max. hitpoints */ update_stuff(); hp_player(5000); *ident = TRUE; return TRUE; } case EF_RESTORE_ALL: { /* Life, above, also gives these effects */ if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_INT)) *ident = TRUE; if (do_res_stat(A_WIS)) *ident = TRUE; if (do_res_stat(A_DEX)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (do_res_stat(A_CHR)) *ident = TRUE; return TRUE; } case EF_RESTORE_ST_LEV: { if (restore_level()) *ident = TRUE; if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_INT)) *ident = TRUE; if (do_res_stat(A_WIS)) *ident = TRUE; if (do_res_stat(A_DEX)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (do_res_stat(A_CHR)) *ident = TRUE; return TRUE; } case EF_TMD_INFRA: { if (inc_timed(TMD_SINFRA, 100 + damroll(4, 25), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_TMD_SINVIS: { if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (inc_timed(TMD_SINVIS, 12 + damroll(2, 6), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_TMD_ESP: { if (clear_timed(TMD_BLIND, TRUE)) *ident = TRUE; if (inc_timed(TMD_TELEPATHY, 12 + damroll(6, 6), TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_ENLIGHTENMENT: { msg("An image of your surroundings forms in your mind..."); wiz_light(); *ident = TRUE; return TRUE; } case EF_ENLIGHTENMENT2: { msg("You begin to feel more enlightened..."); message_flush(); wiz_light(); (void)do_inc_stat(A_INT); (void)do_inc_stat(A_WIS); (void)detect_traps(TRUE); (void)detect_doorstairs(TRUE); (void)detect_treasure(TRUE); identify_pack(); *ident = TRUE; return TRUE; } case EF_HERO: { dur = randint1(25) + 25; if (hp_player(10)) *ident = TRUE; if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; if (inc_timed(TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_HERO, dur, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SHERO: { dur = randint1(25) + 25; if (hp_player(30)) *ident = TRUE; if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; if (inc_timed(TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_SHERO, dur, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_ACID: { if (inc_timed(TMD_OPP_ACID, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_ELEC: { if (inc_timed(TMD_OPP_ELEC, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_FIRE: { if (inc_timed(TMD_OPP_FIRE, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_COLD: { if (inc_timed(TMD_OPP_COLD, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_POIS: { if (inc_timed(TMD_OPP_POIS, randint1(10) + 10, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RESIST_ALL: { if (inc_timed(TMD_OPP_ACID, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_OPP_ELEC, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_OPP_POIS, randint1(20) + 20, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_DETECT_TREASURE: { if (detect_treasure(aware)) *ident = TRUE; return TRUE; } case EF_DETECT_TRAP: { if (detect_traps(aware)) *ident = TRUE; return TRUE; } case EF_DETECT_DOORSTAIR: { if (detect_doorstairs(aware)) *ident = TRUE; return TRUE; } case EF_DETECT_INVIS: { if (detect_monsters_invis(aware)) *ident = TRUE; return TRUE; } case EF_DETECT_EVIL: { if (detect_monsters_evil(aware)) *ident = TRUE; return TRUE; } case EF_DETECT_ALL: { if (detect_all(aware)) *ident = TRUE; return TRUE; } case EF_ENCHANT_TOHIT: { *ident = TRUE; return enchant_spell(1, 0, 0); } case EF_ENCHANT_TODAM: { *ident = TRUE; return enchant_spell(0, 1, 0); } case EF_ENCHANT_WEAPON: { *ident = TRUE; return enchant_spell(randint1(3), randint1(3), 0); } case EF_ENCHANT_ARMOR: { *ident = TRUE; return enchant_spell(0, 0, 1); } case EF_ENCHANT_ARMOR2: { *ident = TRUE; return enchant_spell(0, 0, randint1(3) + 2); } case EF_RESTORE_ITEM: { *ident = TRUE; return restore_item(); } case EF_IDENTIFY: { *ident = TRUE; if (!ident_spell()) return FALSE; return TRUE; } case EF_REMOVE_CURSE: { if (remove_curse()) { if (!p_ptr->timed[TMD_BLIND]) msg("The air around your body glows blue for a moment..."); else msg("You feel as if someone is watching over you."); *ident = TRUE; } return TRUE; } case EF_REMOVE_CURSE2: { remove_all_curse(); *ident = TRUE; return TRUE; } case EF_LIGHT: { if (light_area(damroll(2, 8), 2)) *ident = TRUE; return TRUE; } case EF_SUMMON_MON: { int i; sound(MSG_SUM_MONSTER); for (i = 0; i < randint1(3); i++) { if (summon_specific(py, px, p_ptr->depth, 0, 1)) *ident = TRUE; } return TRUE; } case EF_SUMMON_UNDEAD: { int i; sound(MSG_SUM_UNDEAD); for (i = 0; i < randint1(3); i++) { if (summon_specific(py, px, p_ptr->depth, S_UNDEAD, 1)) *ident = TRUE; } return TRUE; } case EF_TELE_PHASE: { teleport_player(10); *ident = TRUE; return TRUE; } case EF_TELE_LONG: { teleport_player(100); *ident = TRUE; return TRUE; } case EF_TELE_LEVEL: { (void)teleport_player_level(); *ident = TRUE; return TRUE; } case EF_CONFUSING: { if (p_ptr->confusing == 0) { msg("Your hands begin to glow."); p_ptr->confusing = TRUE; *ident = TRUE; } return TRUE; } case EF_MAPPING: { map_area(); *ident = TRUE; return TRUE; } case EF_RUNE: { warding_glyph(); *ident = TRUE; return TRUE; } case EF_ACQUIRE: { acquirement(py, px, p_ptr->depth, 1, TRUE); *ident = TRUE; return TRUE; } case EF_ACQUIRE2: { acquirement(py, px, p_ptr->depth, randint1(2) + 1, TRUE); *ident = TRUE; return TRUE; } case EF_ANNOY_MON: { msg("There is a high pitched humming noise."); aggravate_monsters(0); *ident = TRUE; return TRUE; } case EF_CREATE_TRAP: { /* Hack -- no traps in the town */ if (p_ptr->depth == 0) return TRUE; trap_creation(); msg("You hear a low-pitched whistling sound."); *ident = TRUE; return TRUE; } case EF_DESTROY_TDOORS: { if (destroy_doors_touch()) *ident = TRUE; return TRUE; } case EF_RECHARGE: { *ident = TRUE; if (!recharge(60)) return FALSE; return TRUE; } case EF_BANISHMENT: { *ident = TRUE; if (!banishment()) return FALSE; return TRUE; } case EF_DARKNESS: { if (!check_state(OF_RES_DARK, p_ptr->state.flags)) (void)inc_timed(TMD_BLIND, 3 + randint1(5), TRUE, TRUE); unlight_area(10, 3); wieldeds_notice_flag(OF_RES_DARK); *ident = TRUE; return TRUE; } case EF_PROTEVIL: { if (inc_timed(TMD_PROTEVIL, randint1(25) + 3 * p_ptr->lev, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SATISFY: { if (set_food(PY_FOOD_MAX - 1)) *ident = TRUE; return TRUE; } case EF_CURSE_WEAPON: { if (curse_weapon()) *ident = TRUE; return TRUE; } case EF_CURSE_ARMOR: { if (curse_armor()) *ident = TRUE; return TRUE; } case EF_BLESSING: { if (inc_timed(TMD_BLESSED, randint1(12) + 6, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_BLESSING2: { if (inc_timed(TMD_BLESSED, randint1(24) + 12, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_BLESSING3: { if (inc_timed(TMD_BLESSED, randint1(48) + 24, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_RECALL: { set_recall(); *ident = TRUE; return TRUE; } case EF_DEEP_DESCENT: { int i, target_depth = p_ptr->depth; /* Calculate target depth */ for (i = 2; i > 0; i--) { if (is_quest(target_depth)) break; if (target_depth >= MAX_DEPTH - 1) break; target_depth++; } if (target_depth > p_ptr->depth) { msgt(MSG_TPLEVEL, "You sink through the floor..."); dungeon_change_level(target_depth); *ident = TRUE; return TRUE; } else { msgt(MSG_TPLEVEL, "You sense a malevolent presence blocking passage to the levels below."); *ident = TRUE; return FALSE; } } case EF_LOSHASTE: { if (speed_monsters()) *ident = TRUE; return TRUE; } case EF_LOSSLEEP: { if (sleep_monsters(aware)) *ident = TRUE; return TRUE; } case EF_LOSSLOW: { if (slow_monsters()) *ident = TRUE; return TRUE; } case EF_LOSCONF: { if (confuse_monsters(aware)) *ident = TRUE; return TRUE; } case EF_LOSKILL: { (void)mass_banishment(); *ident = TRUE; return TRUE; } case EF_EARTHQUAKES: { earthquake(py, px, 10); *ident = TRUE; return TRUE; } case EF_DESTRUCTION2: { destroy_area(py, px, 15, TRUE); *ident = TRUE; return TRUE; } case EF_ILLUMINATION: { if (light_area(damroll(2, 15), 3)) *ident = TRUE; return TRUE; } case EF_CLAIRVOYANCE: { *ident = TRUE; wiz_light(); (void)detect_traps(TRUE); (void)detect_doorstairs(TRUE); return TRUE; } case EF_PROBING: { *ident = probing(); return TRUE; } case EF_STONE_TO_MUD: { if (wall_to_mud(dir)) *ident = TRUE; return TRUE; } case EF_CONFUSE2: { *ident = TRUE; confuse_monster(dir, 20, aware); return TRUE; } case EF_BIZARRE: { *ident = TRUE; ring_of_power(dir); return TRUE; } case EF_STAR_BALL: { int i; *ident = TRUE; for (i = 0; i < 8; i++) fire_ball(GF_ELEC, ddd[i], (150 * (100 + boost) / 100), 3); return TRUE; } case EF_RAGE_BLESS_RESIST: { dur = randint1(50) + 50; *ident = TRUE; (void)hp_player(30); (void)clear_timed(TMD_AFRAID, TRUE); (void)inc_timed(TMD_BOLD, dur, TRUE, TRUE); (void)inc_timed(TMD_SHERO, dur, TRUE, TRUE); (void)inc_timed(TMD_BLESSED, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(TMD_OPP_ACID, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(TMD_OPP_ELEC, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(TMD_OPP_FIRE, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(TMD_OPP_COLD, randint1(50) + 50, TRUE, TRUE); (void)inc_timed(TMD_OPP_POIS, randint1(50) + 50, TRUE, TRUE); return TRUE; } case EF_SLEEPII: { *ident = TRUE; sleep_monsters_touch(aware); return TRUE; } case EF_RESTORE_LIFE: { *ident = TRUE; restore_level(); return TRUE; } case EF_MISSILE: { *ident = TRUE; dam = damroll(3, 4) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_MISSILE, dir, dam); return TRUE; } case EF_DISPEL_EVIL: { *ident = TRUE; dam = p_ptr->lev * 5 * (100 + boost) / 100; dispel_evil(dam); return TRUE; } case EF_DISPEL_EVIL60: { dam = 60 * (100 + boost) / 100; if (dispel_evil(dam)) *ident = TRUE; return TRUE; } case EF_DISPEL_UNDEAD: { dam = 60 * (100 + boost) / 100; if (dispel_undead(dam)) *ident = TRUE; return TRUE; } case EF_DISPEL_ALL: { dam = 120 * (100 + boost) / 100; if (dispel_monsters(dam)) *ident = TRUE; return TRUE; } case EF_HASTE: { if (!p_ptr->timed[TMD_FAST]) { if (set_timed(TMD_FAST, damroll(2, 10) + 20, TRUE)) *ident = TRUE; } else { (void)inc_timed(TMD_FAST, 5, TRUE, TRUE); } return TRUE; } case EF_HASTE1: { if (!p_ptr->timed[TMD_FAST]) { if (set_timed(TMD_FAST, randint1(20) + 20, TRUE)) *ident = TRUE; } else { (void)inc_timed(TMD_FAST, 5, TRUE, TRUE); } return TRUE; } case EF_HASTE2: { if (!p_ptr->timed[TMD_FAST]) { if (set_timed(TMD_FAST, randint1(75) + 75, TRUE)) *ident = TRUE; } else { (void)inc_timed(TMD_FAST, 5, TRUE, TRUE); } return TRUE; } case EF_FIRE_BOLT: { *ident = TRUE; dam = damroll(9, 8) * (100 + boost) / 100; fire_bolt(GF_FIRE, dir, dam); return TRUE; } case EF_FIRE_BOLT2: { dam = damroll(12, 8) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_FIRE, dir, dam); *ident = TRUE; return TRUE; } case EF_FIRE_BOLT3: { dam = damroll(16, 8) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_FIRE, dir, dam); *ident = TRUE; return TRUE; } case EF_FIRE_BOLT72: { dam = 72 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_FIRE, dir, dam, 2); return TRUE; } case EF_FIRE_BALL: { dam = 144 * (100 + boost) / 100; fire_ball(GF_FIRE, dir, dam, 2); *ident = TRUE; return TRUE; } case EF_FIRE_BALL2: { dam = 120 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_FIRE, dir, dam, 3); return TRUE; } case EF_FIRE_BALL200: { dam = 200 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_FIRE, dir, dam, 3); return TRUE; } case EF_COLD_BOLT: { dam = damroll(6, 8) * (100 + boost) / 100; *ident = TRUE; fire_bolt_or_beam(beam, GF_COLD, dir, dam); return TRUE; } case EF_COLD_BOLT2: { dam = damroll(12, 8) * (100 + boost) / 100; *ident = TRUE; fire_bolt(GF_COLD, dir, dam); return TRUE; } case EF_COLD_BALL2: { dam = 200 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 3); return TRUE; } case EF_COLD_BALL50: { dam = 50 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 2); return TRUE; } case EF_COLD_BALL100: { dam = 100 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 2); return TRUE; } case EF_COLD_BALL160: { dam = 160 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 3); return TRUE; } case EF_ACID_BOLT: { dam = damroll(5, 8) * (100 + boost) / 100; *ident = TRUE; fire_bolt(GF_ACID, dir, dam); return TRUE; } case EF_ACID_BOLT2: { dam = damroll(10, 8) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_ACID, dir, dam); *ident = TRUE; return TRUE; } case EF_ACID_BOLT3: { dam = damroll(12, 8) * (100 + boost) / 100; fire_bolt_or_beam(beam, GF_ACID, dir, dam); *ident = TRUE; return TRUE; } case EF_ACID_BALL: { dam = 120 * (100 + boost) / 100; fire_ball(GF_ACID, dir, dam, 2); *ident = TRUE; return TRUE; } case EF_ELEC_BOLT: { dam = damroll(6, 6) * (100 + boost) / 100; *ident = TRUE; fire_beam(GF_ELEC, dir, dam); return TRUE; } case EF_ELEC_BALL: { dam = 64 * (100 + boost) / 100; fire_ball(GF_ELEC, dir, dam, 2); *ident = TRUE; return TRUE; } case EF_ELEC_BALL2: { dam = 250 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_ELEC, dir, dam, 3); return TRUE; } case EF_ARROW: { dam = 150 * (100 + boost) / 100; *ident = TRUE; fire_bolt(GF_ARROW, dir, dam); return TRUE; } case EF_REM_FEAR_POIS: { *ident = TRUE; (void)clear_timed(TMD_AFRAID, TRUE); (void)clear_timed(TMD_POISONED, TRUE); return TRUE; } case EF_STINKING_CLOUD: { dam = 12 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_POIS, dir, dam, 3); return TRUE; } case EF_DRAIN_LIFE1: { dam = 90 * (100 + boost) / 100; if (drain_life(dir, dam)) *ident = TRUE; return TRUE; } case EF_DRAIN_LIFE2: { dam = 120 * (100 + boost) / 100; if (drain_life(dir, dam)) *ident = TRUE; return TRUE; } case EF_DRAIN_LIFE3: { dam = 150 * (100 + boost) / 100; if (drain_life(dir, dam)) *ident = TRUE; return TRUE; } case EF_DRAIN_LIFE4: { dam = 250 * (100 + boost) / 100; if (drain_life(dir, dam)) *ident = TRUE; return TRUE; } case EF_FIREBRAND: { *ident = TRUE; if (!brand_bolts()) return FALSE; return TRUE; } case EF_MANA_BOLT: { dam = damroll(12, 8) * (100 + boost) / 100; fire_bolt(GF_MANA, dir, dam); *ident = TRUE; return TRUE; } case EF_MON_HEAL: { if (heal_monster(dir)) *ident = TRUE; return TRUE; } case EF_MON_HASTE: { if (speed_monster(dir)) *ident = TRUE; return TRUE; } case EF_MON_SLOW: { if (slow_monster(dir)) *ident = TRUE; return TRUE; } case EF_MON_CONFUSE: { if (confuse_monster(dir, 10, aware)) *ident = TRUE; return TRUE; } case EF_MON_SLEEP: { if (sleep_monster(dir, aware)) *ident = TRUE; return TRUE; } case EF_MON_CLONE: { if (clone_monster(dir)) *ident = TRUE; return TRUE; } case EF_MON_SCARE: { if (fear_monster(dir, 10, aware)) *ident = TRUE; return TRUE; } case EF_LIGHT_LINE: { msg("A line of shimmering blue light appears."); light_line(dir); *ident = TRUE; return TRUE; } case EF_TELE_OTHER: { if (teleport_monster(dir)) *ident = TRUE; return TRUE; } case EF_DISARMING: { if (disarm_trap(dir)) *ident = TRUE; return TRUE; } case EF_TDOOR_DEST: { if (destroy_door(dir)) *ident = TRUE; return TRUE; } case EF_POLYMORPH: { if (poly_monster(dir)) *ident = TRUE; return TRUE; } case EF_STARLIGHT: { int i; if (!p_ptr->timed[TMD_BLIND]) msg("Light shoots in all directions!"); for (i = 0; i < 8; i++) light_line(ddd[i]); *ident = TRUE; return TRUE; } case EF_STARLIGHT2: { int k; for (k = 0; k < 8; k++) strong_light_line(ddd[k]); *ident = TRUE; return TRUE; } case EF_BERSERKER: { dur = randint1(50) + 50; if (inc_timed(TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE; if (inc_timed(TMD_SHERO, dur, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_WONDER: { if (effect_wonder(dir, randint1(100) + p_ptr->lev / 5, beam)) *ident = TRUE; return TRUE; } case EF_WAND_BREATH: { /* table of random ball effects and their damages */ const int breath_types[] = { GF_ACID, 200, GF_ELEC, 160, GF_FIRE, 200, GF_COLD, 160, GF_POIS, 120 }; /* pick a random (type, damage) tuple in the table */ int which = 2 * randint0(sizeof(breath_types) / (2 * sizeof(int))); fire_ball(breath_types[which], dir, breath_types[which + 1], 3); *ident = TRUE; return TRUE; } case EF_STAFF_MAGI: { if (do_res_stat(A_INT)) *ident = TRUE; if (p_ptr->csp < p_ptr->msp) { p_ptr->csp = p_ptr->msp; p_ptr->csp_frac = 0; *ident = TRUE; msg("Your feel your head clear."); p_ptr->redraw |= (PR_MANA); } return TRUE; } case EF_STAFF_HOLY: { dam = 120 * (100 + boost) / 100; if (dispel_evil(dam)) *ident = TRUE; if (inc_timed(TMD_PROTEVIL, randint1(25) + 3 * p_ptr->lev, TRUE, TRUE)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; if (clear_timed(TMD_AFRAID, TRUE)) *ident = TRUE; if (hp_player(50)) *ident = TRUE; if (clear_timed(TMD_STUN, TRUE)) *ident = TRUE; if (clear_timed(TMD_CUT, TRUE)) *ident = TRUE; return TRUE; } case EF_DRINK_BREATH: { const int breath_types[] = { GF_FIRE, 80, GF_COLD, 80, }; int which = 2 * randint0(N_ELEMENTS(breath_types) / 2); fire_ball(breath_types[which], dir, breath_types[which + 1], 2); *ident = TRUE; return TRUE; } case EF_DRINK_GOOD: { msg("You feel less thirsty."); *ident = TRUE; return TRUE; } case EF_DRINK_DEATH: { msg("A feeling of Death flows through your body."); take_hit(5000, "a potion of Death"); *ident = TRUE; return TRUE; } case EF_DRINK_RUIN: { msg("Your nerves and muscles feel weak and lifeless!"); take_hit(damroll(10, 10), "a potion of Ruination"); player_stat_dec(p_ptr, A_DEX, TRUE); player_stat_dec(p_ptr, A_WIS, TRUE); player_stat_dec(p_ptr, A_CON, TRUE); player_stat_dec(p_ptr, A_STR, TRUE); player_stat_dec(p_ptr, A_CHR, TRUE); player_stat_dec(p_ptr, A_INT, TRUE); *ident = TRUE; return TRUE; } case EF_DRINK_DETONATE: { msg("Massive explosions rupture your body!"); take_hit(damroll(50, 20), "a potion of Detonation"); (void)inc_timed(TMD_STUN, 75, TRUE, TRUE); (void)inc_timed(TMD_CUT, 5000, TRUE, TRUE); *ident = TRUE; return TRUE; } case EF_DRINK_SALT: { msg("The potion makes you vomit!"); (void)set_food(PY_FOOD_STARVE - 1); (void)clear_timed(TMD_POISONED, TRUE); (void)inc_timed(TMD_PARALYZED, 4, TRUE, FALSE); *ident = TRUE; return TRUE; } case EF_FOOD_GOOD: { msg("That tastes good."); *ident = TRUE; return TRUE; } case EF_FOOD_WAYBREAD: { msg("That tastes good."); (void)clear_timed(TMD_POISONED, TRUE); (void)hp_player(damroll(4, 8)); *ident = TRUE; return TRUE; } case EF_SHROOM_EMERGENCY: { (void)set_timed(TMD_IMAGE, rand_spread(250, 50), TRUE); (void)set_timed(TMD_OPP_FIRE, rand_spread(30, 10), TRUE); (void)set_timed(TMD_OPP_COLD, rand_spread(30, 10), TRUE); (void)hp_player(200); *ident = TRUE; return TRUE; } case EF_SHROOM_TERROR: { if (set_timed(TMD_TERROR, rand_spread(100, 20), TRUE)) *ident = TRUE; return TRUE; } case EF_SHROOM_STONE: { if (set_timed(TMD_STONESKIN, rand_spread(80, 20), TRUE)) *ident = TRUE; return TRUE; } case EF_SHROOM_DEBILITY: { int stat = one_in_(2) ? A_STR : A_CON; if (p_ptr->csp < p_ptr->msp) { p_ptr->csp = p_ptr->msp; p_ptr->csp_frac = 0; msg("Your feel your head clear."); p_ptr->redraw |= (PR_MANA); *ident = TRUE; } (void)do_dec_stat(stat, FALSE); *ident = TRUE; return TRUE; } case EF_SHROOM_SPRINTING: { if (inc_timed(TMD_SPRINT, 100, TRUE, TRUE)) *ident = TRUE; return TRUE; } case EF_SHROOM_PURGING: { (void)set_food(PY_FOOD_FAINT - 1); if (do_res_stat(A_STR)) *ident = TRUE; if (do_res_stat(A_CON)) *ident = TRUE; if (clear_timed(TMD_POISONED, TRUE)) *ident = TRUE; return TRUE; } case EF_RING_ACID: { dam = 70 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_ACID, dir, dam, 2); inc_timed(TMD_OPP_ACID, randint1(20) + 20, TRUE, TRUE); return TRUE; } case EF_RING_FLAMES: { dam = 80 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_FIRE, dir, dam, 2); inc_timed(TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE); return TRUE; } case EF_RING_ICE: { dam = 75 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_COLD, dir, dam, 2); inc_timed(TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE); return TRUE; } case EF_RING_LIGHTNING: { dam = 85 * (100 + boost) / 100; *ident = TRUE; fire_ball(GF_ELEC, dir, dam, 2); inc_timed(TMD_OPP_ELEC, randint1(20) + 20, TRUE, TRUE); return TRUE; } case EF_DRAGON_BLUE: { dam = 100 * (100 + boost) / 100; msgt(MSG_BR_ELEC, "You breathe lightning."); fire_ball(GF_ELEC, dir, dam, 2); return TRUE; } case EF_DRAGON_GREEN: { dam = 150 * (100 + boost) / 100; msgt(MSG_BR_GAS, "You breathe poison gas."); fire_ball(GF_POIS, dir, dam, 2); return TRUE; } case EF_DRAGON_RED: { dam = 200 * (100 + boost) / 100; msgt(MSG_BR_FIRE, "You breathe fire."); fire_ball(GF_FIRE, dir, dam, 2); return TRUE; } case EF_DRAGON_MULTIHUED: { static const struct { int msg_sound; const char *msg; int typ; } mh[] = { { MSG_BR_ELEC, "lightning", GF_ELEC }, { MSG_BR_FROST, "frost", GF_COLD }, { MSG_BR_ACID, "acid", GF_ACID }, { MSG_BR_GAS, "poison gas", GF_POIS }, { MSG_BR_FIRE, "fire", GF_FIRE } }; int chance = randint0(5); dam = 250 * (100 + boost) / 100; msgt(mh[chance].msg_sound, "You breathe %s.", mh[chance].msg); fire_ball(mh[chance].typ, dir, dam, 2); return TRUE; } case EF_DRAGON_BRONZE: { dam = 120 * (100 + boost) / 100; msgt(MSG_BR_CONF, "You breathe confusion."); fire_ball(GF_CONFU, dir, dam, 2); return TRUE; } case EF_DRAGON_GOLD: { dam = 130 * (100 + boost) / 100; msgt(MSG_BR_SOUND, "You breathe sound."); fire_ball(GF_SOUND, dir, dam, 2); return TRUE; } case EF_DRAGON_CHAOS: { dam = 220 * (100 + boost) / 100; chance = randint0(2); msgt((chance == 1 ? MSG_BR_CHAOS : MSG_BR_DISEN), "You breathe %s.", ((chance == 1 ? "chaos" : "disenchantment"))); fire_ball((chance == 1 ? GF_CHAOS : GF_DISEN), dir, dam, 2); return TRUE; } case EF_DRAGON_LAW: { dam = 230 * (100 + boost) / 100; chance = randint0(2); msgt((chance == 1 ? MSG_BR_SOUND : MSG_BR_SHARDS), "You breathe %s.", ((chance == 1 ? "sound" : "shards"))); fire_ball((chance == 1 ? GF_SOUND : GF_SHARD), dir, dam, 2); return TRUE; } case EF_DRAGON_BALANCE: { dam = 250 * (100 + boost) / 100; chance = randint0(4); msg("You breathe %s.", ((chance == 1) ? "chaos" : ((chance == 2) ? "disenchantment" : ((chance == 3) ? "sound" : "shards")))); fire_ball(((chance == 1) ? GF_CHAOS : ((chance == 2) ? GF_DISEN : ((chance == 3) ? GF_SOUND : GF_SHARD))), dir, dam, 2); return TRUE; } case EF_DRAGON_SHINING: { dam = 200 * (100 + boost) / 100; chance = randint0(2); msgt((chance == 0 ? MSG_BR_LIGHT : MSG_BR_DARK), "You breathe %s.", ((chance == 0 ? "light" : "darkness"))); fire_ball((chance == 0 ? GF_LIGHT : GF_DARK), dir, dam, 2); return TRUE; } case EF_DRAGON_POWER: { dam = 300 * (100 + boost) / 100; msgt(MSG_BR_ELEMENTS, "You breathe the elements."); fire_ball(GF_MISSILE, dir, dam, 2); return TRUE; } case EF_TRAP_DOOR: { msg("You fall through a trap door!"); if (check_state(OF_FEATHER, p_ptr->state.flags)) { msg("You float gently down to the next level."); } else { take_hit(damroll(2, 8), "a trap"); } wieldeds_notice_flag(OF_FEATHER); dungeon_change_level(p_ptr->depth + 1); return TRUE; } case EF_TRAP_PIT: { msg("You fall into a pit!"); if (check_state(OF_FEATHER, p_ptr->state.flags)) { msg("You float gently to the bottom of the pit."); } else { take_hit(damroll(2, 6), "a trap"); } wieldeds_notice_flag(OF_FEATHER); return TRUE; } case EF_TRAP_PIT_SPIKES: { msg("You fall into a spiked pit!"); if (check_state(OF_FEATHER, p_ptr->state.flags)) { msg("You float gently to the floor of the pit."); msg("You carefully avoid touching the spikes."); } else { int dam = damroll(2, 6); /* Extra spike damage */ if (one_in_(2)) { msg("You are impaled!"); dam *= 2; (void)inc_timed(TMD_CUT, randint1(dam), TRUE, TRUE); } take_hit(dam, "a trap"); } wieldeds_notice_flag(OF_FEATHER); return TRUE; } case EF_TRAP_PIT_POISON: { msg("You fall into a spiked pit!"); if (check_state(OF_FEATHER, p_ptr->state.flags)) { msg("You float gently to the floor of the pit."); msg("You carefully avoid touching the spikes."); } else { int dam = damroll(2, 6); /* Extra spike damage */ if (one_in_(2)) { msg("You are impaled on poisonous spikes!"); (void)inc_timed(TMD_CUT, randint1(dam * 2), TRUE, TRUE); (void)inc_timed(TMD_POISONED, randint1(dam * 4), TRUE, TRUE); } take_hit(dam, "a trap"); } wieldeds_notice_flag(OF_FEATHER); return TRUE; } case EF_TRAP_RUNE_SUMMON: { int i; int num = 2 + randint1(3); msgt(MSG_SUM_MONSTER, "You are enveloped in a cloud of smoke!"); /* Remove trap */ cave->info[py][px] &= ~(CAVE_MARK); cave_set_feat(cave, py, px, FEAT_FLOOR); for (i = 0; i < num; i++) (void)summon_specific(py, px, p_ptr->depth, 0, 1); break; } case EF_TRAP_RUNE_TELEPORT: { msg("You hit a teleport trap!"); teleport_player(100); return TRUE; } case EF_TRAP_SPOT_FIRE: { int dam; msg("You are enveloped in flames!"); dam = damroll(4, 6); dam = adjust_dam(GF_FIRE, dam, RANDOMISE, check_for_resist(GF_FIRE, p_ptr->state.flags, TRUE)); if (dam) { take_hit(dam, "a fire trap"); inven_damage(GF_FIRE, MIN(dam * 5, 300)); } return TRUE; } case EF_TRAP_SPOT_ACID: { int dam; msg("You are splashed with acid!"); dam = damroll(4, 6); dam = adjust_dam(GF_ACID, dam, RANDOMISE, check_for_resist(GF_ACID, p_ptr->state.flags, TRUE)); if (dam) { take_hit(dam, "an acid trap"); inven_damage(GF_ACID, MIN(dam * 5, 300)); } return TRUE; } case EF_TRAP_DART_SLOW: { if (trap_check_hit(125)) { msg("A small dart hits you!"); take_hit(damroll(1, 4), "a trap"); (void)inc_timed(TMD_SLOW, randint0(20) + 20, TRUE, FALSE); } else { msg("A small dart barely misses you."); } return TRUE; } case EF_TRAP_DART_LOSE_STR: { if (trap_check_hit(125)) { msg("A small dart hits you!"); take_hit(damroll(1, 4), "a trap"); (void)do_dec_stat(A_STR, FALSE); } else { msg("A small dart barely misses you."); } return TRUE; } case EF_TRAP_DART_LOSE_DEX: { if (trap_check_hit(125)) { msg("A small dart hits you!"); take_hit(damroll(1, 4), "a trap"); (void)do_dec_stat(A_DEX, FALSE); } else { msg("A small dart barely misses you."); } return TRUE; } case EF_TRAP_DART_LOSE_CON: { if (trap_check_hit(125)) { msg("A small dart hits you!"); take_hit(damroll(1, 4), "a trap"); (void)do_dec_stat(A_CON, FALSE); } else { msg("A small dart barely misses you."); } return TRUE; } case EF_TRAP_GAS_BLIND: { msg("You are surrounded by a black gas!"); (void)inc_timed(TMD_BLIND, randint0(50) + 25, TRUE, TRUE); return TRUE; } case EF_TRAP_GAS_CONFUSE: { msg("You are surrounded by a gas of scintillating colors!"); (void)inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE, TRUE); return TRUE; } case EF_TRAP_GAS_POISON: { msg("You are surrounded by a pungent green gas!"); (void)inc_timed(TMD_POISONED, randint0(20) + 10, TRUE, TRUE); return TRUE; } case EF_TRAP_GAS_SLEEP: { msg("You are surrounded by a strange white mist!"); (void)inc_timed(TMD_PARALYZED, randint0(10) + 5, TRUE, TRUE); return TRUE; } case EF_XXX: case EF_MAX: break; } /* Not used */ msg("Effect not handled."); return FALSE; }
static void display_resistance_panel(const struct player_flag_record *rec, size_t size, const region *bounds) { size_t i; int j; int col = bounds->col; int row = bounds->row; int res_cols = 5 + 2 + player->body.count; Term_putstr(col, row++, res_cols, COLOUR_WHITE, " abcdefghijkl@"); for (i = 0; i < size - 3; i++, row++) { byte name_attr = COLOUR_WHITE; Term_gotoxy(col + 6, row); /* Repeated extraction of flags is inefficient but more natural */ for (j = 0; j <= player->body.count; j++) { struct object *obj; bitflag f[OF_SIZE]; byte attr = COLOUR_WHITE | (j % 2) * 8; /* alternating columns */ char sym = '.'; bool res = false, imm = false, vul = false, rune = false; bool timed = false; bool known = false; /* Wipe flagset */ of_wipe(f); /* Get the object or player info */ obj = j < player->body.count ? slot_object(player, j) : NULL; if (j < player->body.count && obj) { /* Get known properties */ object_flags_known(obj, f); if (rec[i].element != -1) known = object_element_is_known(obj, rec[i].element); else if (rec[i].flag != -1) known = object_flag_is_known(obj, rec[i].flag); else known = true; } else if (j == player->body.count) { player_flags(player, f); known = true; /* Timed flags only in the player column */ if (rec[i].tmd_flag >= 0) { timed = player->timed[rec[i].tmd_flag] ? true : false; /* There has to be one special case... */ if ((rec[i].tmd_flag == TMD_AFRAID) && (player->timed[TMD_TERROR])) timed = true; } } /* Set which (if any) symbol and color are used */ if (rec[i].mod != -1) { if (j != player->body.count) res = (obj && (obj->modifiers[rec[i].mod] != 0)); else { /* Messy special cases */ if (rec[i].mod == OBJ_MOD_INFRA) res = (player->race->infra > 0); if (rec[i].mod == OBJ_MOD_TUNNEL) res = (player->race->r_skills[SKILL_DIGGING] > 0); } rune = (player->obj_k->modifiers[rec[i].mod] == 1); } else if (rec[i].flag != -1) { res = of_has(f, rec[i].flag); rune = of_has(player->obj_k->flags, rec[i].flag); } else if (rec[i].element != -1) { if (j != player->body.count) { imm = obj && known && (obj->el_info[rec[i].element].res_level == 3); res = obj && known && (obj->el_info[rec[i].element].res_level == 1); vul = obj && known && (obj->el_info[rec[i].element].res_level == -1); } else { imm = player->race->el_info[rec[i].element].res_level == 3; res = player->race->el_info[rec[i].element].res_level == 1; vul = player->race->el_info[rec[i].element].res_level == -1; } rune = (player->obj_k->el_info[rec[i].element].res_level == 1); } /* Set the symbols and print them */ if (imm) name_attr = COLOUR_GREEN; else if (!rune) name_attr = COLOUR_SLATE; else if (res && (name_attr != COLOUR_GREEN)) name_attr = COLOUR_L_BLUE; if (vul) sym = '-'; else if (imm) sym = '*'; else if (res) sym = '+'; else if (timed) { sym = '!'; attr = COLOUR_L_GREEN; } else if ((j < player->body.count) && obj && !known && !rune) sym = '?'; Term_addch(attr, sym); } Term_putstr(col, row, 6, name_attr, format("%5s:", rec[i].name)); } Term_putstr(col, row++, res_cols, COLOUR_WHITE, " abcdefghijkl@"); /* Equippy */ display_player_equippy(row++, col + 6); }
/* * This will get data on an object * It gets a lot of stuff, pretty much everything that I * thought was reasonable to get. However, you might have * a much different opinion. Luckily, I tried to make it * trivial to add new items to log. */ static void get_obj_data(const struct object *obj, int y, int x, bool mon, bool uniq) { bool vault = square_isvault(cave, y, x); int number = obj->number; static int lvl; struct artifact *art; double gold_temp = 0; assert(obj->kind); /* get player depth */ lvl = player->depth; /* check for some stuff that we will use regardless of type */ /* originally this was armor, but I decided to generalize it */ /* has free action (hack: don't include Inertia)*/ if (of_has(obj->flags, OF_FREE_ACT) && !((obj->tval == TV_AMULET) && (!strstr(obj->kind->name, "Inertia")))) { /* add the stats */ add_stats(ST_FA_EQUIPMENT, vault, mon, number); /* record first level */ first_find(ST_FF_FA); } /* has see invis */ if (of_has(obj->flags, OF_SEE_INVIS)){ add_stats(ST_SI_EQUIPMENT, vault, mon, number); first_find(ST_FF_SI); } /* has at least one basic resist */ if ((obj->el_info[ELEM_ACID].res_level == 1) || (obj->el_info[ELEM_ELEC].res_level == 1) || (obj->el_info[ELEM_COLD].res_level == 1) || (obj->el_info[ELEM_FIRE].res_level == 1)){ add_stats(ST_RESIST_EQUIPMENT, vault, mon, number); } /* has rbase */ if ((obj->el_info[ELEM_ACID].res_level == 1) && (obj->el_info[ELEM_ELEC].res_level == 1) && (obj->el_info[ELEM_COLD].res_level == 1) && (obj->el_info[ELEM_FIRE].res_level == 1)) add_stats(ST_RBASE_EQUIPMENT, vault, mon, number); /* has resist poison */ if (obj->el_info[ELEM_POIS].res_level == 1){ add_stats(ST_RPOIS_EQUIPMENT, vault, mon, number); first_find(ST_FF_RPOIS); } /* has resist nexus */ if (obj->el_info[ELEM_NEXUS].res_level == 1){ add_stats(ST_RNEXUS_EQUIPMENT, vault, mon, number); first_find(ST_FF_RNEXUS); } /* has resist blind */ if (of_has(obj->flags, OF_PROT_BLIND)){ add_stats(ST_RBLIND_EQUIPMENT, vault, mon, number); first_find(ST_FF_RBLIND); } /* has resist conf */ if (of_has(obj->flags, OF_PROT_CONF)){ add_stats(ST_RCONF_EQUIPMENT, vault, mon, number); first_find(ST_FF_RCONF); } /* has speed */ if (obj->modifiers[OBJ_MOD_SPEED] != 0) add_stats(ST_SPEED_EQUIPMENT, vault, mon, number); /* has telepathy */ if (of_has(obj->flags, OF_TELEPATHY)){ add_stats(ST_TELEP_EQUIPMENT, vault, mon, number); first_find(ST_FF_TELEP); } switch(obj->tval){ /* armor */ case TV_BOOTS: case TV_GLOVES: case TV_HELM: case TV_CROWN: case TV_SHIELD: case TV_CLOAK: case TV_SOFT_ARMOR: case TV_HARD_ARMOR: case TV_DRAG_ARMOR:{ /* do not include artifacts */ if (obj->artifact) break; /* add to armor total */ add_stats(ST_ARMORS, vault, mon, number); /* check if bad, good, or average */ if (obj->to_a < 0) add_stats(ST_BAD_ARMOR, vault, mon, number); if (obj->to_h == 0) add_stats(ST_AVERAGE_ARMOR, vault, mon, number); if (obj->to_h > 0) add_stats(ST_GOOD_ARMOR, vault, mon, number); /* has str boost */ if (obj->modifiers[OBJ_MOD_STR] != 0) add_stats(ST_STR_ARMOR, vault, mon, number); /* has dex boost */ if (obj->modifiers[OBJ_MOD_DEX] != 0) add_stats(ST_DEX_ARMOR, vault, mon, number); /* has int boost */ if (obj->modifiers[OBJ_MOD_INT] != 0) add_stats(ST_INT_ARMOR, vault, mon, number); if (obj->modifiers[OBJ_MOD_WIS] != 0) add_stats(ST_WIS_ARMOR, vault, mon, number); if (obj->modifiers[OBJ_MOD_CON] != 0) add_stats(ST_CON_ARMOR, vault, mon, number); if (of_has(obj->flags, OF_LIGHT_CURSE)) add_stats(ST_CURSED_ARMOR, vault, mon, number); break; } /* weapons */ case TV_DIGGING: case TV_HAFTED: case TV_POLEARM: case TV_SWORD:{ /* do not include artifacts */ if (obj->artifact) break; /* add to weapon total */ add_stats(ST_WEAPONS, vault, mon, number); /* check if bad, good, or average */ if ((obj->to_h < 0) && (obj->to_d < 0)) add_stats(ST_BAD_WEAPONS, vault, mon, number); if ((obj->to_h == 0) && (obj->to_d == 0)) add_stats(ST_AVERAGE_WEAPONS, vault, mon, number); if ((obj->to_h > 0) && (obj->to_d > 0)) add_stats(ST_GOOD_WEAPONS, vault, mon, number); /* Egos by name - changes results a little */ if (obj->ego) { /* slay evil */ if (strstr(obj->ego->name, "of Slay Evil")) add_stats(ST_SLAYEVIL_WEAPONS, vault, mon, number); /* slay weapons */ else if (strstr(obj->ego->name, "of Slay")) add_stats(ST_SLAY_WEAPONS, vault, mon, number); /* kill flag */ if (strstr(obj->ego->name, "of *Slay")) add_stats(ST_KILL_WEAPONS, vault, mon, number); /* determine westernesse by flags */ if (strstr(obj->ego->name, "Westernesse")) add_stats(ST_WESTERNESSE_WEAPONS, vault, mon, number); /* determine defender by flags */ if (strstr(obj->ego->name, "Defender")) add_stats(ST_DEFENDER_WEAPONS, vault, mon, number); /* determine gondolin by flags */ if (strstr(obj->ego->name, "Gondolin")) add_stats(ST_GONDOLIN_WEAPONS, vault, mon, number); /* determine holy avenger by flags */ if (strstr(obj->ego->name, "Avenger")) add_stats(ST_HOLY_WEAPONS, vault, mon, number); /* is morgul */ if (strstr(obj->ego->name, "Morgul")) add_stats(ST_MORGUL_WEAPONS, vault, mon, number); } /* branded weapons */ if (obj->brands) add_stats(ST_BRAND_WEAPONS, vault, mon, number); /* extra blows */ if (obj->modifiers[OBJ_MOD_BLOWS] > 0) add_stats(ST_XTRABLOWS_WEAPONS, vault, mon, number); /* telepathy */ if (of_has(obj->flags, OF_TELEPATHY)) add_stats(ST_TELEP_WEAPONS, vault, mon, number); /* is a top of the line weapon */ if (((obj->tval == TV_HAFTED) && (!strstr(obj->kind->name, "Disruption"))) || ((obj->tval == TV_POLEARM) && (!strstr(obj->kind->name, "Slicing"))) || ((obj->tval == TV_SWORD) && (!strstr(obj->kind->name, "Chaos")))) { add_stats(ST_HUGE_WEAPONS, vault, mon, number); /* is uber need to fix ACB if ((of_has(obj->flags, OF_SLAY_EVIL)) || (obj->modifiers[OBJ_MOD_BLOWS] > 0)) add_stats(ST_UBWE, vault, mon, number); */ } break; } /* launchers */ case TV_BOW:{ /* do not include artifacts */ if (obj->artifact) break; /* add to launcher total */ add_stats(ST_BOWS, vault, mon, number); /* check if bad, average, good, or very good */ if ((obj->to_h < 0) && (obj->to_d < 0)) add_stats(ST_BAD_BOWS, vault, mon, number); if ((obj->to_h == 0) && (obj->to_d == 0)) add_stats(ST_AVERAGE_BOWS, vault, mon, number); if ((obj->to_h > 0) && (obj->to_d > 0)) add_stats(ST_GOOD_BOWS, vault, mon, number); if ((obj->to_h > 15) || (obj->to_d > 15)) add_stats(ST_VERYGOOD_BOWS, vault, mon, number); /* check long bows and xbows for xtra might and/or shots */ if (obj->pval > 2) { if (obj->modifiers[OBJ_MOD_SHOTS] > 0) add_stats(ST_XTRASHOTS_BOWS, vault, mon, number); if (obj->modifiers[OBJ_MOD_MIGHT] > 0) add_stats(ST_XTRAMIGHT_BOWS, vault, mon, number); } /* check for buckland */ if ((obj->pval == 2) && kf_has(obj->kind->kind_flags, KF_SHOOTS_SHOTS) && (obj->modifiers[OBJ_MOD_MIGHT] > 0) && (obj->modifiers[OBJ_MOD_SHOTS] > 0)) add_stats(ST_BUCKLAND_BOWS, vault, mon, number); /* has telep */ if (of_has(obj->flags, OF_TELEPATHY)) add_stats(ST_TELEP_BOWS, vault, mon, number); /* is cursed */ if (of_has(obj->flags, OF_LIGHT_CURSE)) add_stats(ST_CURSED_BOWS, vault, mon, number); break; } /* potion */ case TV_POTION:{ /* Add total amounts */ add_stats(ST_POTIONS, vault, mon, number); /* Stat gain */ if (strstr(obj->kind->name, "Strength") || strstr(obj->kind->name, "Intelligence") || strstr(obj->kind->name, "Wisdom") || strstr(obj->kind->name, "Dexterity") || strstr(obj->kind->name, "Constitution")) { add_stats(ST_GAINSTAT_POTIONS, vault, mon, number); } else if (strstr(obj->kind->name, "Augmentation")) { /* Augmentation counts as 5 stat gain pots */ add_stats(ST_GAINSTAT_POTIONS, vault, mon, number * 5); } else if (strstr(obj->kind->name, "*Enlightenment*")) { /* *Enlight* counts as 2 stat pots */ add_stats(ST_GAINSTAT_POTIONS, vault, mon, number * 2); } else if (strstr(obj->kind->name, "Restore Mana")) { add_stats(ST_RESTOREMANA_POTIONS, vault, mon, number); } else if ((strstr(obj->kind->name, "Life")) || (strstr(obj->kind->name, "*Healing*"))) { add_stats(ST_ELVEN_RINGS, vault, mon, number); } else if (strstr(obj->kind->name, "Healing")) { add_stats(ST_HEALING_POTIONS, vault, mon, number); } break; } /* scrolls */ case TV_SCROLL:{ /* add total amounts */ add_stats(ST_SCROLLS, vault, mon, number); if (strstr(obj->kind->name, "Banishment") || strstr(obj->kind->name, "Mass Banishment") || strstr(obj->kind->name, "Rune of Protection") || strstr(obj->kind->name, "*Destruction*")) { add_stats(ST_ENDGAME_SCROLLS, vault, mon, number); } else if (strstr(obj->kind->name, "Acquirement")) { add_stats(ST_ACQUIRE_SCROLLS, vault, mon, number); } else if (strstr(obj->kind->name, "*Acquirement*")) { /* do the effect of 2 acquires */ add_stats(ST_ACQUIRE_SCROLLS, vault, mon, number * 2); } break; } /* rods */ case TV_ROD:{ /* add to total */ add_stats(ST_RODS, vault, mon, number); if (strstr(obj->kind->name, "Trap Detection") || strstr(obj->kind->name, "Treasure Detection") || strstr(obj->kind->name, "Door/Stair Location") || strstr(obj->kind->name, "Illumination") || strstr(obj->kind->name, "Light")) { add_stats(ST_UTILITY_RODS, vault, mon, number); } else if (strstr(obj->kind->name, "Teleport Other")) { add_stats(ST_TELEPOTHER_RODS, vault, mon, number); } else if (strstr(obj->kind->name, "Detection")) { add_stats(ST_DETECTALL_RODS, vault, mon, number); } else if (strstr(obj->kind->name, "Speed") || strstr(obj->kind->name, "Healing")) { add_stats(ST_ENDGAME_RODS, vault, mon, number); } break; } /* staves */ case TV_STAFF:{ add_stats(ST_STAVES, vault, mon, number); if (strstr(obj->kind->name, "Speed")) { add_stats(ST_SPEED_STAVES, vault, mon, number); } else if (strstr(obj->kind->name, "*Destruction*")) { add_stats(ST_DESTRUCTION_STAVES, vault, mon, number); } else if (strstr(obj->kind->name, "Dispel Evil") || strstr(obj->kind->name, "Power") || strstr(obj->kind->name, "Holiness")) { add_stats(ST_KILL_STAVES, vault, mon, number); } else if (strstr(obj->kind->name, "Healing") || strstr(obj->kind->name, "Banishment") || strstr(obj->kind->name, "the Magi")) { add_stats(ST_ENDGAME_STAVES, vault, mon, number); } break; } case TV_WAND:{ add_stats(ST_WANDS, vault, mon, number); if (strstr(obj->kind->name, "Teleport Other")) add_stats(ST_TELEPOTHER_WANDS, vault, mon, number); break; } case TV_RING:{ add_stats(ST_RINGS, vault, mon, number); /* is it cursed */ if (of_has(obj->flags,OF_LIGHT_CURSE)) add_stats(ST_CURSED_RINGS, vault, mon, number); if (strstr(obj->kind->name, "Speed")) { add_stats(ST_SPEEDS_RINGS, vault, mon, number); } else if ((strstr(obj->kind->name, "Strength")) || (strstr(obj->kind->name, "Intelligence")) || (strstr(obj->kind->name, "Dexterity")) || (strstr(obj->kind->name, "Constitution"))) { add_stats(ST_STAT_RINGS, vault, mon, number); } else if (strstr(obj->kind->name, "Resist Poison")) { add_stats(ST_RPOIS_RINGS, vault, mon, number); } else if (strstr(obj->kind->name, "Free Action")) { add_stats(ST_FA_RINGS, vault, mon, number); } else if (strstr(obj->kind->name, "See invisible")) { add_stats(ST_SI_RINGS, vault, mon, number); } else if ((strstr(obj->kind->name, "Flames")) || (strstr(obj->kind->name, "Ice")) || (strstr(obj->kind->name, "Acid")) || (strstr(obj->kind->name, "Lightning"))) { add_stats(ST_BRAND_RINGS, vault, mon, number); } else if ((strstr(obj->kind->name, "Fire")) || (strstr(obj->kind->name, "Adamant")) || (strstr(obj->kind->name, "Firmament"))) { add_stats(ST_ELVEN_RINGS, vault, mon, number); } else if (strstr(obj->kind->name, "Power")) { add_stats(ST_ONE_RINGS, vault, mon, number); } break; } case TV_AMULET:{ add_stats(ST_AMULETS, vault, mon, number); if (strstr(obj->kind->name, "Wisdom")) { add_stats(ST_WIS_AMULETS, vault, mon, number); } else if ((strstr(obj->kind->name, "Magi")) || (strstr(obj->kind->name, "Trickery")) || (strstr(obj->kind->name, "Weaponmastery"))) { add_stats(ST_ENDGAME_AMULETS, vault, mon, number); } else if (strstr(obj->kind->name, "ESP")) { add_stats(ST_TELEP_AMULETS, vault, mon, number); } /* is cursed */ if (of_has(obj->flags, OF_LIGHT_CURSE)) add_stats(ST_CURSED_AMULETS, vault, mon, number); break; } case TV_SHOT: case TV_ARROW: case TV_BOLT:{ add_stats(ST_AMMO, vault, mon, number); /* check if bad, average, good */ if ((obj->to_h < 0) && (obj->to_d < 0)) add_stats(ST_BAD_AMMO, vault, mon, number); if ((obj->to_h == 0) && (obj->to_d == 0)) add_stats(ST_AVERAGE_AMMO, vault, mon, number); if ((obj->to_h > 0) && (obj->to_d > 0)) add_stats(ST_GOOD_AMMO, vault, mon, number); if (obj->ego) add_stats(ST_BRANDSLAY_AMMO, vault, mon, number); if (strstr(obj->kind->name, "Seeker") || strstr(obj->kind->name, "Mithril")) { /* Mithril and seeker ammo */ add_stats(ST_VERYGOOD_AMMO, vault, mon, number); /* Ego mithril and seeker ammo */ if (obj->ego) { add_stats(ST_AWESOME_AMMO, vault, mon, number); if (strstr(obj->ego->name, "of Slay Evil")) add_stats(ST_SLAYEVIL_AMMO, vault, mon, number); if (strstr(obj->ego->name, "of Holy Might")) add_stats(ST_HOLY_AMMO, vault, mon, number); } } break; } /* prayer books and magic books have the same probability only track one of them */ case TV_MAGIC_BOOK:{ switch(obj->sval){ /* svals begin at 0 and end at 8 */ case 0:{ add_stats(ST_1ST_BOOKS, vault, mon, number); first_find(ST_FF_BOOK1); break; } case 1:{ add_stats(ST_2ND_BOOKS, vault, mon, number); first_find(ST_FF_BOOK2); break; } case 2:{ add_stats(ST_3RD_BOOKS, vault, mon, number); first_find(ST_FF_BOOK3); break; } case 3:{ add_stats(ST_4TH_BOOKS, vault, mon, number); first_find(ST_FF_BOOK4); break; } case 4:{ add_stats(ST_5TH_BOOKS, vault, mon, number); first_find(ST_FF_BOOK5); break; } case 5:{ add_stats(ST_6TH_BOOKS, vault, mon, number); first_find(ST_FF_BOOK6); break; } case 6:{ add_stats(ST_7TH_BOOKS, vault, mon, number); first_find(ST_FF_BOOK7); break; } case 7:{ add_stats(ST_8TH_BOOKS, vault, mon, number); first_find(ST_FF_BOOK8); break; } case 8:{ add_stats(ST_9TH_BOOKS, vault, mon, number); first_find(ST_FF_BOOK9); break; } } break; } } /* check to see if we have an artifact */ if (obj->artifact){ /* add to artifact level total */ art_total[lvl] += addval; /* add to the artifact iteration total */ if (iter < TRIES_SIZE) art_it[iter]++; /* Obtain the artifact info */ art = obj->artifact; //debugging, print out that we found the artifact //msg_format("Found artifact %s",art->name); /* artifact is shallow */ if (art->alloc_min < (player->depth - 20)) art_shal[lvl] += addval; /* artifact is close to the player depth */ if ((art->alloc_min >= player->depth - 20) && (art->alloc_min <= player->depth )) art_ave[lvl] += addval; /* artifact is out of depth */ if (art->alloc_min > (player->depth)) art_ood[lvl] += addval; /* check to see if it's a special artifact */ if ((obj->tval == TV_LIGHT) || (obj->tval == TV_AMULET) || (obj->tval == TV_RING)){ /* increment special artifact counter */ art_spec[lvl] += addval; } else { /* increment normal artifacts */ art_norm[lvl] += addval; /* did it come from a monster? */ if (mon) art_mon[lvl] += addval; /* did it come from a unique? */ if (uniq) art_uniq[lvl] += addval; /* was it in a vault? */ if (vault){ /* did a monster drop it ?*/ if ((mon) || (uniq)) art_mon_vault[lvl] += addval; else art_vault[lvl] += addval; } else { /* was it just lyin' on the floor? */ if ((!uniq) && (!mon)) art_floor[lvl] += addval; } } /* preserve the artifact */ if (!(clearing)) art->created = FALSE; } /* Get info on gold. */ if (obj->tval == TV_GOLD){ int temp = obj->pval; gold_temp = temp; gold_total[lvl] += (gold_temp / tries); /*From a monster? */ if ((mon) || (uniq)) gold_mon[lvl] += (gold_temp / tries); else gold_floor[lvl] += (gold_temp / tries); } }
/** * Wipe an object clean and make it a standard object of the specified kind. */ void object_prep(struct object *obj, struct object_kind *k, int lev, aspect rand_aspect) { int i; /* Clean slate */ memset(obj, 0, sizeof(*obj)); /* Assign the kind and copy across data */ obj->kind = k; obj->tval = k->tval; obj->sval = k->sval; obj->ac = k->ac; obj->dd = k->dd; obj->ds = k->ds; obj->weight = k->weight; obj->effect = k->effect; obj->time = k->time; /* Default number */ obj->number = 1; /* Copy flags */ of_copy(obj->flags, k->base->flags); of_copy(obj->flags, k->flags); /* Assign modifiers */ for (i = 0; i < OBJ_MOD_MAX; i++) obj->modifiers[i] = randcalc(k->modifiers[i], lev, rand_aspect); /* Assign charges (wands/staves only) */ if (tval_can_have_charges(obj)) obj->pval = randcalc(k->charge, lev, rand_aspect); /* Assign pval for food, oil and launchers */ if (tval_is_edible(obj) || tval_is_potion(obj) || tval_is_fuel(obj) || tval_is_launcher(obj)) obj->pval = randcalc(k->pval, lev, rand_aspect); /* Default fuel */ if (tval_is_light(obj)) { if (of_has(obj->flags, OF_BURNS_OUT)) obj->timeout = z_info->fuel_torch; else if (of_has(obj->flags, OF_TAKES_FUEL)) obj->timeout = z_info->default_lamp; } /* Default magic */ obj->to_h = randcalc(k->to_h, lev, rand_aspect); obj->to_d = randcalc(k->to_d, lev, rand_aspect); obj->to_a = randcalc(k->to_a, lev, rand_aspect); /* Default slays and brands */ copy_slay(&obj->slays, k->slays); copy_brand(&obj->brands, k->brands); /* Default resists */ for (i = 0; i < ELEM_MAX; i++) { obj->el_info[i].res_level = k->el_info[i].res_level; obj->el_info[i].flags = k->el_info[i].flags; obj->el_info[i].flags |= k->base->el_info[i].flags; } }