/** * Notice things about an object that would be noticed in time. */ static void object_notice_after_time() { int i; int flag; Object o_ptr; string o_name; //[80]; Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag timed_mask = new Bitflag(Object_Flag.SIZE); Object_Flag.create_mask(timed_mask, true, Object_Flag.object_flag_id.TIMED); /* Check every item the player is wearing */ for (i = Misc.INVEN_WIELD; i < Misc.ALL_INVEN_TOTAL; i++) { o_ptr = Misc.p_ptr.inventory[i]; if (o_ptr.kind == null || o_ptr.is_known()) { continue; } /* Check for timed notice flags */ o_name = o_ptr.object_desc(Detail.BASE); o_ptr.object_flags(ref f); f.inter(timed_mask); for (flag = f.next(Bitflag.FLAG_START); flag != Bitflag.FLAG_null; flag = f.next(flag + 1)) { if (!o_ptr.known_flags.has(flag)) { /* Message */ Object_Flag.flag_message(flag, o_name); /* Notice the flag */ o_ptr.notice_flag(flag); if (o_ptr.is_jewelry() && (o_ptr.effect() == null || o_ptr.effect_is_known())) { /* 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 */ o_ptr.flavor_aware(); o_ptr.check_for_ident(); } } else { /* Notice the flag is absent */ o_ptr.notice_flag(flag); } } /* XXX Is this necessary? */ o_ptr.check_for_ident(); } }
/** * Match slays in flags against a chosen flag mask * * count is the number of matches * \param flags is the flagset to analyse for matches * \param mask is the flagset against which to test * \param desc[] is the array of descriptions of matching slays - can be null * \param brand[] is the array of descriptions of brands - can be null * \param mult[] is the array of multipliers of those slays - can be null * \param dedup is whether or not to remove duplicates * * desc[], brand[] and mult[] must be >= SL_MAX in size */ //Bitflags were size Object_Flag.SIZE, might be an out param public static int list_slays(Bitflag flags, Bitflag mask, string[] desc, string[] brand, int[] mult, bool dedup) { int i, count = 0; Bitflag f = new Bitflag(Object_Flag.SIZE); /* We are only interested in the flags specified in mask */ f.copy(flags); f.inter(mask); /* Remove "duplicate" flags if desired */ if (dedup) { dedup_slays(ref f); } /* Collect slays */ for (i = 0; i < list.Count(); i++) { Slay s_ptr = list[i]; if (f.has(s_ptr.object_flag.value)) { if (mult != null) { mult[count] = s_ptr.mult; } if (brand != null) { brand[count] = s_ptr.brand; } if (desc != null) { desc[count] = s_ptr.desc; } count++; } } return(count); }
/** * Notice curses on an object. * * \param o_ptr is the object to notice curses on */ bool notice_curses() { Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); object_flags(ref f); /* Gather whatever curse flags there are to know */ Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.CURSE); /* Remove everything except the curse flags */ f.inter(f2); /* give knowledge of which curses are present */ notice_flags(f); check_for_ident(); Misc.p_ptr.notice |= Misc.PN_SQUELCH; return(!f.is_empty()); }
/** * Notice curses on an object. * * \param o_ptr is the object to notice curses on */ bool notice_curses() { Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); object_flags(ref f); /* Gather whatever curse flags there are to know */ Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.CURSE); /* Remove everything except the curse flags */ f.inter(f2); /* give knowledge of which curses are present */ notice_flags(f); check_for_ident(); Misc.p_ptr.notice |= Misc.PN_SQUELCH; return !f.is_empty(); }
/** * Notice things about an object that would be noticed in time. */ static void object_notice_after_time() { int i; int flag; Object o_ptr; string o_name;//[80]; Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag timed_mask = new Bitflag(Object_Flag.SIZE); Object_Flag.create_mask(timed_mask, true, Object_Flag.object_flag_id.TIMED); /* Check every item the player is wearing */ for (i = Misc.INVEN_WIELD; i < Misc.ALL_INVEN_TOTAL; i++) { o_ptr = Misc.p_ptr.inventory[i]; if (o_ptr.kind == null || o_ptr.is_known()) continue; /* Check for timed notice flags */ o_name = o_ptr.object_desc(Detail.BASE); o_ptr.object_flags(ref f); f.inter(timed_mask); for (flag = f.next(Bitflag.FLAG_START); flag != Bitflag.FLAG_null; flag = f.next(flag + 1)) { if (!o_ptr.known_flags.has(flag)) { /* Message */ Object_Flag.flag_message(flag, o_name); /* Notice the flag */ o_ptr.notice_flag(flag); if (o_ptr.is_jewelry() && (o_ptr.effect() == null || o_ptr.effect_is_known())) { /* 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 */ o_ptr.flavor_aware(); o_ptr.check_for_ident(); } } else { /* Notice the flag is absent */ o_ptr.notice_flag(flag); } } /* XXX Is this necessary? */ o_ptr.check_for_ident(); } }
/** * Add a pval to an object, rearranging flags as necessary. Returns true * if the number of pvals is now different, false if it is the same. * * \param o_ptr is the object we're adjusting * \param pval is the pval we are adding * \param flag is the flag to which we are adding the pval */ bool add_pval(int pval, int flag) { Bitflag f = new Bitflag(Object_Flag.SIZE); int a = -1, best_pval; /* Sanity check (we may be called with 0 - see ticket #1451) */ if (pval == 0) return false; Object_Flag.create_mask(f, false, Object_Flag.object_flag_type.PVAL, Object_Flag.object_flag_type.STAT); if (flags.has(flag)) { /* See if any other flags are associated with this pval */ a = which_pval(flag); f.off(flag); f.inter(pval_flags[a]); if (f.is_empty()) { /* Safe to increment and finish */ this.pval[a] += (short)pval; if (this.pval[a] == 0) { /* Remove the flag */ flags.off(flag); pval_flags[a].off(flag); } return (object_dedup_pvals()); } } /* So it doesn't have the flag, or it does but that pval also has others */ /* Create a new pval if we can */ if (this.num_pvals < Misc.MAX_PVALS) { this.pval[this.num_pvals] = (short)pval; this.pval_flags[this.num_pvals].on(flag); if (a != -1) { /* then we need to move the flag to the new pval */ this.pval[this.num_pvals] += this.pval[a]; this.pval_flags[a].off(flag); } else /* We need to add it to object_flags */ this.flags.on(flag); this.num_pvals++; /* We do this last because pvals start from zero */ /* We invert the logic because we've already added a pval */ return (!object_dedup_pvals()); } else { /* we use the closest existing pval */ best_pval = object_closest_pval((pval + (a == -1 ? 0 : this.pval[a]))); if (best_pval != a) { /* turn on the flag on the new pval */ this.pval_flags[best_pval].on(flag); if(a != -1) /* turn it off on its old pval */ this.pval_flags[a].off(flag); else /* add it to object_flags */ this.flags.on(flag); } return false; /* We haven't changed any pvals, so no need to de-dup */ } }
/* * Given an object, return a short identifier which gives some idea of what * the item is. */ public obj_pseudo_t pseudo() { Bitflag flags = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); /* Get the known and obvious flags on the object, * not including curses or properties of the kind. */ object_flags_known(ref flags); Object_Flag.create_mask(f2, true, Object_Flag.object_flag_id.WIELD); /* FA on gloves is obvious to mage casters */ if (FA_would_be_obvious()) f2.on(Object_Flag.FREE_ACT.value); /* Now we remove the non-obvious known flags */ flags.inter(f2); /* Now we remove the cursed flags and the kind flags */ Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.CURSE); flags.diff(f2); flags.diff(kind.flags); if ((ident & IDENT_INDESTRUCT) != 0) return obj_pseudo_t.INSCRIP_SPECIAL; if ((was_sensed() || was_worn()) && artifact != null) return obj_pseudo_t.INSCRIP_SPECIAL; /* jewelry does not pseudo */ if (is_jewelry()) return obj_pseudo_t.INSCRIP_null; /* XXX Eddie should also check for flags with pvals where the pval exceeds * the base pval for things like picks of digging, though for now acid brand gets those */ if (!flags.is_empty()) return obj_pseudo_t.INSCRIP_SPLENDID; if (!is_known() && !was_sensed()) return obj_pseudo_t.INSCRIP_null; if (ego != null) { /* uncursed bad egos are not excellent */ if (ego.flags.is_inter(f2)) return obj_pseudo_t.INSCRIP_STRANGE; /* XXX Eddie need something worse */ else return obj_pseudo_t.INSCRIP_EXCELLENT; } if (to_a == Random.randcalc(kind.to_a, 0, aspect.MINIMISE) && to_h == Random.randcalc(kind.to_h, 0, aspect.MINIMISE) && to_d == Random.randcalc(kind.to_d, 0, aspect.MINIMISE)) return obj_pseudo_t.INSCRIP_AVERAGE; if (to_a >= Random.randcalc(kind.to_a, 0, aspect.MINIMISE) && to_h >= Random.randcalc(kind.to_h, 0, aspect.MINIMISE) && to_d >= Random.randcalc(kind.to_d, 0, aspect.MINIMISE)) return obj_pseudo_t.INSCRIP_MAGICAL; if (to_a <= Random.randcalc(kind.to_a, 0, aspect.MINIMISE) && to_h <= Random.randcalc(kind.to_h, 0, aspect.MINIMISE) && to_d <= Random.randcalc(kind.to_d, 0, aspect.MINIMISE)) return obj_pseudo_t.INSCRIP_MAGICAL; return obj_pseudo_t.INSCRIP_STRANGE; }
/* * Obtain the flags for an item which are known to the player */ public void object_flags_known(ref Bitflag flags) { object_flags(ref flags); flags.inter(known_flags); if (flavor_is_aware()) flags.union(kind.flags); if (ego != null && easy_know()) flags.union(ego.flags); }
/** * Calculate the rating for a given slay combination */ int slay_power(bool verbose, StreamWriter log_file, bool known) { Bitflag s_index = new Bitflag(Object_Flag.SIZE); Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); int sv = 0; //uint int i, j; int mult; Slay best_s_ptr = null; Monster_Race r_ptr; Monster.Monster m_ptr; //monster_type monster_type_body; string[] desc = new string[Slay.MAX.value]; // = { 0 }, * string[] brand = new string[Slay.MAX.value]; // = { 0 }; int[] s_mult = new int[Slay.MAX.value]; // = { 0 }; if (known) { object_flags(ref f); } else { object_flags_known(ref f); } /* Combine the slay bytes into an index value, return if there are none */ s_index.copy(f); Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.SLAY, Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND); if (!s_index.is_inter(f2)) { return(Eval.tot_mon_power); } else { s_index.inter(f2); } /* Look in the cache to see if we know this one yet */ sv = Slay.check_slay_cache(s_index); /* If it's cached (or there are no slays), return the value */ if (sv != 0) { //file_putf(log_file, "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 < Misc.z_info.r_max; i++) { best_s_ptr = null; mult = 1; r_ptr = Misc.r_info[i]; if (r_ptr == null) { continue; } m_ptr = new Monster.Monster(); m_ptr.r_idx = (short)i; /* Find the best multiplier against this monster */ Slay.improve_attack_modifier(this, m_ptr, ref best_s_ptr, false, !known); if (best_s_ptr != null) { mult = best_s_ptr.mult; } /* Add the multiple to sv */ sv += (int)(mult * r_ptr.scaled_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: "); j = Slay.list_slays(s_index, s_index, desc, brand, s_mult, false); //for (i = 0; i < j; i++) { // if (brand[i]) { // file_putf(log_file, brand[i]); // } else { // file_putf(log_file, desc[i]); // } // file_putf(log_file, "x%d ", s_mult[i]); //} //file_putf(log_file, "\nsv 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 */ if (Slay.fill_slay_cache(s_index, sv)) { //file_putf(log_file, "Added to slay cache\n"); } return(sv); }
/** * 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 */ public static int create_slay_cache(Ego_Item[] items) { int count = 0; Bitflag cacheme = new Bitflag(Object_Flag.SIZE); Bitflag slay_mask = new Bitflag(Object_Flag.SIZE); /* Build the slay mask */ Object_Flag.create_mask(slay_mask, false, Object_Flag.object_flag_type.SLAY, Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND); /* Calculate necessary size of slay_cache */ Bitflag[] dupcheck = new Bitflag[Misc.z_info.e_max]; for (int i = 0; i < Misc.z_info.e_max; i++) { dupcheck[i] = new Bitflag(Object_Flag.SIZE); Ego_Item e_ptr = items[i]; //Some items are null... I guess we should just skip them...? //TODO: Find out why they are null, and see if we actually should just skip them... if (e_ptr == null) { continue; } /* Find the slay flags on this ego */ cacheme.copy(e_ptr.flags); cacheme.inter(slay_mask); /* Only consider non-empty combinations of slay flags */ if (!cacheme.is_empty()) { /* Skip previously scanned combinations */ for (int j = 0; j < i; j++) { if (cacheme.is_equal(dupcheck[j])) { continue; } } /* msg("Found a new slay combo on an ego item"); */ count++; dupcheck[i].copy(cacheme); } } /* Allocate slay_cache with an extra empty element for an iteration stop */ slay_cache = new flag_cache[count + 1]; count = 0; /* Populate the slay_cache */ for (int i = 0; i < Misc.z_info.e_max; i++) { if (!dupcheck[i].is_empty()) { slay_cache[count] = new flag_cache(); slay_cache[count].flags.copy(dupcheck[i]); slay_cache[count].value = 0; count++; /*msg("Cached a slay combination");*/ } } //From a time without garbage collection... /*for (i = 0; i < z_info.e_max; i++) * FREE(dupcheck[i]); * FREE(dupcheck);*/ /* Success */ return(0); }
/** * Calculate the rating for a given slay combination */ int slay_power(bool verbose, StreamWriter log_file, bool known) { Bitflag s_index = new Bitflag(Object_Flag.SIZE); Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); int sv = 0; //uint int i, j; int mult; Slay best_s_ptr = null; Monster_Race r_ptr; Monster.Monster m_ptr; //monster_type monster_type_body; string[] desc = new string[Slay.MAX.value];// = { 0 }, * string[] brand = new string[Slay.MAX.value];// = { 0 }; int[] s_mult = new int[Slay.MAX.value];// = { 0 }; if (known) object_flags(ref f); else object_flags_known(ref f); /* Combine the slay bytes into an index value, return if there are none */ s_index.copy(f); Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.SLAY, Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND); if (!s_index.is_inter(f2)) return Eval.tot_mon_power; else s_index.inter(f2); /* Look in the cache to see if we know this one yet */ sv = Slay.check_slay_cache(s_index); /* If it's cached (or there are no slays), return the value */ if (sv != 0) { //file_putf(log_file, "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 < Misc.z_info.r_max; i++) { best_s_ptr = null; mult = 1; r_ptr = Misc.r_info[i]; if(r_ptr == null) continue; m_ptr = new Monster.Monster(); m_ptr.r_idx = (short)i; /* Find the best multiplier against this monster */ Slay.improve_attack_modifier(this, m_ptr, ref best_s_ptr, false, !known); if (best_s_ptr != null) mult = best_s_ptr.mult; /* Add the multiple to sv */ sv += (int)(mult * r_ptr.scaled_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: "); j = Slay.list_slays(s_index, s_index, desc, brand, s_mult, false); //for (i = 0; i < j; i++) { // if (brand[i]) { // file_putf(log_file, brand[i]); // } else { // file_putf(log_file, desc[i]); // } // file_putf(log_file, "x%d ", s_mult[i]); //} //file_putf(log_file, "\nsv 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 */ if(Slay.fill_slay_cache(s_index, sv)) { //file_putf(log_file, "Added to slay cache\n"); } return sv; }
/** * Match slays in flags against a chosen flag mask * * count is the number of matches * \param flags is the flagset to analyse for matches * \param mask is the flagset against which to test * \param desc[] is the array of descriptions of matching slays - can be null * \param brand[] is the array of descriptions of brands - can be null * \param mult[] is the array of multipliers of those slays - can be null * \param dedup is whether or not to remove duplicates * * desc[], brand[] and mult[] must be >= SL_MAX in size */ //Bitflags were size Object_Flag.SIZE, might be an out param public static int list_slays(Bitflag flags, Bitflag mask, string[] desc, string[] brand,int[] mult, bool dedup) { int i, count = 0; Bitflag f = new Bitflag(Object_Flag.SIZE); /* We are only interested in the flags specified in mask */ f.copy(flags); f.inter(mask); /* Remove "duplicate" flags if desired */ if (dedup) dedup_slays(ref f); /* Collect slays */ for (i = 0; i < list.Count(); i++) { Slay s_ptr = list[i]; if (f.has(s_ptr.object_flag.value)) { if (mult != null) mult[count] = s_ptr.mult; if (brand != null) brand[count] = s_ptr.brand; if (desc != null) desc[count] = s_ptr.desc; count++; } } return count; }
/** * 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 */ public static int create_slay_cache(Ego_Item[] items) { int count = 0; Bitflag cacheme = new Bitflag(Object_Flag.SIZE); Bitflag slay_mask = new Bitflag(Object_Flag.SIZE); /* Build the slay mask */ Object_Flag.create_mask(slay_mask, false, Object_Flag.object_flag_type.SLAY, Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND); /* Calculate necessary size of slay_cache */ Bitflag[] dupcheck = new Bitflag[Misc.z_info.e_max]; for (int i = 0; i < Misc.z_info.e_max; i++) { dupcheck[i] = new Bitflag(Object_Flag.SIZE); Ego_Item e_ptr = items[i]; //Some items are null... I guess we should just skip them...? //TODO: Find out why they are null, and see if we actually should just skip them... if(e_ptr == null) { continue; } /* Find the slay flags on this ego */ cacheme.copy(e_ptr.flags); cacheme.inter(slay_mask); /* Only consider non-empty combinations of slay flags */ if (!cacheme.is_empty()) { /* Skip previously scanned combinations */ for (int j = 0; j < i; j++) if (cacheme.is_equal(dupcheck[j])) continue; /* msg("Found a new slay combo on an ego item"); */ count++; dupcheck[i].copy(cacheme); } } /* Allocate slay_cache with an extra empty element for an iteration stop */ slay_cache = new flag_cache[count + 1]; count = 0; /* Populate the slay_cache */ for (int i = 0; i < Misc.z_info.e_max; i++) { if (!dupcheck[i].is_empty()) { slay_cache[count] = new flag_cache(); slay_cache[count].flags.copy(dupcheck[i]); slay_cache[count].value = 0; count++; /*msg("Cached a slay combination");*/ } } //From a time without garbage collection... /*for (i = 0; i < z_info.e_max; i++) FREE(dupcheck[i]); FREE(dupcheck);*/ /* Success */ return 0; }