/* * 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; }
/** * Describe random powers on ego items * * \param tb is the description textblock we're building * \param ego is the ego type we're analysing */ static bool describe_ego(textblock *tb, const struct ego_item *ego) { if (ego && ego->num_randlines) { int i, of_type, tot = 0; bitflag f[OF_SIZE]; for (i = 0; i < ego->num_randlines; i++) { /* See whether we recognise the flagset for this choice */ of_type = obj_flag_type(of_next(ego->randmask[i], FLAG_START)); create_mask(f, FALSE, of_type, OFT_MAX); if (of_is_equal(f, ego->randmask[i])) { textblock_append(tb, "It provides %s random %s. ", ego->num_randflags[i] > 1 ? "more than one" : "one", obj_flagtype_name(of_type)); } else /* We don't, so count the number for later */ tot += ego->num_randflags[i]; } if (tot) textblock_append(tb, "It provides %s random power. ", tot > 1 ? "more than one" : "one"); return TRUE; } return FALSE; }
/** * Create a cache of slay combinations found on ego items, and the values of * these combinations. This is to speed up slay_power(), which will be called * many times for ego items during the game. * * \param items is the set of ego types from which we are extracting slay * combinations */ errr create_slay_cache(struct ego_item *items) { int i; int j; int count = 0; bitflag cacheme[OF_SIZE]; bitflag slay_mask[OF_SIZE]; bitflag **dupcheck; ego_item_type *e_ptr; /* Build the slay mask */ create_mask(slay_mask, FALSE, OFT_SLAY, OFT_KILL, OFT_BRAND, OFT_MAX); /* Calculate necessary size of slay_cache */ dupcheck = C_ZNEW(z_info->e_max, bitflag *); for (i = 0; i < z_info->e_max; i++) { dupcheck[i] = C_ZNEW(OF_SIZE, bitflag); e_ptr = items + i; /* Find the slay flags on this ego */ of_copy(cacheme, e_ptr->flags); of_inter(cacheme, slay_mask); /* Only consider non-empty combinations of slay flags */ if (!of_is_empty(cacheme)) { /* Skip previously scanned combinations */ for (j = 0; j < i; j++) if (of_is_equal(cacheme, dupcheck[j])) continue; /* msg("Found a new slay combo on an ego item"); */ count++; of_copy(dupcheck[i], cacheme); } } /* Allocate slay_cache with an extra empty element for an iteration stop */ slay_cache = C_ZNEW((count + 1), struct flag_cache); count = 0; /* Populate the slay_cache */ for (i = 0; i < z_info->e_max; i++) { if (!of_is_empty(dupcheck[i])) { of_copy(slay_cache[count].flags, dupcheck[i]); slay_cache[count].value = 0; count++; /*msg("Cached a slay combination");*/ } } for (i = 0; i < z_info->e_max; i++) FREE(dupcheck[i]); FREE(dupcheck); /* Success */ return 0; }
/** * Check the slay cache for a combination of slays and return a slay value * * \param index is the set of slay flags to look for */ s32b check_slay_cache(bitflag *index) { int i; for (i = 0; !of_is_empty(slay_cache[i].flags); i++) if (of_is_equal(index, slay_cache[i].flags)) break; return slay_cache[i].value; }
/** * Fill in a value in the slay cache. Return TRUE if a change is made. * * \param index is the set of slay flags whose value we are adding * \param value is the value of the slay flags in index */ bool fill_slay_cache(bitflag *index, s32b value) { int i; for (i = 0; !of_is_empty(slay_cache[i].flags); i++) { if (of_is_equal(index, slay_cache[i].flags)) { slay_cache[i].value = value; return TRUE; } } return FALSE; }
/** * Determine if an item can "absorb" a second item * * See "object_absorb()" for the actual "absorption" code. * * If permitted, we allow weapons/armor to stack, if "known". * * Missiles will combine if both stacks have the same "known" status. * This is done to make unidentified stacks of missiles useful. * * Food, potions, scrolls, and "easy know" items always stack. * * Chests, and activatable items, except rods, never stack (for various * reasons). */ bool object_stackable(const struct object *obj1, const struct object *obj2, object_stack_t mode) { int i; /* Equipment items don't stack */ if (object_is_equipped(player->body, obj1)) return false; if (object_is_equipped(player->body, obj2)) return false; /* If either item is unknown, do not stack */ if (mode & OSTACK_LIST && obj1->kind != obj1->known->kind) return false; if (mode & OSTACK_LIST && obj2->kind != obj2->known->kind) return false; /* Hack -- identical items cannot be stacked */ if (obj1 == obj2) return false; /* Require identical object kinds */ if (obj1->kind != obj2->kind) return false; /* Different flags don't stack */ if (!of_is_equal(obj1->flags, obj2->flags)) return false; /* Different elements don't stack */ for (i = 0; i < ELEM_MAX; i++) { if (obj1->el_info[i].res_level != obj2->el_info[i].res_level) return false; if ((obj1->el_info[i].flags & (EL_INFO_HATES | EL_INFO_IGNORE)) != (obj2->el_info[i].flags & (EL_INFO_HATES | EL_INFO_IGNORE))) return false; } /* Artifacts never stack */ if (obj1->artifact || obj2->artifact) return false; /* Analyze the items */ if (tval_is_chest(obj1)) { /* Chests never stack */ return false; } else if (tval_is_edible(obj1) || tval_is_potion(obj1) || tval_is_scroll(obj1) || tval_is_rod(obj1)) { /* Food, potions, scrolls and rods all stack nicely, since the kinds are identical, either both will be aware or both will be unaware */ } else if (tval_can_have_charges(obj1) || tval_is_money(obj1)) { /* Gold, staves and wands stack most of the time */ /* Too much gold or too many charges */ if (obj1->pval + obj2->pval > MAX_PVAL) return false; /* ... otherwise ok */ } else if (tval_is_weapon(obj1) || tval_is_armor(obj1) || tval_is_jewelry(obj1) || tval_is_light(obj1)) { bool obj1_is_known = object_fully_known((struct object *)obj1); bool obj2_is_known = object_fully_known((struct object *)obj2); /* Require identical values */ if (obj1->ac != obj2->ac) return false; if (obj1->dd != obj2->dd) return false; if (obj1->ds != obj2->ds) return false; /* Require identical bonuses */ if (obj1->to_h != obj2->to_h) return false; if (obj1->to_d != obj2->to_d) return false; if (obj1->to_a != obj2->to_a) return false; /* Require all identical modifiers */ for (i = 0; i < OBJ_MOD_MAX; i++) if (obj1->modifiers[i] != obj2->modifiers[i]) return (false); /* Require identical ego-item types */ if (obj1->ego != obj2->ego) return false; /* Require identical curses */ if (!curses_are_equal(obj1->curses, obj2->curses)) return false; /* Hack - Never stack recharging wearables ... */ if ((obj1->timeout || obj2->timeout) && !tval_is_light(obj1)) return false; /* ... and lights must have same amount of fuel */ else if ((obj1->timeout != obj2->timeout) && tval_is_light(obj1)) return false; /* Prevent unIDd items stacking with IDd items in the object list */ if (mode & OSTACK_LIST && (obj1_is_known != obj2_is_known)) return false; } else { /* Anything else probably okay */ } /* Require compatible inscriptions */ if (obj1->note && obj2->note && (obj1->note != obj2->note)) return false; /* They must be similar enough */ return true; }
/* * Calculate the rating for a given slay combination */ static s32b slay_power(const object_type *o_ptr, int verbose, ang_file* log_file, const bitflag flags[OF_SIZE]) { bitflag s_index[OF_SIZE]; s32b sv = 0; int i; int mult; const slay_t *s_ptr; /* Combine the slay bytes into an index value */ of_copy(s_index, flags); flags_mask(s_index, OF_SIZE, OF_ALL_SLAY_MASK, FLAG_END); /* Look in the cache to see if we know this one yet */ for (i = 0; !of_is_empty(slay_cache[i].flags); i++) { if (of_is_equal(s_index, slay_cache[i].flags)) break; } sv = slay_cache[i].value; /* If it's cached (or there are no slays), return the value */ if (sv) { LOG_PRINT("Slay cache hit\n"); return sv; } /* * Otherwise we need to calculate the expected average multiplier * for this combination (multiplied by the total number of * monsters, which we'll divide out later). */ for (i = 0; i < z_info->r_max; i++) { monster_race *r_ptr = &r_info[i]; mult = 1; /* * Do the following in ascending order so that the best * multiple is retained */ for (s_ptr = slay_table; s_ptr->slay_flag; s_ptr++) { if (!of_has(flags, s_ptr->slay_flag)) continue; if (rf_has(r_ptr->flags, s_ptr->monster_flag) || (s_ptr->resist_flag && !rf_has(r_ptr->flags, s_ptr->resist_flag))) { mult = s_ptr->mult; } } /* Add the multiple to sv */ sv += mult * r_ptr->power; } /* * To get the expected damage for this weapon, multiply the * average damage from base dice by sv, and divide by the * total number of monsters. */ if (verbose) { /* Write info about the slay combination and multiplier */ file_putf(log_file,"Slay multiplier for:"); if (of_has(flags, OF_SLAY_EVIL)) file_putf(log_file,"Evl "); if (of_has(flags, OF_KILL_DRAGON)) file_putf(log_file,"XDr "); if (of_has(flags, OF_KILL_DEMON)) file_putf(log_file,"XDm "); if (of_has(flags, OF_KILL_UNDEAD)) file_putf(log_file,"XUn "); if (of_has(flags, OF_SLAY_ANIMAL)) file_putf(log_file,"Ani "); if (of_has(flags, OF_SLAY_UNDEAD)) file_putf(log_file,"Und "); if (of_has(flags, OF_SLAY_DRAGON)) file_putf(log_file,"Drg "); if (of_has(flags, OF_SLAY_DEMON)) file_putf(log_file,"Dmn "); if (of_has(flags, OF_SLAY_TROLL)) file_putf(log_file,"Tro "); if (of_has(flags, OF_SLAY_ORC)) file_putf(log_file,"Orc "); if (of_has(flags, OF_SLAY_GIANT)) file_putf(log_file,"Gia "); if (of_has(flags, OF_BRAND_ACID)) file_putf(log_file,"Acd "); if (of_has(flags, OF_BRAND_ELEC)) file_putf(log_file,"Elc "); if (of_has(flags, OF_BRAND_FIRE)) file_putf(log_file,"Fir "); if (of_has(flags, OF_BRAND_COLD)) file_putf(log_file,"Cld "); if (of_has(flags, OF_BRAND_POIS)) file_putf(log_file,"Poi "); file_putf(log_file,"sv is: %d\n", sv); file_putf(log_file," and t_m_p is: %d \n", tot_mon_power); file_putf(log_file,"times 1000 is: %d\n", (1000 * sv) / tot_mon_power); } /* Add to the cache */ for (i = 0; !of_is_empty(slay_cache[i].flags); i++) { if (of_is_equal(s_index, slay_cache[i].flags)) { slay_cache[i].value = sv; LOG_PRINT("Added to slay cache\n"); break; } } return sv; }