/* * Checks for additional knowledge implied by what the player already knows. * * \param o_ptr is the object to check * * returns whether it calls object_notice_everyting */ bool object_check_for_ident(object_type *o_ptr) { bitflag flags[OF_SIZE], known_flags[OF_SIZE]; object_flags(o_ptr, flags); object_flags_known(o_ptr, known_flags); /* Some flags are irrelevant or never learned or too hard to learn */ flags_clear(flags, OF_SIZE, OF_OBJ_ONLY_MASK, FLAG_END); flags_clear(known_flags, OF_SIZE, OF_OBJ_ONLY_MASK, FLAG_END); if (!of_is_equal(flags, known_flags)) return FALSE; /* If we know attack bonuses, and defence bonuses, and effect, then * we effectively know everything, so mark as such */ if ((object_attack_plusses_are_visible(o_ptr) || (object_was_sensed(o_ptr) && o_ptr->to_h == 0 && o_ptr->to_d == 0)) && (object_defence_plusses_are_visible(o_ptr) || (object_was_sensed(o_ptr) && o_ptr->to_a == 0)) && (object_effect_is_known(o_ptr) || !object_effect(o_ptr))) { object_notice_everything(o_ptr); return TRUE; } /* We still know all the flags, so we still know if it's an ego */ else if (ego_item_p(o_ptr)) { /* require worn status so you don't learn launcher of accuracy or gloves of slaying before wield */ if (object_was_worn(o_ptr)) object_notice_ego(o_ptr); } return FALSE; }
/** * Notice things about an object that would be noticed in time. */ static void object_notice_after_time(void) { int i; int flag; object_type *o_ptr; char o_name[80]; bitflag f[OF_SIZE], timed_mask[OF_SIZE]; flags_init(timed_mask, OF_SIZE, OF_NOTICE_TIMED_MASK, FLAG_END); /* Check every item the player is wearing */ for (i = INVEN_WIELD; i < ALL_INVEN_TOTAL; i++) { o_ptr = &p_ptr->inventory[i]; if (!o_ptr->k_idx || object_is_known(o_ptr)) continue; /* Check for timed notice flags */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE); object_flags(o_ptr, f); of_inter(f, timed_mask); for (flag = of_next(f, FLAG_START); flag != FLAG_END; flag = of_next(f, flag + 1)) { if (!of_has(o_ptr->known_flags, flag)) { /* Message */ if (!streq(msgs[flag], "")) msg_format(msgs[flag], o_name); /* Notice the flag */ object_notice_flag(o_ptr, flag); if (object_is_jewelry(o_ptr) && (!object_effect(o_ptr) || object_effect_is_known(o_ptr))) { /* XXX this is a small hack, but jewelry with anything noticeable really is obvious */ /* XXX except, wait until learn activation if that is only clue */ object_flavor_aware(o_ptr); object_check_for_ident(o_ptr); } } else { /* Notice the flag is absent */ object_notice_flag(o_ptr, flag); } } /* XXX Is this necessary? */ object_check_for_ident(o_ptr); } }
/** * Gives the known effects of using the given item. * * Fills in: * - the effect * - whether the effect can be aimed * - the minimum and maximum time in game turns for the item to recharge * (or zero if it does not recharge) * - the percentage chance of the effect failing when used * * Return false if the object has no effect. */ static bool obj_known_effect(const struct object *obj, struct effect **effect, bool *aimed, int *min_recharge, int *max_recharge, int *failure_chance) { random_value timeout = {0, 0, 0, 0}; *effect = 0; *min_recharge = 0; *max_recharge = 0; *failure_chance = 0; *aimed = false; if (object_effect_is_known(obj)) { *effect = object_effect(obj); timeout = obj->time; if (effect_aim(*effect)) *aimed = true;; } else if (object_effect(obj)) { /* Don't know much - be vague */ *effect = NULL; if (!obj->artifact && effect_aim(object_effect(obj))) *aimed = true; return true; } else { /* No effect - no info */ return false; } if (randcalc(timeout, 0, MAXIMISE) > 0) { *min_recharge = randcalc(timeout, 0, MINIMISE); *max_recharge = randcalc(timeout, 0, MAXIMISE); } if (tval_is_edible(obj) || tval_is_potion(obj) || tval_is_scroll(obj)) { *failure_chance = 0; } else { *failure_chance = get_use_device_chance(obj); } return true; }
/** * Add power for effect */ static int effects_power(const object_type *obj, int p, bool known) { int q = 0; if (known || object_effect_is_known(obj)) { if (obj->artifact && obj->artifact->activation && obj->artifact->activation->power) { q = obj->artifact->activation->power; } else if (obj->kind->power) { q = obj->kind->power; } if (q) { p += q; log_obj(format("Add %d power for item activation, total is %d\n", q, p)); } } return p; }
/** * Gives the known effects of using the given item. * * Fills in: * - the effect id, or OBJ_KNOWN_PRESENT if there is an effect but details * are unknown * - whether the effect can be aimed * - the minimum and maximum time in game turns for the item to recharge * (or zero if it does not recharge) * - the percentage chance of the effect failing when used * * Return FALSE if the object has no effect. */ static bool obj_known_effect(const struct object *obj, int *effect, bool *aimed, int *min_recharge, int *max_recharge, int *failure_chance) { random_value timeout = {0, 0, 0, 0}; *effect = 0; *min_recharge = 0; *max_recharge = 0; *failure_chance = 0; *aimed = FALSE; if (object_effect_is_known(obj)) { *effect = object_effect(obj); timeout = obj->time; } else if (object_effect(obj)) { /* Don't know much - be vague */ *effect = OBJ_KNOWN_PRESENT; if (!obj->artifact && effect_aim(obj->effect)) *aimed = TRUE; return TRUE; } else { /* No effect - no info */ return FALSE; } if (randcalc(timeout, 0, MAXIMISE) > 0) { *min_recharge = randcalc(timeout, 0, MINIMISE); *max_recharge = randcalc(timeout, 0, MAXIMISE); } if (tval_is_food(obj) || tval_is_potion(obj) || tval_is_scroll(obj)) { *failure_chance = 0; } else { *failure_chance = get_use_device_chance(obj); } return TRUE; }
/* * Describe an object's effect, if any. */ static bool describe_effect(textblock *tb, const object_type *o_ptr, bool full, bool only_artifacts, bool subjective) { const char *desc; random_value timeout = {0, 0, 0, 0}; int effect = 0, fail; if (o_ptr->artifact) { if (object_effect_is_known(o_ptr) || full) { effect = o_ptr->artifact->effect; timeout = o_ptr->artifact->time; } else if (object_effect(o_ptr)) { textblock_append(tb, "It can be activated.\n"); return TRUE; } } else { /* Sometimes only print artifact activation info */ if (only_artifacts == TRUE) return FALSE; if (object_effect_is_known(o_ptr) || full) { effect = o_ptr->kind->effect; timeout = o_ptr->kind->time; } else if (object_effect(o_ptr) != 0) { if (effect_aim(o_ptr->kind->effect)) textblock_append(tb, "It can be aimed.\n"); else if (o_ptr->tval == TV_FOOD) textblock_append(tb, "It can be eaten.\n"); else if (o_ptr->tval == TV_POTION) textblock_append(tb, "It can be drunk.\n"); else if (o_ptr->tval == TV_SCROLL) textblock_append(tb, "It can be read.\n"); else textblock_append(tb, "It can be activated.\n"); return TRUE; } } /* Forget it without an effect */ if (!effect) return FALSE; /* Obtain the description */ desc = effect_desc(effect); if (!desc) return FALSE; if (effect_aim(effect)) textblock_append(tb, "When aimed, it "); else if (o_ptr->tval == TV_FOOD) textblock_append(tb, "When eaten, it "); else if (o_ptr->tval == TV_POTION) textblock_append(tb, "When drunk, it "); else if (o_ptr->tval == TV_SCROLL) textblock_append(tb, "When read, it "); else textblock_append(tb, "When activated, it "); /* Print a colourised description */ do { if (isdigit((unsigned char) *desc)) textblock_append_c(tb, TERM_L_GREEN, "%c", *desc); else textblock_append(tb, "%c", *desc); } while (*desc++); textblock_append(tb, ".\n"); if (randcalc(timeout, 0, MAXIMISE) > 0) { int min_time, max_time; /* Sometimes adjust for player speed */ int multiplier = extract_energy[p_ptr->state.speed]; if (!subjective) multiplier = 10; textblock_append(tb, "Takes "); /* Correct for player speed */ min_time = randcalc(timeout, 0, MINIMISE) * multiplier / 10; max_time = randcalc(timeout, 0, MAXIMISE) * multiplier / 10; textblock_append_c(tb, TERM_L_GREEN, "%d", min_time); if (min_time != max_time) { textblock_append(tb, " to "); textblock_append_c(tb, TERM_L_GREEN, "%d", max_time); } textblock_append(tb, " turns to recharge"); if (subjective && p_ptr->state.speed != 110) textblock_append(tb, " at your current speed"); textblock_append(tb, ".\n"); } if (!subjective || o_ptr->tval == TV_FOOD || o_ptr->tval == TV_POTION || o_ptr->tval == TV_SCROLL) { return TRUE; } else { fail = get_use_device_chance(o_ptr); textblock_append(tb, "Your chance of success is %d.%d%%\n", (1000 - fail) / 10, (1000 - fail) % 10); } return TRUE; }
/* * Display a list of objects. Each object may be prefixed with a label. * Used by show_inven(), show_equip(), and show_floor(). Mode flags are * documented in object.h */ static void show_obj_list(int num_obj, int num_head, char labels[50][80], object_type *objects[50], olist_detail_t mode) { int i, row = 0, col = 0; int attr; size_t max_len = 0; int ex_width = 0, ex_offset, ex_offset_ctr; object_type *o_ptr; char o_name[50][80]; char tmp_val[80]; bool in_term = (mode & OLIST_WINDOW) ? TRUE : FALSE; bool terse = FALSE; if (in_term) max_len = 40; if (in_term && Term->wid < 40) mode &= ~(OLIST_WEIGHT); if (Term->wid < 50) terse = TRUE; /* Calculate name offset and max name length */ for (i = 0; i < num_obj; i++) { o_ptr = objects[i]; /* Null objects are used to skip lines, or display only a label */ if (!o_ptr || !o_ptr->kind) { if (i < num_head) strnfmt(o_name[i], sizeof(o_name[i]), ""); else strnfmt(o_name[i], sizeof(o_name[i]), "(nothing)"); } else object_desc(o_name[i], sizeof(o_name[i]), o_ptr, ODESC_PREFIX | ODESC_FULL | (terse ? ODESC_TERSE : 0)); /* Max length of label + object name */ max_len = MAX(max_len, strlen(labels[i]) + strlen(o_name[i])); } /* Take the quiver message into consideration */ if (mode & OLIST_QUIVER && p_ptr->quiver_slots > 0) max_len = MAX(max_len, 24); /* Width of extra fields */ if (mode & OLIST_WEIGHT) ex_width += 9; if (mode & OLIST_PRICE) ex_width += 9; if (mode & OLIST_FAIL) ex_width += 10; /* Determine beginning row and column */ if (in_term) { /* Term window */ row = 0; col = 0; } else { /* Main window */ row = 1; col = Term->wid - 1 - max_len - ex_width; if (col < 3) col = 0; } /* Column offset of the first extra field */ ex_offset = MIN(max_len, (size_t)(Term->wid - 1 - ex_width - col)); /* Output the list */ for (i = 0; i < num_obj; i++) { o_ptr = objects[i]; /* Clear the line */ prt("", row + i, MAX(col - 2, 0)); /* If we have no label then we won't display anything */ if (!strlen(labels[i])) continue; /* Print the label */ put_str(labels[i], row + i, col); /* Limit object name */ if (strlen(labels[i]) + strlen(o_name[i]) > (size_t)ex_offset) { int truncate = ex_offset - strlen(labels[i]); if (truncate < 0) truncate = 0; if ((size_t)truncate > sizeof(o_name[i]) - 1) truncate = sizeof(o_name[i]) - 1; o_name[i][truncate] = '\0'; } /* Item kind determines the color of the output */ if (o_ptr && o_ptr->kind) attr = tval_to_attr[o_ptr->tval % N_ELEMENTS(tval_to_attr)]; else attr = TERM_SLATE; /* Object name */ c_put_str(attr, o_name[i], row + i, col + strlen(labels[i])); /* If we don't have an object, we can skip the rest of the output */ if (!(o_ptr && o_ptr->kind)) continue; /* Extra fields */ ex_offset_ctr = ex_offset; if (mode & OLIST_PRICE) { int price = price_item(o_ptr, TRUE, o_ptr->number); strnfmt(tmp_val, sizeof(tmp_val), "%6d au", price); put_str(tmp_val, row + i, col + ex_offset_ctr); ex_offset_ctr += 9; } if (mode & OLIST_FAIL && obj_can_fail(o_ptr)) { int fail = (9 + get_use_device_chance(o_ptr)) / 10; if (object_effect_is_known(o_ptr)) strnfmt(tmp_val, sizeof(tmp_val), "%4d%% fail", fail); else my_strcpy(tmp_val, " ? fail", sizeof(tmp_val)); put_str(tmp_val, row + i, col + ex_offset_ctr); ex_offset_ctr += 10; } if (mode & OLIST_WEIGHT) { int weight = o_ptr->weight * o_ptr->number; strnfmt(tmp_val, sizeof(tmp_val), "%4d.%1d lb", weight / 10, weight % 10); put_str(tmp_val, row + i, col + ex_offset_ctr); ex_offset_ctr += 9; } } /* For the inventory: print the quiver count */ if (mode & OLIST_QUIVER) { int count, j; /* Quiver may take multiple lines */ for(j = 0; j < p_ptr->quiver_slots; j++, i++) { const char *fmt = "in Quiver: %d missile%s"; char letter = index_to_label(in_term ? i - 1 : i); /* Number of missiles in this "slot" */ if (j == p_ptr->quiver_slots - 1 && p_ptr->quiver_remainder > 0) count = p_ptr->quiver_remainder; else count = MAX_STACK_SIZE-1; /* Clear the line */ prt("", row + i, MAX(col - 2, 0)); /* Print the (disabled) label */ strnfmt(tmp_val, sizeof(tmp_val), "%c) ", letter); c_put_str(TERM_SLATE, tmp_val, row + i, col); /* Print the count */ strnfmt(tmp_val, sizeof(tmp_val), fmt, count, count == 1 ? "" : "s"); c_put_str(TERM_L_UMBER, tmp_val, row + i, col + 3); } } /* Clear term windows */ if (in_term) { for (; i < Term->hgt; i++) { prt("", row + i, MAX(col - 2, 0)); } } /* Print a drop shadow for the main window if necessary */ else if (i > 0 && row + i < 24) { prt("", row + i, MAX(col - 2, 0)); } }
/* * Display a list of objects. Each object may be prefixed with a label. * Used by show_inven(), show_equip(), and show_floor(). Mode flags are * documented in object.h */ static void show_obj_list(int num_obj, char labels[50][80], object_type *objects[50], olist_detail_t mode) { int i, row = 0, col = 0; size_t max_len = 0; int ex_width = 0, ex_offset, ex_offset_ctr; object_type *o_ptr; char o_name[50][80]; char tmp_val[80]; bool in_term; in_term = (mode & OLIST_WINDOW) ? TRUE : FALSE; if (in_term) max_len = 40; /* Calculate name offset and max name length */ for (i = 0; i < num_obj; i++) { o_ptr = objects[i]; /* Null objects are used to skip lines, or display only a label */ if (o_ptr == NULL) continue; /* Max length of label + object name */ object_desc(o_name[i], sizeof(o_name[i]), o_ptr, ODESC_PREFIX | ODESC_FULL); max_len = MAX(max_len, strlen(labels[i]) + strlen(o_name[i])); } /* Width of extra fields */ if (mode & OLIST_WEIGHT) ex_width += 9; if (mode & OLIST_PRICE) ex_width += 9; if (mode & OLIST_FAIL) ex_width += 10; /* Determine beginning row and column */ if (in_term) { /* Term window */ row = 0; col = 0; } else { /* Main window */ row = 1; col = Term->wid - 1 - max_len - ex_width; if (col < 3) col = 0; } /* Column offset of the first extra field */ ex_offset = MIN(max_len, (size_t)(Term->wid - 1 - ex_width - col)); /* Output the list */ for (i = 0; i < num_obj; i++) { o_ptr = objects[i]; /* Clear the line */ prt("", row + i, MAX(col - 2, 0)); /* Print the label */ put_str(labels[i], row + i, col); /* Print the object */ if (o_ptr != NULL) { /* Limit object name */ if (strlen(labels[i]) + strlen(o_name[i]) > (size_t)ex_offset) { int truncate = ex_offset - strlen(labels[i]); if (truncate < 0) truncate = 0; if ((size_t)truncate > sizeof(o_name[i]) - 1) truncate = sizeof(o_name[i]) - 1; o_name[i][truncate] = '\0'; } /* Object name */ c_put_str(tval_to_attr[o_ptr->tval % N_ELEMENTS(tval_to_attr)], o_name[i], row + i, col + strlen(labels[i])); /* Extra fields */ ex_offset_ctr = ex_offset; if (mode & OLIST_PRICE) { int price = price_item(o_ptr, TRUE, o_ptr->number); strnfmt(tmp_val, sizeof(tmp_val), "%6d au", price); put_str(tmp_val, row + i, col + ex_offset_ctr); ex_offset_ctr += 9; } if (mode & OLIST_FAIL) { int fail = (9 + get_use_device_chance(o_ptr)) / 10; if (object_effect_is_known(o_ptr)) strnfmt(tmp_val, sizeof(tmp_val), "%4d%% fail", fail); else my_strcpy(tmp_val, " ? fail", sizeof(tmp_val)); put_str(tmp_val, row + i, col + ex_offset_ctr); ex_offset_ctr += 10; } if (mode & OLIST_WEIGHT) { int weight = o_ptr->weight * o_ptr->number; strnfmt(tmp_val, sizeof(tmp_val), "%4d.%1d lb", weight / 10, weight % 10); put_str(tmp_val, row + i, col + ex_offset_ctr); ex_offset_ctr += 9; } } } /* For the inventory: print the quiver count */ if (mode & OLIST_QUIVER) { int count, j; /* Quiver may take multiple lines */ for(j = 0; j < p_ptr->quiver_slots; j++, i++) { /* Number of missiles in this "slot" */ if (j == p_ptr->quiver_slots - 1 && p_ptr->quiver_remainder > 0) count = p_ptr->quiver_remainder; else count = 99; /* Clear the line */ prt("", row + i, MAX(col - 2, 0)); /* Print the (disabled) label */ strnfmt(tmp_val, sizeof(tmp_val), "%c) ", index_to_label(i)); c_put_str(TERM_SLATE, tmp_val, row + i, col); /* Print the count */ strnfmt(tmp_val, sizeof(tmp_val), "in Quiver: %d missile%s", count, count == 1 ? "" : "s"); c_put_str(TERM_L_UMBER, tmp_val, row + i, col + 3); } } /* Clear term windows */ if (in_term) { for (; i < Term->hgt; i++) { prt("", row + i, MAX(col - 2, 0)); } } /* Print a drop shadow for the main window if necessary */ else if (i > 0 && row + i < 24) { prt("", row + i, MAX(col - 2, 0)); } }
/** * Display an object. Each object may be prefixed with a label. * Used by show_inven(), show_equip(), show_quiver() and show_floor(). * Mode flags are documented in object.h */ static void show_obj(int obj_num, int row, int col, bool cursor, olist_detail_t mode) { int attr; int label_attr = cursor ? COLOUR_L_BLUE : COLOUR_WHITE; int ex_offset_ctr; char buf[80]; struct object *obj = items[obj_num].object; bool show_label = mode & (OLIST_WINDOW | OLIST_DEATH) ? true : false; int label_size = show_label ? strlen(items[obj_num].label) : 0; int equip_label_size = strlen(items[obj_num].equip_label); /* Clear the line */ prt("", row + obj_num, MAX(col - 1, 0)); /* If we have no label then we won't display anything */ if (!strlen(items[obj_num].label)) return; /* Print the label */ if (show_label) c_put_str(label_attr, items[obj_num].label, row + obj_num, col); /* Print the equipment label */ c_put_str(label_attr, items[obj_num].equip_label, row + obj_num, col + label_size); /* Limit object name */ if (label_size + equip_label_size + strlen(items[obj_num].o_name) > (size_t)ex_offset) { int truncate = ex_offset - label_size - equip_label_size; if (truncate < 0) truncate = 0; if ((size_t)truncate > sizeof(items[obj_num].o_name) - 1) truncate = sizeof(items[obj_num].o_name) - 1; items[obj_num].o_name[truncate] = '\0'; } /* Item kind determines the color of the output */ if (obj) { attr = obj->kind->base->attr; /* Unreadable books are a special case */ if (tval_is_book_k(obj->kind) && (player_object_to_book(player, obj) == NULL)) { attr = COLOUR_SLATE; } } else { attr = COLOUR_SLATE; } /* Object name */ c_put_str(attr, items[obj_num].o_name, row + obj_num, col + label_size + equip_label_size); /* If we don't have an object, we can skip the rest of the output */ if (!obj) return; /* Extra fields */ ex_offset_ctr = ex_offset; /* Price */ if (mode & OLIST_PRICE) { struct store *store = store_at(cave, player->grid); if (store) { int price = price_item(store, obj, true, obj->number); strnfmt(buf, sizeof(buf), "%6d au", price); put_str(buf, row + obj_num, col + ex_offset_ctr); ex_offset_ctr += 9; } } /* Failure chance for magic devices and activations */ if (mode & OLIST_FAIL && obj_can_fail(obj)) { int fail = (9 + get_use_device_chance(obj)) / 10; if (object_effect_is_known(obj)) strnfmt(buf, sizeof(buf), "%4d%% fail", fail); else my_strcpy(buf, " ? fail", sizeof(buf)); put_str(buf, row + obj_num, col + ex_offset_ctr); ex_offset_ctr += 10; } /* Failure chances for recharging an item; see effect_handler_RECHARGE */ if (mode & OLIST_RECHARGE) { int fail = 1000 / recharge_failure_chance(obj, player->upkeep->recharge_pow); if (object_effect_is_known(obj)) strnfmt(buf, sizeof(buf), "%2d.%1d%% fail", fail / 10, fail % 10); else my_strcpy(buf, " ? fail", sizeof(buf)); put_str(buf, row + obj_num, col + ex_offset_ctr); ex_offset_ctr += 10; } /* Weight */ if (mode & OLIST_WEIGHT) { int weight = obj->weight * obj->number; strnfmt(buf, sizeof(buf), "%4d.%1d lb", weight / 10, weight % 10); put_str(buf, row + obj_num, col + ex_offset_ctr); ex_offset_ctr += 9; } }
/* * Evaluate the object's overall power level. */ s32b object_power(const object_type* o_ptr, int verbose, ang_file *log_file, bool known) { s32b p = 0, q = 0, slay_pwr = 0; unsigned int i, j; int extra_stat_bonus = 0, mult = 1, num_slays = 0, k = 1; bitflag flags[OF_SIZE], mask[OF_SIZE]; /* Zero the flag counts */ for (i = 0; i < N_ELEMENTS(sets); i++) sets[i].count = 0; /* Extract the flags */ if (known) { file_putf(log_file, "Object is deemed known\n"); object_flags(o_ptr, flags); } else { file_putf(log_file, "Object may not be fully known\n"); object_flags_known(o_ptr, flags); } /* Log the flags in human-readable form */ if (verbose) log_flags(flags, log_file); /* Get the slay power and number of slay/brand types */ create_mask(mask, FALSE, OFT_SLAY, OFT_KILL, OFT_BRAND, OFT_MAX); num_slays = list_slays(flags, mask, NULL, NULL, NULL, TRUE); if (num_slays) slay_pwr = slay_power(o_ptr, verbose, log_file, known); /* Start with any damage boost from the item itself */ p += (o_ptr->to_d * DAMAGE_POWER / 2); file_putf(log_file, "Adding power from to_dam, total is %d\n", p); /* Add damage from dice for any wieldable weapon or ammo */ if (wield_slot(o_ptr) == INVEN_WIELD || obj_is_ammo(o_ptr)) { p += (o_ptr->dd * (o_ptr->ds + 1) * DAMAGE_POWER / 4); file_putf(log_file, "Adding power for dam dice, total is %d\n", p); /* Add 2nd lot of damage power for nonweapons */ } else if (wield_slot(o_ptr) != INVEN_BOW) { p += (o_ptr->to_d * DAMAGE_POWER); file_putf(log_file, "Adding power from nonweap to_dam, total is %d\n", p); /* Add power boost for nonweapons with combat flags */ if (num_slays || of_has(flags, OF_BLOWS) || of_has(flags, OF_SHOTS) || of_has(flags, OF_MIGHT)) { p += (WEAP_DAMAGE * DAMAGE_POWER); file_putf(log_file, "Adding power for nonweap combat flags, total is %d\n", p); } } /* Add ammo damage for launchers, get multiplier and rescale */ if (wield_slot(o_ptr) == INVEN_BOW) { p += (archery[o_ptr->sval / 10].ammo_dam * DAMAGE_POWER / 2); file_putf(log_file, "Adding power from ammo, total is %d\n", p); mult = bow_multiplier(o_ptr->sval); file_putf(log_file, "Base mult for this weapon is %d\n", mult); } /* Add launcher bonus for ego ammo, multiply for launcher and rescale */ if (obj_is_ammo(o_ptr)) { if (o_ptr->ego) p += (archery[o_ptr->tval - TV_SHOT].launch_dam * DAMAGE_POWER / 2); p = p * archery[o_ptr->tval - TV_SHOT].launch_mult / (2 * MAX_BLOWS); file_putf(log_file, "After multiplying ammo and rescaling, power is %d\n", p); } /* Add power for extra blows */ if (of_has(flags, OF_BLOWS)) { j = which_pval(o_ptr, OF_BLOWS); if (known || object_this_pval_is_visible(o_ptr, j)) { if (o_ptr->pval[j] >= INHIBIT_BLOWS) { p += INHIBIT_POWER; file_putf(log_file, "INHIBITING - too many extra blows\n"); } else { p = p * (MAX_BLOWS + o_ptr->pval[j]) / MAX_BLOWS; /* Add boost for assumed off-weapon damage */ p += (NONWEAP_DAMAGE * o_ptr->pval[j] * DAMAGE_POWER / 2); file_putf(log_file, "Adding power for extra blows, total is %d\n", p); } } } /* Add power for extra shots - note that we cannot handle negative shots */ if (of_has(flags, OF_SHOTS)) { j = which_pval(o_ptr, OF_SHOTS); if (known || object_this_pval_is_visible(o_ptr, j)) { if (o_ptr->pval[j] >= INHIBIT_SHOTS) { p += INHIBIT_POWER; file_putf(log_file, "INHIBITING - too many extra shots\n"); } else if (o_ptr->pval[j] > 0) { p = (p * (1 + o_ptr->pval[j])); file_putf(log_file, "Extra shots: multiplying power by 1 + %d, total is %d\n", o_ptr->pval[j], p); } } } /* Add power for extra might */ if (of_has(flags, OF_MIGHT)) { j = which_pval(o_ptr, OF_MIGHT); if (known || object_this_pval_is_visible(o_ptr, j)) { if (o_ptr->pval[j] >= INHIBIT_MIGHT) { p += INHIBIT_POWER; mult = 1; /* don't overflow */ file_putf(log_file, "INHIBITING - too much extra might\n"); } else mult += o_ptr->pval[j]; file_putf(log_file, "Mult after extra might is %d\n", mult); } } p *= mult; file_putf(log_file, "After multiplying power for might, total is %d\n", p); /* Apply the correct slay multiplier */ if (slay_pwr) { p = (p * (slay_pwr / 10)) / (tot_mon_power / 10); file_putf(log_file, "Adjusted for slay power, total is %d\n", p); } /* Melee weapons assume MAX_BLOWS per turn, so we must divide by MAX_BLOWS * to get equal ratings for launchers. */ if (wield_slot(o_ptr) == INVEN_BOW) { p /= MAX_BLOWS; file_putf(log_file, "Rescaling bow power, total is %d\n", p); } /* Add power for +to_hit */ p += (o_ptr->to_h * TO_HIT_POWER / 2); file_putf(log_file, "Adding power for to hit, total is %d\n", p); /* Add power for base AC and adjust for weight */ if (o_ptr->ac) { q += BASE_ARMOUR_POWER; q += (o_ptr->ac * BASE_AC_POWER / 2); file_putf(log_file, "Adding %d power for base AC value\n", q); /* Add power for AC per unit weight */ if (o_ptr->weight > 0) { i = 800 * (o_ptr->ac + o_ptr->to_a) / o_ptr->weight; /* Avoid overpricing Elven Cloaks */ if (i > 450) i = 450; q *= i; q /= 100; /* Weightless (ethereal) armour items get fixed boost */ } else q *= 5; p += q; file_putf(log_file, "Adding power for AC per unit weight, now %d\n", p); } /* Add power for +to_ac */ p += (o_ptr->to_a * TO_AC_POWER / 2); file_putf(log_file, "Adding power for to_ac of %d, total is %d\n", o_ptr->to_a, p); if (o_ptr->to_a > HIGH_TO_AC) { p += ((o_ptr->to_a - (HIGH_TO_AC - 1)) * TO_AC_POWER); file_putf(log_file, "Adding power for high to_ac value, total is %d\n", p); } if (o_ptr->to_a > VERYHIGH_TO_AC) { p += ((o_ptr->to_a - (VERYHIGH_TO_AC -1)) * TO_AC_POWER * 2); file_putf(log_file, "Adding power for very high to_ac value, total is %d\n", p); } if (o_ptr->to_a >= INHIBIT_AC) { p += INHIBIT_POWER; file_putf(log_file, "INHIBITING: AC bonus too high\n"); } /* Add power for light sources by radius XXX Hack - rewrite calc_torch! */ if (wield_slot(o_ptr) == INVEN_LIGHT) { p += BASE_LIGHT_POWER; /* Artifact lights have larger radius so add more */ if (o_ptr->artifact) p += BASE_LIGHT_POWER; file_putf(log_file, "Adding power for light radius, total is %d\n", p); } /* Add base power for jewelry */ if (object_is_jewelry(o_ptr)) { p += BASE_JEWELRY_POWER; file_putf(log_file, "Adding power for jewelry, total is %d\n", p); } /* Add power for non-derived flags (derived flags have flag_power 0) */ for (i = 0; i < OF_MAX; i++) { if (of_has(flags, i)) { if (flag_uses_pval(i)) { j = which_pval(o_ptr, i); if (known || object_this_pval_is_visible(o_ptr, j)) { k = o_ptr->pval[j]; extra_stat_bonus += (k * pval_mult(i)); } } else k = 1; if (flag_power(i)) { p += (k * flag_power(i) * slot_mult(i, wield_slot(o_ptr))); file_putf(log_file, "Adding power for %s, total is %d\n", flag_name(i), p); } /* Track combinations of flag types - note we ignore SUST_CHR */ for (j = 0; j < N_ELEMENTS(sets); j++) if ((sets[j].type == obj_flag_type(i)) && (i != OF_SUST_CHR)) sets[j].count++; } } /* Add extra power term if there are a lot of ability bonuses */ if (extra_stat_bonus > 249) { file_putf(log_file, "Inhibiting! (Total ability bonus of %d is too high)\n", extra_stat_bonus); p += INHIBIT_POWER; } else { p += ability_power[extra_stat_bonus / 10]; file_putf(log_file, "Adding power for pval total of %d, total is %d\n", extra_stat_bonus, p); } /* Add extra power for multiple flags of the same type */ for (i = 0; i < N_ELEMENTS(sets); i++) { if (sets[i].count > 1) { p += (sets[i].factor * sets[i].count * sets[i].count); file_putf(log_file, "Adding power for multiple flags of type %d, total is %d\n", i, p); } /* Add bonus if item has a full set of these flags */ if (sets[i].count == sets[i].size) { p += sets[i].bonus; file_putf(log_file, "Adding power for full set of type %d, total is %d\n", i, p); } } /* add power for effect */ if (known || object_effect_is_known(o_ptr)) { if (o_ptr->artifact && o_ptr->artifact->effect) { p += effect_power(o_ptr->artifact->effect); file_putf(log_file, "Adding power for artifact activation, total is %d\n", p); } else { p += effect_power(o_ptr->kind->effect); file_putf(log_file, "Adding power for item activation, total is %d\n", p); } } file_putf(log_file, "FINAL POWER IS %d\n", p); return p; }
/* * Evaluate the object's overall power level. */ s32b object_power(const object_type* o_ptr, int verbose, ang_file *log_file, bool known) { s32b p = 0; object_kind *k_ptr; int immunities = 0; int misc = 0; int lowres = 0; int highres = 0; int sustains = 0; int extra_stat_bonus = 0; int i; bitflag flags[OF_SIZE]; const slay_t *s_ptr; /* Extract the flags */ if (known) { LOG_PRINT("Object is known\n"); object_flags(o_ptr, flags); } else { LOG_PRINT("Object is not fully known\n"); object_flags_known(o_ptr, flags); } if (verbose) { LOG_PRINT("Object flags ="); for (i = 0; i < (int)OF_SIZE; i++) LOG_PRINT1(" %02x", flags[i]); LOG_PRINT("\n"); } k_ptr = &k_info[o_ptr->k_idx]; /* Evaluate certain abilities based on type of object. */ switch (o_ptr->tval) { case TV_BOW: { int mult; /* * Damage multiplier for bows should be weighted less than that * for melee weapons, since players typically get fewer shots * than hits (note, however, that the multipliers are applied * afterwards in the bow calculation, not before as for melee * weapons, which tends to bring these numbers back into line). * ToDo: rework evaluation of negative pvals */ p += (o_ptr->to_d * DAMAGE_POWER / 2); LOG_PRINT1("Adding power from to_dam, total is %d\n", p); /* * Add the average damage of fully enchanted (good) ammo for this * weapon. Could make this dynamic based on k_info if desired. * ToDo: precisely that. */ if (o_ptr->sval == SV_SLING) { p += (AVG_SLING_AMMO_DAMAGE * DAMAGE_POWER / 2); } else if (o_ptr->sval == SV_SHORT_BOW || o_ptr->sval == SV_LONG_BOW) { p += (AVG_BOW_AMMO_DAMAGE * DAMAGE_POWER / 2); } else if (o_ptr->sval == SV_LIGHT_XBOW || o_ptr->sval == SV_HEAVY_XBOW) { p += (AVG_XBOW_AMMO_DAMAGE * DAMAGE_POWER / 2); } LOG_PRINT1("Adding power from ammo, total is %d\n", p); mult = bow_multiplier(o_ptr->sval); LOG_PRINT1("Base multiplier for this weapon is %d\n", mult); if (of_has(flags, OF_MIGHT) && (known || object_pval_is_visible(o_ptr))) { if (o_ptr->pval >= INHIBIT_MIGHT || o_ptr->pval < 0) { p += INHIBIT_POWER; /* inhibit */ mult = 1; /* don't overflow */ LOG_PRINT("INHIBITING - too much extra might\n"); } else { mult += o_ptr->pval; } LOG_PRINT1("Extra might multiple is %d\n", mult); } p *= mult; LOG_PRINT2("Multiplying power by %d, total is %d\n", mult, p); if (of_has(flags, OF_SHOTS) && (known || object_pval_is_visible(o_ptr))) { LOG_PRINT1("Extra shots: %d\n", o_ptr->pval); if (o_ptr->pval >= INHIBIT_SHOTS || o_ptr->pval < 0) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING - too many extra shots\n"); } else if (o_ptr->pval > 0) { p = (p * (1 + o_ptr->pval)); LOG_PRINT2("Multiplying power by 1 + %d, total is %d\n", o_ptr->pval, p); } } /* Apply the correct slay multiplier */ p = (p * slay_power(o_ptr, verbose, log_file, flags)) / tot_mon_power; LOG_PRINT1("Adjusted for slay power, total is %d\n", p); if (o_ptr->weight < k_ptr->weight) { p++; LOG_PRINT("Incrementing power by one for low weight\n"); } /* * Correction to match ratings to melee damage ratings. * We multiply all missile weapons by 1.5 in order to compare damage. * (CR 11/20/01 - changed this to 1.25). * (CC 25/07/10 - changed this back to 1.5). * Melee weapons assume MAX_BLOWS per turn, so we must * also divide by MAX_BLOWS to get equal ratings. */ p = sign(p) * (ABS(p) * BOW_RESCALER / (10 * MAX_BLOWS)); LOG_PRINT1("Rescaling bow power, total is %d\n", p); p += sign(o_ptr->to_h) * (ABS(o_ptr->to_h) * TO_HIT_POWER / 2); LOG_PRINT1("Adding power from to_hit, total is %d\n", p); break; } case TV_SHOT: case TV_ARROW: case TV_BOLT: case TV_DIGGING: case TV_HAFTED: case TV_POLEARM: case TV_SWORD: { p += (o_ptr->dd * (o_ptr->ds + 1) * DAMAGE_POWER / 4); LOG_PRINT1("Adding power for dam dice, total is %d\n", p); /* Apply the correct slay multiplier */ p = (p * slay_power(o_ptr, verbose, log_file, flags)) / tot_mon_power; LOG_PRINT1("Adjusted for slay power, total is %d\n", p); p += (o_ptr->to_d * DAMAGE_POWER / 2); LOG_PRINT1("Adding power for to_dam, total is %d\n", p); if (of_has(flags, OF_BLOWS) && (known || object_pval_is_visible(o_ptr))) { LOG_PRINT1("Extra blows: %d\n", o_ptr->pval); if (o_ptr->pval >= INHIBIT_BLOWS || o_ptr->pval < 0) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING, too many extra blows or a negative number\n"); } else if (o_ptr->pval > 0) { p = sign(p) * ((ABS(p) * (MAX_BLOWS + o_ptr->pval)) / MAX_BLOWS); /* Add an extra amount per extra blow to account for damage/branding rings */ p += ((MELEE_DAMAGE_BOOST + RING_BRAND_DMG) * o_ptr->pval * DAMAGE_POWER / (2 * MAX_BLOWS)); LOG_PRINT1("Adding power for blows, total is %d\n", p); } } /* * add extra power for multiple slays/brands, as these * add diminishing amounts to average damage */ i = 0; for (s_ptr = slay_table; s_ptr->slay_flag; s_ptr++) { if (!of_has(flags, s_ptr->slay_flag)) continue; i++; if (i > 1) p += (i * 3); } LOG_PRINT1("Adding power for multiple slays/brands, total is %d\n", p); /* add launcher bonus for ego ammo, and multiply */ if (o_ptr->tval == TV_SHOT) { if (o_ptr->name2) p += (AVG_LAUNCHER_DMG * DAMAGE_POWER / 2); p = p * AVG_SLING_MULT * BOW_RESCALER / (20 * MAX_BLOWS); } if (o_ptr->tval == TV_ARROW) { if (o_ptr->name2) p += (AVG_LAUNCHER_DMG * DAMAGE_POWER / 2); p = p * AVG_BOW_MULT * BOW_RESCALER / (20 * MAX_BLOWS); } if (o_ptr->tval == TV_BOLT) { if (o_ptr->name2) p += (AVG_LAUNCHER_DMG * DAMAGE_POWER / 2); p = p * AVG_XBOW_MULT * BOW_RESCALER / (20 * MAX_BLOWS); } LOG_PRINT1("After multiplying ammo and rescaling, power is %d\n", p); p += sign(o_ptr->to_h) * (ABS(o_ptr->to_h) * TO_HIT_POWER / 2); LOG_PRINT1("Adding power for to hit, total is %d\n", p); /* Remember, weight is in 0.1 lb. units. */ if (o_ptr->weight < k_ptr->weight) { p += (k_ptr->weight - o_ptr->weight) / 20; LOG_PRINT1("Adding power for low weight, total is %d\n", p); } break; } 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: { p += BASE_ARMOUR_POWER; LOG_PRINT1("Armour item, base power is %d\n", p); p += sign(o_ptr->ac) * ((ABS(o_ptr->ac) * BASE_AC_POWER) / 2); LOG_PRINT1("Adding power for base AC value, total is %d\n", p); /* Add power for AC per unit weight */ if (o_ptr->weight > 0) { i = 1000 * (o_ptr->ac + o_ptr->to_a) / o_ptr->weight; /* Stop overpricing Elven Cloaks */ if (i > 400) i = 400; /* Adjust power */ p *= i; p /= 100; } /* Weightless (ethereal) items get fixed boost */ else p *= 5; /* Add power for +hit and +dam */ p += sign(o_ptr->to_h) * (ABS(o_ptr->to_h) * TO_HIT_POWER); LOG_PRINT1("Adding power for to_hit, total is %d\n", p); p += o_ptr->to_d * DAMAGE_POWER; LOG_PRINT1("Adding power for to_dam, total is %d\n", p); /* Apply the correct brand/slay multiplier */ p += (((2 * (o_ptr->to_d + RING_BRAND_DMG) * slay_power(o_ptr, verbose, log_file, flags)) / tot_mon_power) - (2 * (o_ptr->to_d + RING_BRAND_DMG))); LOG_PRINT1("Adjusted for brand/slay power, total is %d\n", p); /* Add power for extra blows */ if (of_has(flags, OF_BLOWS) && (known || object_pval_is_visible(o_ptr))) { LOG_PRINT1("Extra blows: %d\n", o_ptr->pval); if (o_ptr->pval >= INHIBIT_BLOWS || o_ptr->pval < 0) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING, too many extra blows or a negative number\n"); } else if (o_ptr->pval > 0) { p += ((MELEE_DAMAGE_BOOST + RING_BRAND_DMG + o_ptr->to_d) * o_ptr->pval * DAMAGE_POWER / MAX_BLOWS); LOG_PRINT1("Adding power for extra blows, total is %d\n", p); } } /* Add power for extra shots */ if (of_has(flags, OF_SHOTS) && (known || object_pval_is_visible(o_ptr))) { LOG_PRINT1("Extra shots: %d\n", o_ptr->pval); if (o_ptr->pval >= INHIBIT_SHOTS || o_ptr->pval < 0) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING - too many extra shots\n"); } else if (o_ptr->pval > 0) { p += ((AVG_XBOW_AMMO_DAMAGE + AVG_LAUNCHER_DMG) * AVG_XBOW_MULT * o_ptr->pval * DAMAGE_POWER * BOW_RESCALER / (20 * MAX_BLOWS)); LOG_PRINT1("Adding power for extra shots - total is %d\n", p); } } break; } case TV_LIGHT: { p += BASE_LIGHT_POWER; LOG_PRINT("Light source, adding base power\n"); p += sign(o_ptr->to_h) * (ABS(o_ptr->to_h) * TO_HIT_POWER); LOG_PRINT1("Adding power for to_hit, total is %d\n", p); p += o_ptr->to_d * DAMAGE_POWER; LOG_PRINT1("Adding power for to_dam, total is %d\n", p); /* Apply the correct brand/slay multiplier */ p += (((2 * (o_ptr->to_d + RING_BRAND_DMG) * slay_power(o_ptr, verbose, log_file, flags)) / tot_mon_power) - (2 * (o_ptr->to_d + RING_BRAND_DMG))); LOG_PRINT1("Adjusted for brand/slay power, total is %d\n", p); /* Add power for extra blows */ if (of_has(flags, OF_BLOWS) && (known || object_pval_is_visible(o_ptr))) { LOG_PRINT1("Extra blows: %d\n", o_ptr->pval); if (o_ptr->pval >= INHIBIT_BLOWS || o_ptr->pval < 0) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING, too many extra blows or a negative number\n"); } else if (o_ptr->pval > 0) { p += ((MELEE_DAMAGE_BOOST + RING_BRAND_DMG + o_ptr->to_d) * o_ptr->pval * DAMAGE_POWER / MAX_BLOWS); LOG_PRINT1("Adding power for extra blows, total is %d\n", p); } } /* Add power for extra shots */ if (of_has(flags, OF_SHOTS) && (known || object_pval_is_visible(o_ptr))) { LOG_PRINT1("Extra shots: %d\n", o_ptr->pval); if (o_ptr->pval >= INHIBIT_SHOTS || o_ptr->pval < 0) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING - too many extra shots\n"); } else if (o_ptr->pval > 0) { p += ((AVG_XBOW_AMMO_DAMAGE + AVG_LAUNCHER_DMG) * AVG_XBOW_MULT * o_ptr->pval * DAMAGE_POWER * BOW_RESCALER / (20 * MAX_BLOWS)); LOG_PRINT1("Adding power for extra shots - total is %d\n", p); } } /* * Big boost for extra light radius * n.b. Another few points are added below */ if (of_has(flags, OF_LIGHT)) p += 30; break; } case TV_RING: case TV_AMULET: { p += BASE_JEWELRY_POWER; LOG_PRINT("Jewellery - adding base power\n"); p += sign(o_ptr->to_h) * (ABS(o_ptr->to_h) * TO_HIT_POWER); LOG_PRINT1("Adding power for to_hit, total is %d\n", p); p += o_ptr->to_d * DAMAGE_POWER; LOG_PRINT1("Adding power for to_dam, total is %d\n", p); /* Apply the correct brand/slay multiplier */ p += (((2 * (o_ptr->to_d + RING_BRAND_DMG) * slay_power(o_ptr, verbose, log_file, flags)) / tot_mon_power) - (2 * (o_ptr->to_d + RING_BRAND_DMG))); LOG_PRINT1("Adjusted for brand/slay power, total is %d\n", p); /* Add power for extra blows */ if (of_has(flags, OF_BLOWS) && (known || object_pval_is_visible(o_ptr))) { LOG_PRINT1("Extra blows: %d\n", o_ptr->pval); if (o_ptr->pval >= INHIBIT_BLOWS || o_ptr->pval < 0) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING, too many extra blows or a negative number\n"); } else if (o_ptr->pval > 0) { p += ((MELEE_DAMAGE_BOOST + RING_BRAND_DMG + o_ptr->to_d) * o_ptr->pval * DAMAGE_POWER / MAX_BLOWS); LOG_PRINT1("Adding power for extra blows, total is %d\n", p); } } /* Add power for extra shots */ if (of_has(flags, OF_SHOTS) && (known || object_pval_is_visible(o_ptr))) { LOG_PRINT1("Extra shots: %d\n", o_ptr->pval); if (o_ptr->pval >= INHIBIT_SHOTS || o_ptr->pval < 0) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING - too many extra shots\n"); } else if (o_ptr->pval > 0) { p += ((AVG_XBOW_AMMO_DAMAGE + AVG_LAUNCHER_DMG) * AVG_XBOW_MULT * o_ptr->pval * DAMAGE_POWER * BOW_RESCALER / (20 * MAX_BLOWS)); LOG_PRINT1("Adding power for extra shots - total is %d\n", p); } } break; } } /* Other abilities are evaluated independent of the object type. */ p += sign(o_ptr->to_a) * (ABS(o_ptr->to_a) * TO_AC_POWER / 2); LOG_PRINT2("Adding power for to_ac of %d, total is %d\n", o_ptr->to_a, p); if (o_ptr->to_a > HIGH_TO_AC) { p += ((o_ptr->to_a - (HIGH_TO_AC - 1)) * TO_AC_POWER / 2); LOG_PRINT1("Adding power for high to_ac value, total is %d\n", p); } if (o_ptr->to_a > VERYHIGH_TO_AC) { p += ((o_ptr->to_a - (VERYHIGH_TO_AC -1)) * TO_AC_POWER / 2); LOG_PRINT1("Adding power for very high to_ac value, total is %d\n", p); } if (o_ptr->to_a >= INHIBIT_AC) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING: AC bonus too high\n"); } if ((o_ptr->pval > 0) && (known || object_pval_is_visible(o_ptr))) { if (of_has(flags, OF_STR)) { p += STR_POWER * o_ptr->pval; LOG_PRINT2("Adding power for STR bonus %d, total is %d\n", o_ptr->pval, p); } if (of_has(flags, OF_INT)) { p += INT_POWER * o_ptr->pval; LOG_PRINT2("Adding power for INT bonus %d, total is %d\n", o_ptr->pval, p); } if (of_has(flags, OF_WIS)) { p += WIS_POWER * o_ptr->pval; LOG_PRINT2("Adding power for WIS bonus %d, total is %d\n", o_ptr->pval, p); } if (of_has(flags, OF_DEX)) { p += DEX_POWER * o_ptr->pval; LOG_PRINT2("Adding power for DEX bonus %d, total is %d\n", o_ptr->pval, p); } if (of_has(flags, OF_CON)) { p += CON_POWER * o_ptr->pval; LOG_PRINT2("Adding power for CON bonus %d, total is %d\n", o_ptr->pval, p); } if (of_has(flags, OF_STEALTH)) { p += STEALTH_POWER * o_ptr->pval; LOG_PRINT2("Adding power for Stealth bonus %d, total is %d\n", o_ptr->pval, p); } if (of_has(flags, OF_SEARCH)) { p += SEARCH_POWER * o_ptr->pval; LOG_PRINT2("Adding power for searching bonus %d, total is %d\n", o_ptr->pval , p); } /* Add extra power term if there are a lot of ability bonuses */ if (o_ptr->pval > 0) { extra_stat_bonus += (of_has(flags, OF_STR) ? 1 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_INT) ? 1 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_WIS) ? 1 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_DEX) ? 1 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_CON) ? 1 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_CHR) ? 0 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_STEALTH) ? 1 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_INFRA) ? 0 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_TUNNEL) ? 0 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_SEARCH) ? 0 * o_ptr->pval : 0); extra_stat_bonus += (of_has(flags, OF_SPEED) ? 0 * o_ptr->pval : 0); if (o_ptr->tval == TV_BOW) { extra_stat_bonus += (of_has(flags, OF_MIGHT) ? 5 * o_ptr->pval / 2 : 0); extra_stat_bonus += (of_has(flags, OF_SHOTS) ? 3 * o_ptr->pval : 0); } else if ( (o_ptr->tval == TV_DIGGING) || (o_ptr->tval == TV_HAFTED) || (o_ptr->tval == TV_POLEARM) || (o_ptr->tval == TV_SWORD) ) { extra_stat_bonus += (of_has(flags, OF_BLOWS) ? 3 * o_ptr->pval : 0); } if (extra_stat_bonus > 24) { /* Inhibit */ LOG_PRINT1("Inhibiting! (Total ability bonus of %d is too high)\n", extra_stat_bonus); p += INHIBIT_POWER; } else { p += ability_power[extra_stat_bonus]; LOG_PRINT2("Adding power for combination of %d, total is %d\n", ability_power[extra_stat_bonus], p); } } } else if ((o_ptr->pval < 0) && (known || object_pval_is_visible(o_ptr))) { if (of_has(flags, OF_STR)) p += 4 * o_ptr->pval; if (of_has(flags, OF_INT)) p += 2 * o_ptr->pval; if (of_has(flags, OF_WIS)) p += 2 * o_ptr->pval; if (of_has(flags, OF_DEX)) p += 3 * o_ptr->pval; if (of_has(flags, OF_CON)) p += 4 * o_ptr->pval; if (of_has(flags, OF_STEALTH)) p += o_ptr->pval; LOG_PRINT1("Subtracting power for negative ability values, total is %d\n", p); } if (known || object_pval_is_visible(o_ptr)) { if (of_has(flags, OF_CHR)) { p += CHR_POWER * o_ptr->pval; LOG_PRINT2("Adding power for CHR bonus/penalty %d, total is %d\n", o_ptr->pval, p); } if (of_has(flags, OF_INFRA)) { p += INFRA_POWER * o_ptr->pval; LOG_PRINT2("Adding power for infra bonus/penalty %d, total is %d\n", o_ptr->pval, p); } if (of_has(flags, OF_TUNNEL)) { p += TUNN_POWER * o_ptr->pval; LOG_PRINT2("Adding power for tunnelling bonus/penalty %d, total is %d\n", o_ptr->pval, p); } if (of_has(flags, OF_SPEED)) { p += sign(o_ptr->pval) * speed_power[ABS(o_ptr->pval)]; LOG_PRINT2("Adding power for speed bonus/penalty %d, total is %d\n", o_ptr->pval, p); } } #define ADD_POWER1(string, val, flag) \ if (of_has(flags, flag)) { \ p += (val); \ LOG_PRINT1("Adding power for " string ", total is %d\n", p); \ } #define ADD_POWER2(string, val, flag, extra) \ if (of_has(flags, flag)) { \ p += (val); \ extra; \ LOG_PRINT1("Adding power for " string ", total is %d\n", p); \ } ADD_POWER2("sustain STR", 9, OF_SUST_STR, sustains++); ADD_POWER2("sustain INT", 4, OF_SUST_INT, sustains++); ADD_POWER2("sustain WIS", 4, OF_SUST_WIS, sustains++); ADD_POWER2("sustain DEX", 7, OF_SUST_DEX, sustains++); ADD_POWER2("sustain CON", 8, OF_SUST_CON, sustains++); ADD_POWER1("sustain CHR", 1, OF_SUST_CHR); for (i = 2; i <= sustains; i++) { p += i; LOG_PRINT1("Adding power for multiple sustains, total is %d\n", p); if (i == 5) { p += SUST_POWER; LOG_PRINT1("Adding power for full set of sustains, total is %d\n", p); } } ADD_POWER2("acid immunity", 38, OF_IM_ACID, immunities++); ADD_POWER2("elec immunity", 35, OF_IM_ELEC, immunities++); ADD_POWER2("fire immunity", 40, OF_IM_FIRE, immunities++); ADD_POWER2("cold immunity", 37, OF_IM_COLD, immunities++); for (i = 2; i <= immunities; i++) { p += IMMUNITY_POWER; LOG_PRINT1("Adding power for multiple immunities, total is %d\n", p); if (i >= INHIBIT_IMMUNITIES) { p += INHIBIT_POWER; /* inhibit */ LOG_PRINT("INHIBITING: Too many immunities\n"); } } ADD_POWER2("free action", 14, OF_FREE_ACT, misc++); ADD_POWER2("hold life", 12, OF_HOLD_LIFE, misc++); ADD_POWER1("feather fall", 1, OF_FEATHER); ADD_POWER2("permanent light", 3, OF_LIGHT, misc++); ADD_POWER2("see invisible", 10, OF_SEE_INVIS, misc++); ADD_POWER2("telepathy", 70, OF_TELEPATHY, misc++); ADD_POWER2("slow digestion", 2, OF_SLOW_DIGEST, misc++); ADD_POWER2("resist acid", 5, OF_RES_ACID, lowres++); ADD_POWER2("resist elec", 6, OF_RES_ELEC, lowres++); ADD_POWER2("resist fire", 6, OF_RES_FIRE, lowres++); ADD_POWER2("resist cold", 6, OF_RES_COLD, lowres++); ADD_POWER2("resist poison", 28, OF_RES_POIS, highres++); ADD_POWER2("resist fear", 6, OF_RES_FEAR, highres++); ADD_POWER2("resist light", 6, OF_RES_LIGHT, highres++); ADD_POWER2("resist dark", 16, OF_RES_DARK, highres++); ADD_POWER2("resist blindness", 16, OF_RES_BLIND, highres++); ADD_POWER2("resist confusion", 24, OF_RES_CONFU, highres++); ADD_POWER2("resist sound", 14, OF_RES_SOUND, highres++); ADD_POWER2("resist shards", 8, OF_RES_SHARD, highres++); ADD_POWER2("resist nexus", 15, OF_RES_NEXUS, highres++); ADD_POWER2("resist nether", 20, OF_RES_NETHR, highres++); ADD_POWER2("resist chaos", 20, OF_RES_CHAOS, highres++); ADD_POWER2("resist disenchantment", 20, OF_RES_DISEN, highres++); ADD_POWER2("regeneration", 9, OF_REGEN, misc++); ADD_POWER1("blessed", 1, OF_BLESSED); ADD_POWER1("no fuel", 5, OF_NO_FUEL); for (i = 2; i <= misc; i++) { p += i; LOG_PRINT1("Adding power for multiple misc abilities, total is %d\n", p); } for (i = 2; i <= lowres; i++) { p += i; LOG_PRINT1("Adding power for multiple low resists, total is %d\n", p); if (i == 4) { p += RBASE_POWER; LOG_PRINT1("Adding power for full rbase set, total is %d\n", p); } } for (i = 2; i <= highres; i++) { p += (i * 2); LOG_PRINT1("Adding power for multiple high resists, total is %d\n", p); } /* Note: the following code is irrelevant until curses are reworked */ if (of_has(flags, OF_TELEPORT)) { p -= 1; LOG_PRINT1("Subtracting power for teleportation, total is %d\n", p); } if (of_has(flags, OF_DRAIN_EXP)) { p -= 1; LOG_PRINT1("Subtracting power for drain experience, total is %d\n", p); } if (of_has(flags, OF_AGGRAVATE)) { p -= 1; LOG_PRINT1("Subtracting power for aggravation, total is %d\n", p); } if (of_has(flags, OF_LIGHT_CURSE)) { p -= 1; LOG_PRINT1("Subtracting power for light curse, total is %d\n", p); } if (of_has(flags, OF_HEAVY_CURSE)) { p -= 1; LOG_PRINT1("Subtracting power for heavy curse, total is %d\n", p); } /* if (of_has(flags, OF_PERMA_CURSE)) p -= 40; */ /* add power for effect */ if (known || object_effect_is_known(o_ptr)) { if (o_ptr->name1 && a_info[o_ptr->name1].effect) { p += effect_power(a_info[o_ptr->name1].effect); LOG_PRINT1("Adding power for artifact activation, total is %d\n", p); } else { p += effect_power(k_info[o_ptr->k_idx].effect); LOG_PRINT1("Adding power for item activation, total is %d\n", p); } } /* add tiny amounts for ignore flags */ if (of_has(flags, OF_IGNORE_ACID)) p++; if (of_has(flags, OF_IGNORE_FIRE)) p++; if (of_has(flags, OF_IGNORE_COLD)) p++; if (of_has(flags, OF_IGNORE_ELEC)) p++; LOG_PRINT1("After ignore flags, FINAL POWER IS %d\n", p); return (p); }