public Artifact() { for (int i = 0; i < Misc.MAX_PVAL; i++) { pval_flags[i] = new Bitflag(Object_Flag.SIZE); } }
/** * Notice any slays on a particular object which are in mask. * * \param o_ptr is the object on which we are noticing slays * \param mask is the flagset within which we are noticing them */ //mask was size: Object_Flag.SIZE. It might not even be an array, but just a bitflag with that size... //It might end up being an out parameter... public static void object_notice_slays(Object o_ptr, Bitflag mask) { throw new NotImplementedException(); //bool learned; //bitflag f[Object_Flag.SIZE]; //char o_name[40]; //int i; ///* We are only interested in the flags specified in mask */ //object_flags(o_ptr, f); //Object_Flag.inter(f, mask); ///* if you learn a slay, learn the ego and print a message */ //for (i = 0; i < SL_MAX; i++) { // const struct slay *s_ptr = &slay_table[i]; // if (Object_Flag.has(f, s_ptr.object_flag)) { // learned = object_notice_flag(o_ptr, s_ptr.object_flag); // if (EASY_LEARN && learned) { // object_notice_ego(o_ptr); // object_desc(o_name, sizeof(o_name), o_ptr, ODESC_BASE); // msg("Your %s %s!", o_name, s_ptr.active_verb); // } // } //} //object_check_for_ident(o_ptr); }
/** * Remove slays which are duplicates, i.e. they have exactly the same "monster * flag" and the same "resist flag". The one with highest multiplier is kept. * * \param flags is the flagset from which to remove duplicates. * count is the number of dups removed. */ public static int dedup_slays(ref Bitflag flags) { int i, j; int count = 0; for (i = 0; i < list.Count(); i++) { Slay s_ptr = list[i]; if (flags.has(s_ptr.object_flag.value)) { for (j = i + 1; j < list.Count(); j++) { Slay t_ptr = list[j]; if (flags.has(t_ptr.object_flag.value) && (t_ptr.monster_flag == s_ptr.monster_flag) && (t_ptr.resist_flag == s_ptr.resist_flag) && (t_ptr.mult != s_ptr.mult)) { count++; if (t_ptr.mult > s_ptr.mult) { flags.off(s_ptr.object_flag.value); } else { flags.off(t_ptr.object_flag.value); } } } } } return(count); }
/** * Extract the multiplier from a given object hitting a given monster. * * \param o_ptr is the object being used to attack * \param m_ptr is the monster being attacked * \param best_s_ptr is the best applicable slay_table entry, or null if no * slay already known * \param real is whether this is a real attack (where we update lore) or a * simulation (where we don't) * \param known_only is whether we are using all the object flags, or only * the ones we *already* know about */ //Best_s_ptr was slay** public static void improve_attack_modifier(Object o_ptr, Monster.Monster m_ptr, ref Slay best_s_ptr, bool real, bool known_only) { Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; Monster_Lore l_ptr = Misc.l_list[m_ptr.r_idx]; Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag known_f = new Bitflag(Object_Flag.SIZE); Bitflag note_f = new Bitflag(Object_Flag.SIZE); int i; o_ptr.object_flags(ref f); o_ptr.object_flags_known(ref known_f); for (i = 0; i < Slay.MAX.value; i++) { Slay s_ptr = list[i]; if ((known_only && !known_f.has(s_ptr.object_flag.value)) || (!known_only && !f.has(s_ptr.object_flag.value))) { continue; } /* In a real attack, learn about monster resistance or slay match if: * EITHER the slay flag on the object is known, * OR the monster is vulnerable to the slay/brand */ if (real && (known_f.has(s_ptr.object_flag.value) || (s_ptr.monster_flag != Monster_Flag.NONE && r_ptr.flags.has(s_ptr.monster_flag.value)) || (s_ptr.resist_flag != Monster_Flag.NONE && !r_ptr.flags.has(s_ptr.resist_flag.value)))) { /* notice any brand or slay that would affect monster */ note_f.wipe(); note_f.on(s_ptr.object_flag.value); object_notice_slays(o_ptr, note_f); if (m_ptr.ml && s_ptr.monster_flag != Monster_Flag.NONE) { l_ptr.flags.on(s_ptr.monster_flag.value); } if (m_ptr.ml && s_ptr.resist_flag != Monster_Flag.NONE) { l_ptr.flags.on(s_ptr.resist_flag.value); } } /* If the monster doesn't resist or the slay flag matches */ if ((s_ptr.brand != null && s_ptr.brand.Length != 0 && !r_ptr.flags.has(s_ptr.resist_flag.value)) || (s_ptr.monster_flag != Monster_Flag.NONE && r_ptr.flags.has(s_ptr.monster_flag.value))) { /* compare multipliers to determine best attack */ if ((best_s_ptr == null) || ((best_s_ptr).mult < s_ptr.mult)) { best_s_ptr = s_ptr; } } } }
/** * Determine whether a flagset includes any curse flags. */ public static bool cursed_p(Bitflag f) { Bitflag f2 = new Bitflag(Object_Flag.SIZE); f2.wipe(); create_mask(f2, false, object_flag_type.CURSE); return(f.is_inter(f2)); }
/** * 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(); } }
/* * 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 check_for_ident() { Bitflag flags = new Bitflag(Object_Flag.SIZE); Bitflag known_flags = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); object_flags(ref flags); object_flags_known(ref known_flags); /* Some flags are irrelevant or never learned or too hard to learn */ Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.INT, Object_Flag.object_flag_type.IGNORE, Object_Flag.object_flag_type.HATES); flags.diff(f2); known_flags.diff(f2); if (!flags.is_equal(known_flags)) { return(false); } /* If we know attack bonuses, and defence bonuses, and effect, then * we effectively know everything, so mark as such */ if ((attack_plusses_are_visible() || (was_sensed() && to_h == 0 && to_d == 0)) && (defence_plusses_are_visible() || (was_sensed() && to_a == 0)) && (effect_is_known() || effect() == null)) { /* In addition to knowing the pval flags, it is necessary to know the pvals to know everything */ int i; for (i = 0; i < num_pvals; i++) { if (!this_pval_is_visible(i)) { break; } } if (i == num_pvals) { notice_everything(); return(true); } } /* We still know all the flags, so we still know if it's an ego */ if (ego != null) { /* require worn status so you don't learn launcher of accuracy or gloves of slaying before wield */ if (was_worn()) { notice_ego(); } } return(false); }
/** * Get a random slay (or brand). * We use randint1 because the first entry in slay_table is null. * * \param mask is the set of slays from which we are choosing. */ //mask.size = Object_Flag.SIZE public static Slay random_slay(Bitflag mask) { throw new NotImplementedException(); //const struct slay *s_ptr; //do { // s_ptr = &slay_table[randint1(SL_MAX - 1)]; //} while (!Object_Flag.has(mask, s_ptr.object_flag)); //return s_ptr; }
public byte xtra; /* Extra sustain/resist/power */ #endregion Fields #region Constructors public Ego_Item() { for(int i = 0; i < Misc.MAX_PVALS; i++) { pval_flags[i] = new Bitflag(Object_Flag.SIZE); } to_h = new random_value(); to_d = new random_value(); to_a = new random_value(); }
/** * Log the names of a flagset to a file. * * \param f is the set of flags we are logging. * \param log_file is the file to which we are logging the names. */ //log_file was type ang_file... I don't think we need that anymore... public static void log_flags(Bitflag f, FileStream log_file) { throw new NotImplementedException(); //int i; //file_putf(log_file, "Object flags are:\n"); //for (i = 0; i < OF_MAX; i++) // if (of_has(f, i)) // file_putf(log_file, "%s\n", flag_names[i]); }
/** * React to slays which hurt a monster * * \param obj_flags is the set of flags we're testing for slays * \param mon_flags is the set of flags we're adjusting as a result */ //both are probably arrays public static void react_to_slay(Bitflag obj_flags, Bitflag mon_flags) { throw new NotImplementedException(); //int i; //for (i = 0; i < SL_MAX; i++) { // const struct slay *s_ptr = &slay_table[i]; // if (Object_Flag.has(obj_flags, s_ptr.object_flag) && s_ptr.monster_flag) // Monster_Flag.on(mon_flags, s_ptr.monster_flag); //} }
public Ego_Item() { for (int i = 0; i < Misc.MAX_PVALS; i++) { pval_flags[i] = new Bitflag(Object_Flag.SIZE); } to_h = new random_value(); to_d = new random_value(); to_a = new random_value(); }
/** * Notice a given special flag on wielded items. * * \param flag is the flag to notice */ public static void wieldeds_notice_flag(Player.Player p, int flag) { int i; /* Sanity check */ if (flag == 0) { return; } /* XXX Eddie need different naming conventions for starting wieldeds at INVEN_WIELD vs INVEN_WIELD+2 */ for (i = Misc.INVEN_WIELD; i < Misc.ALL_INVEN_TOTAL; i++) { Object o_ptr = p.inventory[i]; Bitflag f = new Bitflag(Object_Flag.SIZE); if (o_ptr.kind == null) { continue; } o_ptr.object_flags(ref f); if (f.has(flag) && !o_ptr.known_flags.has(flag)) { //char o_name[80]; string o_name = o_ptr.object_desc(Detail.BASE); /* Notice the flag */ o_ptr.notice_flag(flag); /* XXX Eddie should this go before noticing the flag to avoid learning twice? */ if (EASY_LEARN && o_ptr.is_jewelry()) { /* XXX Eddie EASY_LEARN Possible concern: gets =teleportation just from +2 speed */ o_ptr.flavor_aware(); o_ptr.check_for_ident(); } /* Message */ Object_Flag.flag_message(flag, o_name); } else { /* Notice that flag is absent */ o_ptr.notice_flag(flag); } /* XXX Eddie should not need this, should be done in noticing, but will remove later */ o_ptr.check_for_ident(); } return; }
/** * 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 */ public static bool fill_slay_cache(Bitflag index, int value) { for (int i = 0; !slay_cache[i].flags.is_empty(); i++) { if (index.is_equal(slay_cache[i].flags)) { slay_cache[i].value = value; return(true); } } return(false); }
static int obj_desc_light(Object o_ptr, ref string buf, int max, int end) { Bitflag f = new Bitflag(Object_Flag.SIZE); o_ptr.object_flags(ref f); /* Fuelled light sources get number of remaining turns appended */ if ((o_ptr.tval == TVal.TV_LIGHT) && !f.has(Object_Flag.NO_FUEL.value)) { buf += String.Format(" ({0} turns)", o_ptr.timeout); } return(buf.Length); }
/** * 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 */ //index might be an array public static int check_slay_cache(Bitflag index) { int i; for (i = 0; !slay_cache[i].flags.is_empty(); i++) { if (index.is_equal(slay_cache[i].flags)) { break; } } return(slay_cache[i].value); }
/** * Apply generation magic to an ego-item. */ void ego_apply_magic(int level) { int i, flag, x; Bitflag flags = new Bitflag(Object_Flag.SIZE); Bitflag newf = new Bitflag(Object_Flag.SIZE); object_flags(ref flags); /* Extra powers */ if (ego.xtra == Object_Flag.OBJECT_XTRA_TYPE_SUSTAIN) { Object_Flag.create_mask(newf, false, Object_Flag.object_flag_type.SUST); } else if (ego.xtra == Object_Flag.OBJECT_XTRA_TYPE_RESIST) { Object_Flag.create_mask(newf, false, Object_Flag.object_flag_type.HRES); } else if (ego.xtra == Object_Flag.OBJECT_XTRA_TYPE_POWER) { Object_Flag.create_mask(newf, false, Object_Flag.object_flag_type.PROT, Object_Flag.object_flag_type.MISC); } if (ego.xtra != 0) { this.flags.on(get_new_attr(flags, newf)); } /* Apply extra ego bonuses */ to_h += (short)Random.randcalc(ego.to_h, level, aspect.RANDOMISE); to_d += (short)Random.randcalc(ego.to_d, level, aspect.RANDOMISE); to_a += (short)Random.randcalc(ego.to_a, level, aspect.RANDOMISE); /* Apply pvals */ for (i = 0; i < ego.num_pvals; i++) { flags.copy(ego.pval_flags[i]); x = Random.randcalc(ego.pval[i], level, aspect.RANDOMISE); for (flag = flags.next(Bitflag.FLAG_START); flag != Bitflag.FLAG_null; flag = flags.next(flag + 1)) { add_pval(x, flag); } } /* Apply flags */ this.flags.union(ego.flags); return; }
/* * Obtain the "flags" for the player as if he was an item */ public static void player_flags(ref Bitflag f) { if (f == null) { f = new Bitflag(Object.Object_Flag.SIZE); } /* Add racial flags */ f.copy(instance.Race.flags); /* Some classes become immune to fear at a certain plevel */ if (instance.player_has(Misc.PF.BRAVERY_30.value) && instance.lev >= 30) { f.on(Object.Object_Flag.RES_FEAR.value); } }
public char x_char; /**< Desired object character (set by user/pref file) */ #endregion Fields #region Constructors public Object_Kind() { for(int i = 0; i < Misc.MAX_PVALS; i++) { pval_flags[i] = new Bitflag(Object_Flag.SIZE); } to_h = new random_value(); to_d = new random_value(); to_a = new random_value(); for(int i = 0; i < pval.Length; i++) { pval[i] = new random_value(); } effect = Effect.XXX; time = new random_value(); }
/** * Determine whether an object flag or its timed equivalent are set in the * passed-in flags (which probably come from a state structure). This assumes * that there are no p_ptr.timed effects which can be active yet unknown to * the player. * * \param p player to act upon * \param flag is the object flag for which we are checking. * \param f is the set of flags we're checking */ public bool check_state(Object.Object_Flag flag, Bitflag f) { Object_Flag of_ptr = Object_Flag.list[flag.value]; /* Sanity check */ if (flag == null) { return(false); } if (f.has(flag.value) || (of_ptr.timed != (Timed_Effect)0 && timed[(int)of_ptr.timed] > 0)) { return(true); } return(false); }
/* * Notice a set of flags - returns true if anything new was learned */ bool notice_flags(Bitflag flags) { throw new NotImplementedException(); //if (!of_is_subset(o_ptr.known_flags, flags)) //{ // of_union(o_ptr.known_flags, flags); // /* XXX Eddie don't want infinite recursion if object_check_for_ident sets more flags, // * but maybe this will interfere with savefile repair // */ // object_check_for_ident(o_ptr); // event_signal(EVENT_INVENTORY); // event_signal(EVENT_EQUIPMENT); // return true; //} //return false; }
public Object_Kind() { for (int i = 0; i < Misc.MAX_PVALS; i++) { pval_flags[i] = new Bitflag(Object_Flag.SIZE); } to_h = new random_value(); to_d = new random_value(); to_a = new random_value(); for (int i = 0; i < pval.Length; i++) { pval[i] = new random_value(); } effect = Effect.XXX; time = new random_value(); }
/** * This is a safe way to choose a random new flag to add to an object. * It takes the existing flags and an array of new flags, * and returns an entry from newf, or 0 if there are no * new flags available. */ static int get_new_attr(Bitflag flags, Bitflag newf) { int options = 0, flag = 0; for (int i = newf.next(Bitflag.FLAG_START); i != Bitflag.FLAG_null; i = newf.next(i + 1)) { /* skip this one if the flag is already present */ if (flags.has(i)) { continue; } /* each time we find a new possible option, we have a 1-in-N chance of * choosing it and an (N-1)-in-N chance of keeping a previous one */ if (Random.one_in_(++options)) { flag = i; } } return(flag); }
/** * 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()); }
/** * 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 "mask" of flags of a specific type or ID threshold. * * \param f is the flag array we're filling * \param id is whether we're masking by ID level * \param ... is the list of flags or ID types we're looking for * * N.B. OFT_MAX must be the last item in the ... list */ public static void create_mask(Bitflag f, bool id, params object[] vals) { f.wipe(); /* Process each type in the va_args */ for (int i = 0; i < vals.Length; i++) { int value = (int)vals[i]; foreach (Object_Flag of in list) { if ((id && of.value == value) || (!id && of.type == (object_flag_type)vals[i])) { f.on(of.value); } } /*for (Object_Flag of_ptr = object_flag_table; of_ptr.index < OF_MAX; of_ptr++) * if ((id && of_ptr.id == i) || (!id && of_ptr.type == i)) * of_on(f, of_ptr.index);*/ } return; }
static int obj_desc_pval(Object o_ptr, string buf, int max, int end, bool spoil) { Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); int i; o_ptr.object_flags(ref f); Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.PVAL, Object_Flag.object_flag_type.STAT); if (!f.is_inter(f2)) { return(end); } buf += " <"; //strnfcat(buf, max, &end, " <"); for (i = 0; i < o_ptr.num_pvals; i++) { if (spoil || o_ptr.this_pval_is_visible(i)) { if (i > 0) { buf += ", "; //strnfcat(buf, max, &end, ", "); } buf += o_ptr.pval[i] > 0 ? "+" + o_ptr.pval[i] : o_ptr.pval[i].ToString(); //strnfcat(buf, max, &end, "%+d", o_ptr.pval[i]); } } buf += ">"; end = buf.Length; //f**k it. //strnfcat(buf, max, &end, ">"); return(end); }
/* * Obtain the "flags" for the player as if he was an item */ public static void player_flags(ref Bitflag f) { if(f == null) { f = new Bitflag(Object.Object_Flag.SIZE); } /* Add racial flags */ f.copy(instance.Race.flags); /* Some classes become immune to fear at a certain plevel */ if (instance.player_has(Misc.PF.BRAVERY_30.value) && instance.lev >= 30) f.on(Object.Object_Flag.RES_FEAR.value); }
static int obj_desc_combat(Object o_ptr, ref string buf, int max, int end, bool spoil) { Bitflag flags = new Bitflag(Object_Flag.SIZE); Bitflag flags_known = new Bitflag(Object_Flag.SIZE); o_ptr.object_flags(ref flags); o_ptr.object_flags_known(ref flags_known); if (flags.has(Object_Flag.SHOW_DICE.value)) { /* Only display the real damage dice if the combat stats are known */ if (spoil || o_ptr.attack_plusses_are_visible()) { buf = buf + " (" + o_ptr.dd + "d" + o_ptr.ds + ")"; } else { buf = buf + " (" + o_ptr.kind.dd + "d" + o_ptr.kind.ds + ")"; } } if (flags.has(Object_Flag.SHOW_MULT.value)) { /* Display shooting power as part of the multiplier */ if (flags.has(Object_Flag.MIGHT.value) && (spoil || o_ptr.object_flag_is_known(Object_Flag.MIGHT.value))) { buf = buf + " (x" + (o_ptr.sval % 10) + o_ptr.pval[o_ptr.which_pval(Object_Flag.MIGHT.value)] + ")"; } else { buf = buf + " (x" + o_ptr.sval % 10 + ")"; } } /* Show weapon bonuses */ if (spoil || o_ptr.attack_plusses_are_visible()) { if (flags.has(Object_Flag.SHOW_MODS.value) || o_ptr.to_d != 0 || o_ptr.to_h != 0) { /* Make an exception for body armor with only a to-hit penalty */ if (o_ptr.to_h < 0 && o_ptr.to_d == 0 && (o_ptr.tval == TVal.TV_SOFT_ARMOR || o_ptr.tval == TVal.TV_HARD_ARMOR || o_ptr.tval == TVal.TV_DRAG_ARMOR)) { buf = buf + " (" + (o_ptr.to_h > 0 ? "+" : "-") + o_ptr.to_h + ")"; } /* Otherwise, always use the full tuple */ else { buf = buf + " (" + (o_ptr.to_h > 0 ? "+" : "-") + o_ptr.to_h + "," + (o_ptr.to_d > 0 ? "+" : "-") + o_ptr.to_d + ")"; } } } /* Show armor bonuses */ if (spoil || o_ptr.defence_plusses_are_visible()) { if (obj_desc_show_armor(o_ptr)) { buf = buf + " [" + o_ptr.ac + "," + (o_ptr.to_a > 0?"+":"-") + o_ptr.to_a + "]"; } else if (o_ptr.to_a != 0) { buf = buf + " [" + (o_ptr.to_a > 0?"+":"-") + o_ptr.to_a + "]"; } } else if (obj_desc_show_armor(o_ptr)) { buf = buf + " [" + (o_ptr.was_sensed() ? o_ptr.ac : o_ptr.kind.ac) + "]"; } return(end); }
/* * Process a monster * * In several cases, we directly update the monster lore * * Note that a monster is only allowed to "reproduce" if there * are a limited number of "reproducing" monsters on the current * level. This should prevent the level from being "swamped" by * reproducing monsters. It also allows a large mass of mice to * prevent a louse from multiplying, but this is a small price to * pay for a simple multiplication method. * * XXX Monster fear is slightly odd, in particular, monsters will * fixate on opening a door even if they cannot open it. Actually, * the same thing happens to normal monsters when they hit a door * * In addition, monsters which *cannot* open or bash down a door * will still stand there trying to open it... XXX XXX XXX * * Technically, need to check for monster in the way combined * with that monster being in a wall (or door?) XXX */ public static void process_monster(Cave c, int m_idx) { Monster m_ptr = Cave.cave_monster(Cave.cave, m_idx); Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; Monster_Lore l_ptr = Misc.l_list[m_ptr.r_idx]; int i, oy, ox, ny, nx; int[] mm = new int[5]; bool woke_up = false; bool stagger; bool do_turn; bool do_move; bool do_view; bool did_open_door; bool did_bash_door; /* Handle "sleep" */ if (m_ptr.m_timed[(int)Misc.MON_TMD.SLEEP] != 0) { uint notice; /* Aggravation */ if (Misc.p_ptr.check_state(Object_Flag.AGGRAVATE, Misc.p_ptr.state.flags)) { /* Wake the monster */ mon_clear_timed(m_idx, (int)Misc.MON_TMD.SLEEP, Misc.MON_TMD_FLG_NOTIFY, false); /* Notice the "waking up" */ if (m_ptr.ml && !m_ptr.unaware) { //char m_name[80]; string m_name; /* Get the monster name */ m_name = m_ptr.monster_desc(0); //monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Dump a message */ Utilities.msg("%^s wakes up.", m_name); /* Hack -- Update the health bar */ if (Misc.p_ptr.health_who == m_idx) Misc.p_ptr.redraw |= (Misc.PR_HEALTH); } /* Efficiency XXX XXX */ return; } /* Anti-stealth */ notice = (uint)Random.randint0(1024); /* Hack -- See if monster "notices" player */ if ((notice * notice * notice) <= Misc.p_ptr.state.noise) { int d = 1; /* Wake up faster near the player */ if (m_ptr.cdis < 50) d = (100 / m_ptr.cdis); /* Still asleep */ if (m_ptr.m_timed[(int)Misc.MON_TMD.SLEEP] > d) { /* Monster wakes up "a little bit" */ mon_dec_timed(m_idx, (int)Misc.MON_TMD.SLEEP, d , (ushort)Misc.MON_TMD_FLG_NOMESSAGE, false); /* Notice the "not waking up" */ if (m_ptr.ml && !m_ptr.unaware) { /* Hack -- Count the ignores */ if (l_ptr.ignore < Byte.MaxValue) { l_ptr.ignore++; } } } /* Just woke up */ else { /* Reset sleep counter */ woke_up = mon_clear_timed(m_idx, (int)Misc.MON_TMD.SLEEP, Misc.MON_TMD_FLG_NOMESSAGE, false); /* Notice the "waking up" */ if (m_ptr.ml && !m_ptr.unaware) { //char m_name[80]; string m_name; /* Get the monster name */ m_name = m_ptr.monster_desc(0); /* Dump a message */ //Utilities.msg("%^s wakes up.", m_name); Utilities.msg(m_name + " wakes up."); /* Hack -- Update the health bar */ if (Misc.p_ptr.health_who == m_idx) Misc.p_ptr.redraw |= (Misc.PR_HEALTH); /* Hack -- Count the wakings */ if (l_ptr.wake < byte.MaxValue) { l_ptr.wake++; } } } } /* Still sleeping */ if (m_ptr.m_timed[(int)Misc.MON_TMD.SLEEP] != 0) return; } /* If the monster just woke up, then it doesn't act */ if (woke_up) return; if (m_ptr.m_timed[(int)Misc.MON_TMD.FAST] != 0) mon_dec_timed(m_idx, Misc.MON_TMD.FAST, 1, 0, false); if (m_ptr.m_timed[(int)Misc.MON_TMD.SLOW] != 0) mon_dec_timed(m_idx, Misc.MON_TMD.SLOW, 1, 0, false); if (m_ptr.m_timed[(int)Misc.MON_TMD.STUN] != 0) { throw new NotImplementedException(); //int d = 1; ///* Make a "saving throw" against stun */ //if (randint0(5000) <= r_ptr.level * r_ptr.level) //{ // /* Recover fully */ // d = m_ptr.m_timed[MON_TMD_STUN]; //} ///* Hack -- Recover from stun */ //if (m_ptr.m_timed[MON_TMD_STUN] > d) // mon_dec_timed(m_idx, MON_TMD_STUN, 1, MON_TMD_FLG_NOMESSAGE, false); //else // mon_clear_timed(m_idx, MON_TMD_STUN, MON_TMD_FLG_NOTIFY, false); ///* Still stunned */ //if (m_ptr.m_timed[MON_TMD_STUN]) return; } if (m_ptr.m_timed[(int)Misc.MON_TMD.CONF] != 0) { throw new NotImplementedException(); //int d = randint1(r_ptr.level / 10 + 1); ///* Still confused */ //if (m_ptr.m_timed[MON_TMD_CONF] > d) // mon_dec_timed(m_idx, MON_TMD_CONF, d , MON_TMD_FLG_NOMESSAGE, // false); //else // mon_clear_timed(m_idx, MON_TMD_CONF, MON_TMD_FLG_NOTIFY, false); } if (m_ptr.m_timed[(int)Misc.MON_TMD.FEAR] != 0) { /* Amount of "boldness" */ int d = Random.randint1(r_ptr.level / 10 + 1); if (m_ptr.m_timed[(int)Misc.MON_TMD.FEAR] > d) mon_dec_timed(m_idx, Misc.MON_TMD.FEAR, d, Misc.MON_TMD_FLG_NOMESSAGE, false); else mon_clear_timed(m_idx, Misc.MON_TMD.FEAR, Misc.MON_TMD_FLG_NOTIFY, false); } /* Get the origin */ oy = m_ptr.fy; ox = m_ptr.fx; /* Attempt to "mutiply" (all monsters are allowed an attempt for lore * purposes, even non-breeders) */ if (Misc.num_repro < Misc.MAX_REPRO) { int k, y, x; /* Count the adjacent monsters */ for (k = 0, y = oy - 1; y <= oy + 1; y++) { for (x = ox - 1; x <= ox + 1; x++) { /* Count monsters */ if (Cave.cave.m_idx[y][x] > 0) k++; } } /* Multiply slower in crowded areas */ if ((k < 4) && (k == 0 || Random.one_in_(k * Misc.MON_MULT_ADJ))) { /* Successful breeding attempt, learn about that now */ if (m_ptr.ml) l_ptr.flags.on(Monster_Flag.MULTIPLY.value); /* Try to multiply (only breeders allowed) */ if (r_ptr.flags.has(Monster_Flag.MULTIPLY.value) && multiply_monster(m_idx)) { /* Make a sound */ if (m_ptr.ml) { //sound(MSG_MULTIPLY); //TODO: enable sound } /* Multiplying takes energy */ return; } } } /* Mimics lie in wait */ if (is_mimicking(m_idx)) return; /* Attempt to cast a spell */ if (make_attack_spell(m_idx)) return; /* Reset */ stagger = false; /* Confused */ if (m_ptr.m_timed[(int)Misc.MON_TMD.CONF] != 0) { /* Stagger */ stagger = true; } /* Random movement - always attempt for lore purposes */ else { int roll = Random.randint0(100); /* Random movement (25%) */ if (roll < 25) { /* Learn about small random movement */ if (m_ptr.ml) l_ptr.flags.on(Monster_Flag.RAND_25.value); /* Stagger */ if (r_ptr.flags.test(Monster_Flag.RAND_25.value, Monster_Flag.RAND_50.value)) stagger = true; } /* Random movement (50%) */ else if (roll < 50) { /* Learn about medium random movement */ if (m_ptr.ml) l_ptr.flags.on(Monster_Flag.RAND_50.value); /* Stagger */ if (r_ptr.flags.has(Monster_Flag.RAND_50.value)) stagger = true; } /* Random movement (75%) */ else if (roll < 75) { /* Stagger */ if (r_ptr.flags.test_all(Monster_Flag.RAND_25.value, Monster_Flag.RAND_50.value)) { stagger = true; } } } /* Normal movement */ if (!stagger) { /* Logical moves, may do nothing */ if (!get_moves(Cave.cave, m_idx, mm)) return; } /* Assume nothing */ do_turn = false; do_move = false; do_view = false; /* Assume nothing */ did_open_door = false; did_bash_door = false; /* Process moves */ for (i = 0; i < 5; i++) { /* Get the direction (or stagger) */ int d = (stagger ? Misc.ddd[Random.randint0(8)] : mm[i]); /* Get the destination */ ny = oy + Misc.ddy[d]; nx = ox + Misc.ddx[d]; /* Floor is open? */ if (Cave.cave_floor_bold(ny, nx)) { /* Go ahead and move */ do_move = true; } /* Permanent wall in the way */ else if (Cave.cave.feat[ny][nx] >= Cave.FEAT_PERM_EXTRA) { /* Nothing */ } /* Normal wall, door, or secret door in the way */ else { /* There's some kind of feature in the way, so learn about * kill-wall and pass-wall now */ if (m_ptr.ml) { l_ptr.flags.on(Monster_Flag.PASS_WALL.value); l_ptr.flags.on(Monster_Flag.KILL_WALL.value); } /* Monster moves through walls (and doors) */ if (r_ptr.flags.has(Monster_Flag.PASS_WALL.value)) { /* Pass through walls/doors/rubble */ do_move = true; } /* Monster destroys walls (and doors) */ else if (r_ptr.flags.has(Monster_Flag.KILL_WALL.value)) { /* Eat through walls/doors/rubble */ do_move = true; /* Forget the wall */ Cave.cave.info[ny][nx] &= ~(Cave.CAVE_MARK); /* Notice */ Cave.cave_set_feat(c, ny, nx, Cave.FEAT_FLOOR); /* Note changes to viewable region */ if (Cave.player_has_los_bold(ny, nx)) do_view = true; } /* Handle doors and secret doors */ else if (((Cave.cave.feat[ny][nx] >= Cave.FEAT_DOOR_HEAD) && (Cave.cave.feat[ny][nx] <= Cave.FEAT_DOOR_TAIL)) || (Cave.cave.feat[ny][nx] == Cave.FEAT_SECRET)) { bool may_bash = true; /* Take a turn */ do_turn = true; /* Learn about door abilities */ if (m_ptr.ml) { l_ptr.flags.on(Monster_Flag.OPEN_DOOR.value); l_ptr.flags.on(Monster_Flag.BASH_DOOR.value); } /* Creature can open doors. */ if (r_ptr.flags.has(Monster_Flag.OPEN_DOOR.value)) { /* Closed doors and secret doors */ if ((Cave.cave.feat[ny][nx] == Cave.FEAT_DOOR_HEAD) || (Cave.cave.feat[ny][nx] == Cave.FEAT_SECRET)) { /* The door is open */ did_open_door = true; /* Do not bash the door */ may_bash = false; } /* Locked doors (not jammed) */ else if (Cave.cave.feat[ny][nx] < Cave.FEAT_DOOR_HEAD + 0x08) { int k; /* Door power */ k = ((Cave.cave.feat[ny][nx] - Cave.FEAT_DOOR_HEAD) & 0x07); /* Try to unlock it */ if (Random.randint0(m_ptr.hp / 10) > k) { Utilities.msg("Something fiddles with a lock."); /* Reduce the power of the door by one */ Cave.cave_set_feat(c, ny, nx, Cave.cave.feat[ny][nx] - 1); /* Do not bash the door */ may_bash = false; } } } /* Stuck doors -- attempt to bash them down if allowed */ if (may_bash && r_ptr.flags.has(Monster_Flag.BASH_DOOR.value)) { int k; /* Door power */ k = ((Cave.cave.feat[ny][nx] - Cave.FEAT_DOOR_HEAD) & 0x07); /* Attempt to bash */ if (Random.randint0(m_ptr.hp / 10) > k) { Utilities.msg("Something slams against a door."); /* Reduce the power of the door by one */ Cave.cave_set_feat(c, ny, nx, Cave.cave.feat[ny][nx] - 1); /* If the door is no longer jammed */ if (Cave.cave.feat[ny][nx] < Cave.FEAT_DOOR_HEAD + 0x09) { Utilities.msg("You hear a door burst open!"); /* Disturb (sometimes) */ Cave.disturb(Misc.p_ptr, 0, 0); /* The door was bashed open */ did_bash_door = true; /* Hack -- fall into doorway */ do_move = true; } } } } /* Deal with doors in the way */ if (did_open_door || did_bash_door) { /* Break down the door */ if (did_bash_door && (Random.randint0(100) < 50)) { Cave.cave_set_feat(c, ny, nx, Cave.FEAT_BROKEN); } /* Open the door */ else { Cave.cave_set_feat(c, ny, nx, Cave.FEAT_OPEN); } /* Handle viewable doors */ if (Cave.player_has_los_bold(ny, nx)) do_view = true; } } /* Hack -- check for Glyph of Warding */ if (do_move && (Cave.cave.feat[ny][nx] == Cave.FEAT_GLYPH)) { /* Assume no move allowed */ do_move = false; /* Break the ward */ if (Random.randint1(Misc.BREAK_GLYPH) < r_ptr.level) { /* Describe observable breakage */ if ((Cave.cave.info[ny][nx] & (Cave.CAVE_MARK)) != 0) { Utilities.msg("The rune of protection is broken!"); } /* Forget the rune */ Cave.cave.info[ny][nx] &= ~Cave.CAVE_MARK; /* Break the rune */ Cave.cave_set_feat(c, ny, nx, Cave.FEAT_FLOOR); /* Allow movement */ do_move = true; } } /* The player is in the way. */ if (do_move && (Cave.cave.m_idx[ny][nx] < 0)) { /* Learn about if the monster attacks */ if (m_ptr.ml) l_ptr.flags.on(Monster_Flag.NEVER_BLOW.value); /* Some monsters never attack */ if (r_ptr.flags.has(Monster_Flag.NEVER_BLOW.value)) { /* Do not move */ do_move = false; } /* Otherwise, attack the player */ else { /* Do the attack */ m_ptr.make_attack_normal(Misc.p_ptr); /* Do not move */ do_move = false; /* Took a turn */ do_turn = true; } } /* Some monsters never move */ if (do_move && r_ptr.flags.has(Monster_Flag.NEVER_MOVE.value)) { /* Learn about lack of movement */ if (m_ptr.ml) l_ptr.flags.on(Monster_Flag.NEVER_MOVE.value); /* Do not move */ do_move = false; } /* A monster is in the way */ if (do_move && (Cave.cave.m_idx[ny][nx] > 0)) { Monster n_ptr = Cave.cave_monster(Cave.cave, Cave.cave.m_idx[ny][nx]); /* Kill weaker monsters */ bool kill_ok = r_ptr.flags.has(Monster_Flag.KILL_BODY.value); /* Move weaker monsters if they can swap places */ /* (not in a wall) */ bool move_ok = (r_ptr.flags.has(Monster_Flag.MOVE_BODY.value) && Cave.cave_floor_bold(m_ptr.fy, m_ptr.fx)); /* Assume no movement */ do_move = false; if (compare_monsters(m_ptr, n_ptr) > 0) { /* Learn about pushing and shoving */ if (m_ptr.ml) { l_ptr.flags.on(Monster_Flag.KILL_BODY.value); l_ptr.flags.on(Monster_Flag.MOVE_BODY.value); } if (kill_ok || move_ok) { /* Get the names of the monsters involved */ //char m_name[80]; //char n_name[80]; string m_name; string n_name; m_name = m_ptr.monster_desc(Desc.IND1); n_name = n_ptr.monster_desc(Desc.IND1); /* Allow movement */ do_move = true; /* Monster ate another monster */ if (kill_ok) { /* Note if visible */ if (m_ptr.ml && (m_ptr.mflag & (Monster_Flag.MFLAG_VIEW)) != 0) { string name = Char.ToUpper(m_name[0]) + m_name.Substring(1); Utilities.msg("{0} tramples over {1}.", name, n_name); } throw new NotImplementedException(); //delete_monster(ny, nx); } else { /* Note if visible */ if (m_ptr.ml && (m_ptr.mflag & (Monster_Flag.MFLAG_VIEW)) != 0) { string name = Char.ToUpper(m_name[0]) + m_name.Substring(1); Utilities.msg("{0} pushes past {1}.", name, n_name); } } } } } /* Creature has been allowed move */ if (do_move) { short this_o_idx, next_o_idx = 0; /* Learn about no lack of movement */ if (m_ptr.ml) l_ptr.flags.on(Monster_Flag.NEVER_MOVE.value); /* Take a turn */ do_turn = true; /* Move the monster */ monster_swap(oy, ox, ny, nx); /* Possible disturb */ if (m_ptr.ml && (Option.disturb_move.value || (((m_ptr.mflag & (Monster_Flag.MFLAG_VIEW)) != 0) && Option.disturb_near.value))) { /* Disturb */ Cave.disturb(Misc.p_ptr, 0, 0); } /* Scan all objects in the grid */ for (this_o_idx = Cave.cave.o_idx[ny][nx]; this_o_idx != 0; this_o_idx = next_o_idx) { Object.Object o_ptr; /* Get the object */ o_ptr = Object.Object.byid(this_o_idx); if(o_ptr == null) continue; /* Get the next object */ next_o_idx = o_ptr.next_o_idx; /* Skip gold */ if (o_ptr.tval == TVal.TV_GOLD) continue; /* Learn about item pickup behavior */ if (m_ptr.ml) { l_ptr.flags.on(Monster_Flag.TAKE_ITEM.value); l_ptr.flags.on(Monster_Flag.KILL_ITEM.value); } /* Take or Kill objects on the floor */ if (r_ptr.flags.has(Monster_Flag.TAKE_ITEM.value) || r_ptr.flags.has(Monster_Flag.KILL_ITEM.value)) { Bitflag obj_flags = new Bitflag(Object_Flag.SIZE); Bitflag mon_flags = new Bitflag(Monster_Flag.SIZE); //char m_name[80]; //char o_name[80]; string m_name; string o_name = ""; mon_flags.wipe(); /* Extract some flags */ o_ptr.object_flags(ref obj_flags); /* Get the object name */ o_name = o_ptr.object_desc(Object.Object.Detail.PREFIX | Object.Object.Detail.FULL); /* Get the monster name */ m_name = m_ptr.monster_desc(Desc.IND1); /* React to objects that hurt the monster */ throw new NotImplementedException(); //react_to_slay(obj_flags, mon_flags); ///* The object cannot be picked up by the monster */ //if (o_ptr.artifact || rf_is_inter(r_ptr.flags, mon_flags)) //{ // /* Only give a message for "take_item" */ // if (rf_has(r_ptr.flags, RF_TAKE_ITEM)) // { // /* Describe observable situations */ // if (m_ptr.ml && Cave.player_has_los_bold(ny, nx) && !squelch_item_ok(o_ptr)) // { // /* Dump a message */ // msg("%^s tries to pick up %s, but fails.", // m_name, o_name); // } // } //} ///* Pick up the item */ //else if (rf_has(r_ptr.flags, RF_TAKE_ITEM)) //{ // Object.Object i_ptr; // //object_type object_type_body; // /* Describe observable situations */ // if (player_has_los_bold(ny, nx) && !squelch_item_ok(o_ptr)) // { // /* Dump a message */ // msg("%^s picks up %s.", m_name, o_name); // } // /* Get local object */ // i_ptr = &object_type_body; // /* Obtain local object */ // object_copy(i_ptr, o_ptr); // /* Delete the object */ // delete_object_idx(this_o_idx); // /* Carry the object */ // monster_carry(m_ptr, i_ptr); //} ///* Destroy the item */ //else //{ // /* Describe observable situations */ // if (player_has_los_bold(ny, nx) && !squelch_item_ok(o_ptr)) // { // /* Dump a message */ // msgt(MSG_DESTROY, "%^s crushes %s.", m_name, o_name); // } // /* Delete the object */ // delete_object_idx(this_o_idx); //} } } } /* Stop when done */ if (do_turn) break; } /* If we haven't done anything, try casting a spell again */ if (Option.birth_ai_smart.value && !do_turn && !do_move) { /* Cast spell */ if (make_attack_spell(m_idx)) return; } if (r_ptr.flags.has(Monster_Flag.HAS_LIGHT.value)) do_view = true; /* Notice changes in view */ if (do_view) { /* Update the visuals */ Misc.p_ptr.update |= (Misc.PU_UPDATE_VIEW | Misc.PU_MONSTERS); /* Fully update the flow XXX XXX XXX */ Misc.p_ptr.update |= (Misc.PU_FORGET_FLOW | Misc.PU_UPDATE_FLOW); } /* Hack -- get "bold" if out of options */ if (!do_turn && !do_move && m_ptr.m_timed[(int)Misc.MON_TMD.FEAR] != 0) { mon_clear_timed(m_idx, Misc.MON_TMD.FEAR, Misc.MON_TMD_FLG_NOTIFY, false); } /* If we see an unaware monster do something, become aware of it */ if(do_turn && m_ptr.unaware) { throw new NotImplementedException(); //become_aware(m_idx); } }
/** * Log the names of a flagset to a file. * * \param f is the set of flags we are logging. * \param log_file is the file to which we are logging the names. */ //log_file was type ang_file... I don't think we need that anymore... public static void log_flags(Bitflag f, FileStream log_file) { throw new NotImplementedException(); //int i; //file_putf(log_file, "Object flags are:\n"); //for (i = 0; i < OF_MAX; i++) // if (of_has(f, i)) // file_putf(log_file, "%s\n", flag_names[i]); }
/** * Create a "mask" of flags of a specific type or ID threshold. * * \param f is the flag array we're filling * \param id is whether we're masking by ID level * \param ... is the list of flags or ID types we're looking for * * N.B. OFT_MAX must be the last item in the ... list */ public static void create_mask(Bitflag f, bool id, params object[] vals) { f.wipe(); /* Process each type in the va_args */ for (int i = 0; i < vals.Length; i++) { int value = (int)vals[i]; foreach(Object_Flag of in list) { if ((id && of.value == value) || (!id && of.type == (object_flag_type)vals[i])) f.on(of.value); } /*for (Object_Flag of_ptr = object_flag_table; of_ptr.index < OF_MAX; of_ptr++) if ((id && of_ptr.id == i) || (!id && of_ptr.type == i)) of_on(f, of_ptr.index);*/ } return; }
/* * Calculate maximum mana. You do not need to know any spells. * Note that mana is lowered by heavy (or inappropriate) armor. * * This function induces status messages. */ static void calc_mana() { int msp, levels, cur_wgt, max_wgt; Object.Object o_ptr; bool old_cumber_glove = instance.cumber_glove; bool old_cumber_armor = instance.cumber_armor; /* Hack -- Must be literate */ if (instance.Class.spell_book == 0) { instance.msp = 0; instance.csp = 0; instance.csp_frac = 0; return; } /* Extract "effective" player level */ levels = (instance.lev - instance.Class.spell_first) + 1; if (levels > 0) { msp = 1; msp += (short)(adj_mag_mana[instance.state.stat_ind[instance.Class.spell_stat]] * levels / 100); } else { levels = 0; msp = 0; } /* Process gloves for those disturbed by them */ if (instance.player_has(Misc.PF.CUMBER_GLOVE.value)) { Bitflag f = new Bitflag(Object_Flag.SIZE); /* Assume player is not encumbered by gloves */ instance.cumber_glove = false; /* Get the gloves */ o_ptr = instance.inventory[Misc.INVEN_HANDS]; /* Examine the gloves */ o_ptr.object_flags(ref f); /* Normal gloves hurt mage-type spells */ if (o_ptr.kind != null && !f.has(Object_Flag.FREE_ACT.value) && !f.has(Object_Flag.SPELLS_OK.value) && !(f.has(Object_Flag.DEX.value) && (o_ptr.pval[o_ptr.which_pval(Object_Flag.DEX.value)] > 0))) { /* Encumbered */ instance.cumber_glove = true; /* Reduce mana */ msp = (3 * msp) / 4; } } /* Assume player not encumbered by armor */ instance.cumber_armor = false; /* Weigh the armor */ cur_wgt = 0; cur_wgt += instance.inventory[Misc.INVEN_BODY].weight; cur_wgt += instance.inventory[Misc.INVEN_HEAD].weight; cur_wgt += instance.inventory[Misc.INVEN_ARM].weight; cur_wgt += instance.inventory[Misc.INVEN_OUTER].weight; cur_wgt += instance.inventory[Misc.INVEN_HANDS].weight; cur_wgt += instance.inventory[Misc.INVEN_FEET].weight; /* Determine the weight allowance */ max_wgt = instance.Class.spell_weight; /* Heavy armor penalizes mana */ if (((cur_wgt - max_wgt) / 10) > 0) { /* Encumbered */ instance.cumber_armor = true; /* Reduce mana */ msp -= ((cur_wgt - max_wgt) / 10); } /* Mana can never be negative */ if (msp < 0) msp = 0; /* Maximum mana has changed */ if (msp != instance.msp) { /* Save new limit */ instance.msp = (short)msp; /* Enforce new limit */ if (instance.csp >= msp) { instance.csp = (short)msp; instance.csp_frac = 0; } /* Display mana later */ instance.redraw |= (Misc.PR_MANA); } /* Hack -- handle "xtra" mode */ if (Misc.character_xtra != 0) return; /* Take note when "glove state" changes */ if (old_cumber_glove != instance.cumber_glove) { /* Message */ if (instance.cumber_glove) { Utilities.msg("Your covered hands feel unsuitable for spellcasting."); } else { Utilities.msg("Your hands feel more suitable for spellcasting."); } } /* Take note when "armor state" changes */ if (old_cumber_armor != instance.cumber_armor) { /* Message */ if (instance.cumber_armor) { Utilities.msg("The weight of your armor encumbers your movement."); } else { Utilities.msg("You feel able to move more freely."); } } }
/* * Notice a set of flags - returns true if anything new was learned */ bool notice_flags(Bitflag flags) { throw new NotImplementedException(); //if (!of_is_subset(o_ptr.known_flags, flags)) //{ // of_union(o_ptr.known_flags, flags); // /* XXX Eddie don't want infinite recursion if object_check_for_ident sets more flags, // * but maybe this will interfere with savefile repair // */ // object_check_for_ident(o_ptr); // event_signal(EVENT_INVENTORY); // event_signal(EVENT_EQUIPMENT); // return true; //} //return false; }
/* * 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; }
/** * Wipe an object clean and make it a standard object of the specified kind. * Was previous "object_prep", is now a constructor for Object */ public void prep(Object_Kind k, int lev, aspect rand_aspect) { int flag, x; Bitflag flags = new Bitflag(Object_Flag.SIZE); // Assign the kind and copy across data this.kind = k; this.tval = k.tval; this.sval = k.sval; this.ac = k.ac; this.dd = k.dd; this.ds = k.ds; this.weight = k.weight; // Default number this.number = 1; for(int i = 0; i < pval_flags.Length; i++) { pval_flags[i] = new Bitflag(Object_Flag.SIZE); } // Apply pvals and then copy flags for (int i = 0; i < k.num_pvals; i++) { flags.copy(k.pval_flags[i]); flags.copy(k.pval_flags[i]); x = Random.randcalc(k.pval[i], lev, rand_aspect); for (flag = flags.next(Bitflag.FLAG_START); flag != Bitflag.FLAG_null; flag = flags.next(flag + 1)) add_pval(x, flag); } if(k.Base != null) { flags.copy(k.Base.flags); } flags.union(k.flags); // Assign charges (wands/staves only) if (tval == TVal.TV_WAND || tval == TVal.TV_STAFF) pval[Misc.DEFAULT_PVAL] = (short)Random.randcalc(k.charge, lev, rand_aspect); // Assign flagless pval for food or oil if (tval == TVal.TV_FOOD || tval == TVal.TV_POTION || tval == TVal.TV_FLASK) pval[Misc.DEFAULT_PVAL] = (short)Random.randcalc(k.pval[Misc.DEFAULT_PVAL], lev, rand_aspect); // Default fuel for lamps if (tval == TVal.TV_LIGHT) { if(sval == SVal.SV_LIGHT_TORCH) timeout = Misc.DEFAULT_TORCH; else if(sval == SVal.SV_LIGHT_LANTERN) timeout = Misc.DEFAULT_LAMP; } // Default magic to_h = (short)Random.randcalc(k.to_h, lev, rand_aspect); to_d = (short)Random.randcalc(k.to_d, lev, rand_aspect); to_a = (short)Random.randcalc(k.to_a, lev, rand_aspect); }
/** * Return the pval_flags for an item */ public void object_pval_flags(out Bitflag[] flags) { flags = new Bitflag[Misc.MAX_PVALS]; if (this.kind == null) return; for (int i = 0; i < Misc.MAX_PVALS; i++) { flags[i] = new Bitflag(Object_Flag.SIZE); flags[i].copy(pval_flags[i]); } }
/* * 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); }
static int obj_desc_pval(Object o_ptr, string buf, int max, int end, bool spoil) { Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); int i; o_ptr.object_flags(ref f); Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.PVAL, Object_Flag.object_flag_type.STAT); if (!f.is_inter(f2)) return end; buf += " <"; //strnfcat(buf, max, &end, " <"); for (i = 0; i < o_ptr.num_pvals; i++) { if (spoil || o_ptr.this_pval_is_visible(i)) { if(i > 0) { buf += ", "; //strnfcat(buf, max, &end, ", "); } buf += o_ptr.pval[i] > 0 ? "+" + o_ptr.pval[i] : o_ptr.pval[i].ToString(); //strnfcat(buf, max, &end, "%+d", o_ptr.pval[i]); } } buf += ">"; end = buf.Length; //f**k it. //strnfcat(buf, max, &end, ">"); return end; }
/* * Have a monster choose a spell to cast. * * Note that the monster's spell list has already had "useless" spells * (bolts that won't hit the player, summons without room, etc.) removed. * Perhaps that should be done by this function. * * Stupid monsters will just pick a spell randomly. Smart monsters * will choose more "intelligently". * * This function could be an efficiency bottleneck. */ static int choose_attack_spell(int m_idx, Bitflag f) { throw new NotImplementedException(); //monster_type *m_ptr = cave_monster(cave, m_idx); //monster_race *r_ptr = &r_info[m_ptr.r_idx]; //int num = 0; //byte spells[RSF_MAX]; //int i, py = p_ptr.py, px = p_ptr.px; //bool has_escape, has_attack, has_summon, has_tactic; //bool has_annoy, has_haste, has_heal; ///* Smart monsters restrict their spell choices. */ //if (OPT(birth_ai_smart) && !rf_has(r_ptr.flags, RF_STUPID)) //{ // /* What have we got? */ // has_escape = test_spells(f, RST_ESCAPE); // has_attack = test_spells(f, RST_ATTACK | RST_BOLT | RST_BALL | RST_BREATH); // has_summon = test_spells(f, RST_SUMMON); // has_tactic = test_spells(f, RST_TACTIC); // has_annoy = test_spells(f, RST_ANNOY); // has_haste = test_spells(f, RST_HASTE); // has_heal = test_spells(f, RST_HEAL); // /*** Try to pick an appropriate spell type ***/ // /* Hurt badly or afraid, attempt to flee */ // if (has_escape && ((m_ptr.hp < m_ptr.maxhp / 4) || m_ptr.m_timed[MON_TMD_FEAR])) // { // /* Choose escape spell */ // set_spells(f, RST_ESCAPE); // } // /* Still hurt badly, couldn't flee, attempt to heal */ // else if (has_heal && m_ptr.hp < m_ptr.maxhp / 4) // { // /* Choose heal spell */ // set_spells(f, RST_HEAL); // } // /* Player is close and we have attack spells, blink away */ // else if (has_tactic && (distance(py, px, m_ptr.fy, m_ptr.fx) < 4) && // has_attack && (randint0(100) < 75)) // { // /* Choose tactical spell */ // set_spells(f, RST_TACTIC); // } // /* We're hurt (not badly), try to heal */ // else if (has_heal && (m_ptr.hp < m_ptr.maxhp * 3 / 4) && // (randint0(100) < 60)) // { // /* Choose heal spell */ // set_spells(f, RST_HEAL); // } // /* Summon if possible (sometimes) */ // else if (has_summon && (randint0(100) < 50)) // { // /* Choose summon spell */ // set_spells(f, RST_SUMMON); // } // /* Attack spell (most of the time) */ // else if (has_attack && (randint0(100) < 85)) // { // /* Choose attack spell */ // set_spells(f, RST_ATTACK | RST_BOLT | RST_BALL | RST_BREATH); // } // /* Try another tactical spell (sometimes) */ // else if (has_tactic && (randint0(100) < 50)) // { // /* Choose tactic spell */ // set_spells(f, RST_TACTIC); // } // /* Haste self if we aren't already somewhat hasted (rarely) */ // else if (has_haste && (randint0(100) < (20 + r_ptr.speed - m_ptr.mspeed))) // { // /* Choose haste spell */ // set_spells(f, RST_HASTE); // } // /* Annoy player (most of the time) */ // else if (has_annoy && (randint0(100) < 85)) // { // /* Choose annoyance spell */ // set_spells(f, RST_ANNOY); // } // /* Else choose no spell */ // else // { // rsf_wipe(f); // } // /* Anything left? */ // if (rsf_is_empty(f)) return (FLAG_END); //} ///* Extract all spells: "innate", "normal", "bizarre" */ //for (i = FLAG_START, num = 0; i < RSF_MAX; i++) //{ // if (rsf_has(f, i)) spells[num++] = i; //} ///* Paranoia */ //if (num == 0) return 0; ///* Pick at random */ //return (spells[randint0(num)]); }
/* * 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 check_for_ident() { Bitflag flags = new Bitflag(Object_Flag.SIZE); Bitflag known_flags = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); object_flags(ref flags); object_flags_known(ref known_flags); /* Some flags are irrelevant or never learned or too hard to learn */ Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.INT, Object_Flag.object_flag_type.IGNORE, Object_Flag.object_flag_type.HATES); flags.diff(f2); known_flags.diff(f2); if (!flags.is_equal(known_flags)) return false; /* If we know attack bonuses, and defence bonuses, and effect, then * we effectively know everything, so mark as such */ if ((attack_plusses_are_visible() || (was_sensed() && to_h == 0 && to_d == 0)) && (defence_plusses_are_visible() || (was_sensed() && to_a == 0)) && (effect_is_known() || effect() == null)) { /* In addition to knowing the pval flags, it is necessary to know the pvals to know everything */ int i; for (i = 0; i < num_pvals; i++) if (!this_pval_is_visible(i)) break; if (i == num_pvals) { notice_everything(); return true; } } /* We still know all the flags, so we still know if it's an ego */ if (ego != null) { /* require worn status so you don't learn launcher of accuracy or gloves of slaying before wield */ if (was_worn()) notice_ego(); } return false; }
/** * Obtain the pval_flags for an item which are known to the player */ public void pval_flags_known(out Bitflag[] flags) { int i, flag; object_pval_flags(out flags); for(i = 0; i < Misc.MAX_PVALS; i++) { flags[i].inter(known_flags); } /* Kind and ego pval_flags may have shifted pvals so we iterate */ if(flavor_is_aware()) { for(i = 0; i < Misc.MAX_PVALS; i++) { for(flag = kind.pval_flags[i].next(Bitflag.FLAG_START); flag != Bitflag.FLAG_null; flag = kind.pval_flags[i].next(flag + 1)) { flags[which_pval(flag)].on(flag); } } } if(ego != null && easy_know()) { for(i = 0; i < Misc.MAX_PVALS; i++) { for(flag = ego.pval_flags[i].next(Bitflag.FLAG_START); flag != Bitflag.FLAG_null; flag = ego.pval_flags[i].next(flag + 1)) { flags[which_pval(flag)].on(flag); } } } }
/** * 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(); }
/** * \returns whether a specific pval is known to the player */ public bool this_pval_is_visible(int pval) { Bitflag[] f = new Bitflag[Misc.MAX_PVALS]; //for (int i = 0; i < f.Length; i++){ //We use f for an outtype, no need to initialize // f[i] = new Bitflag(Object_Flag.SIZE); //} Bitflag f2 = new Bitflag(Object_Flag.SIZE); Misc.assert(kind != null); if ((ident & IDENT_STORE) != 0) return true; /* Aware jewelry with non-variable pval */ if (is_jewelry() && flavor_is_aware()) { if (!Random.randcalc_varies(kind.pval[pval])) return true; } if (was_worn()) { pval_flags_known(out f); /* Create the mask for pval-related flags */ Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.STAT, Object_Flag.object_flag_type.PVAL); if (f[pval].is_inter(f2)) return true; } return false; }
/* * Calculate and set the current light radius. * * The brightest wielded object counts as the light source; radii do not add * up anymore. * * Note that a cursed light source no longer emits light. */ void calc_torch() { int i; short old_light = cur_light; bool burn_light = true; short new_light = 0; int extra_light = 0; /* Ascertain lightness if in the town */ if (depth == 0 && ((Misc.turn % (10L * Cave.TOWN_DAWN)) < ((10L * Cave.TOWN_DAWN) / 2))) burn_light = false; /* Examine all wielded objects, use the brightest */ for (i = Misc.INVEN_WIELD; i < Misc.INVEN_TOTAL; i++) { Bitflag f = new Bitflag(Object_Flag.SIZE); int amt = 0; Object.Object o_ptr = inventory[i]; /* Skip empty slots */ if (o_ptr.kind == null) continue; /* Extract the flags */ o_ptr.object_flags(ref f); /* Cursed objects emit no light */ if (f.has(Object_Flag.LIGHT_CURSE.value)) amt = 0; /* Examine actual lights */ else if (o_ptr.tval == TVal.TV_LIGHT) { int flag_inc = f.has(Object_Flag.LIGHT.value) ? 1 : 0; /* Artifact lights provide permanent bright light */ if (o_ptr.artifact != null) amt = 3 + flag_inc; /* Non-artifact lights and those without fuel provide no light */ else if (!burn_light || o_ptr.timeout == 0) amt = 0; /* All lit lights provide at least radius 2 light */ else { amt = 2 + flag_inc; /* Torches below half fuel provide less light */ if (o_ptr.sval == SVal.SV_LIGHT_TORCH && o_ptr.timeout < (Misc.FUEL_TORCH / 4)) //Nick: This looks like 1/4th... amt--; } } else { /* LIGHT flag on an non-cursed non-lights always increases radius */ if (f.has(Object_Flag.LIGHT.value)) extra_light++; } /* Alter cur_light if reasonable */ if (new_light < amt) new_light = (short)amt; } /* Add bonus from LIGHT flags */ new_light += (short)extra_light; /* Limit light */ new_light = (short)Math.Min((int)new_light, 5); new_light = (short)Math.Max((int)new_light, 0); /* Notice changes in the "light radius" */ if (old_light != new_light) { /* Update the visuals */ cur_light = new_light; update |= (Misc.PU_UPDATE_VIEW | Misc.PU_MONSTERS); } }
/** * 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 */ } }
/* * Calculate the players current "state", taking into account * not only race/class intrinsics, but also objects being worn * and temporary spell effects. * * See also calc_mana() and calc_hitpoints(). * * Take note of the new "speed code", in particular, a very strong * player will start slowing down as soon as he reaches 150 pounds, * but not until he reaches 450 pounds will he be half as fast as * a normal kobold. This both hurts and helps the player, hurts * because in the old days a player could just avoid 300 pounds, * and helps because now carrying 300 pounds is not very painful. * * The "weapon" and "bow" do *not* add to the bonuses to hit or to * damage, since that would affect non-combat things. These values * are actually added in later, at the appropriate place. * * If id_only is true, calc_bonuses() will only use the known * information of objects; thus it returns what the player _knows_ * the character state to be. */ void calc_bonuses(Object.Object[] inventory, ref Player_State state, bool id_only) { Player p_ptr = Player.instance; int i, j, hold; int extra_blows = 0; int extra_shots = 0; int extra_might = 0; Object.Object o_ptr; Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag collect_f = new Bitflag(Object_Flag.SIZE); /*** Reset ***/ state = new Player_State(); //memset(state, 0, sizeof *state); /* Set various defaults */ state.speed = 110; state.num_blows = 100; /*** Extract race/class info ***/ /* Base infravision (purely racial) */ if(p_ptr.Race == null) return; state.see_infra = p_ptr.Race.infra; /* Base skills */ for (i = 0; i < (int)Skill.MAX; i++) state.skills[i] = (short)(p_ptr.Race.r_skills[i] + p_ptr.Class.c_skills[i]); /*** Analyze player ***/ /* Extract the player flags */ Player.player_flags(ref collect_f); /*** Analyze equipment ***/ /* Scan the equipment */ for (i = Misc.INVEN_WIELD; i < Misc.INVEN_TOTAL; i++) { o_ptr = inventory[i]; /* Skip non-objects */ if (o_ptr == null || o_ptr.kind == null) continue; /* Extract the item flags */ if (id_only) o_ptr.object_flags_known(ref f); else o_ptr.object_flags(ref f); collect_f.union(f); /* Affect stats */ if (f.has(Object_Flag.STR.value)) state.stat_add[(int)Stat.Str] += o_ptr.pval[o_ptr.which_pval(Object_Flag.STR.value)]; if (f.has(Object_Flag.INT.value)) state.stat_add[(int)Stat.Int] += o_ptr.pval[o_ptr.which_pval(Object_Flag.INT.value)]; if (f.has(Object_Flag.WIS.value)) state.stat_add[(int)Stat.Wis] += o_ptr.pval[o_ptr.which_pval(Object_Flag.WIS.value)]; if (f.has(Object_Flag.DEX.value)) state.stat_add[(int)Stat.Dex] += o_ptr.pval[o_ptr.which_pval(Object_Flag.DEX.value)]; if (f.has(Object_Flag.CON.value)) state.stat_add[(int)Stat.Con] += o_ptr.pval[o_ptr.which_pval(Object_Flag.CON.value)]; if (f.has(Object_Flag.CHR.value)) state.stat_add[(int)Stat.Chr] += o_ptr.pval[o_ptr.which_pval(Object_Flag.CHR.value)]; /* Affect stealth */ if (f.has(Object_Flag.STEALTH.value)) state.skills[(int)Skill.STEALTH] += o_ptr.pval[o_ptr.which_pval(Object_Flag.STEALTH.value)]; /* Affect searching ability (factor of five) */ if (f.has(Object_Flag.SEARCH.value)) state.skills[(int)Skill.SEARCH] += (short)(o_ptr.pval[o_ptr.which_pval(Object_Flag.SEARCH.value)] * 5); /* Affect searching frequency (factor of five) */ if (f.has(Object_Flag.SEARCH.value)) state.skills[(int)Skill.SEARCH_FREQUENCY] += (short)(o_ptr.pval[o_ptr.which_pval(Object_Flag.SEARCH.value)] * 5); /* Affect infravision */ if (f.has(Object_Flag.INFRA.value)) state.see_infra += o_ptr.pval[o_ptr.which_pval(Object_Flag.INFRA.value)]; /* Affect digging (factor of 20) */ if (f.has(Object_Flag.TUNNEL.value)) state.skills[(int)Skill.DIGGING] += (short)(o_ptr.pval[o_ptr.which_pval(Object_Flag.TUNNEL.value)] * 20); /* Affect speed */ if (f.has(Object_Flag.SPEED.value)) state.speed += o_ptr.pval[o_ptr.which_pval(Object_Flag.SPEED.value)]; /* Affect blows */ if (f.has(Object_Flag.BLOWS.value)) extra_blows += o_ptr.pval[o_ptr.which_pval(Object_Flag.BLOWS.value)]; /* Affect shots */ if (f.has(Object_Flag.SHOTS.value)) extra_shots += o_ptr.pval[o_ptr.which_pval(Object_Flag.SHOTS.value)]; /* Affect Might */ if (f.has(Object_Flag.MIGHT.value)) extra_might += o_ptr.pval[o_ptr.which_pval(Object_Flag.MIGHT.value)]; /* Modify the base armor class */ state.ac += o_ptr.ac; /* The base armor class is always known */ state.dis_ac += o_ptr.ac; /* Apply the bonuses to armor class */ if (!id_only || o_ptr.is_known()) state.to_a += o_ptr.to_a; /* Apply the mental bonuses to armor class, if known */ if (o_ptr.defence_plusses_are_visible()) state.dis_to_a += o_ptr.to_a; /* Hack -- do not apply "weapon" bonuses */ if (i == Misc.INVEN_WIELD) continue; /* Hack -- do not apply "bow" bonuses */ if (i == Misc.INVEN_BOW) continue; /* Apply the bonuses to hit/damage */ if (!id_only || o_ptr.is_known()) { state.to_h += o_ptr.to_h; state.to_d += o_ptr.to_d; } /* Apply the mental bonuses tp hit/damage, if known */ if (o_ptr.attack_plusses_are_visible()) { state.dis_to_h += o_ptr.to_h; state.dis_to_d += o_ptr.to_d; } } /*** Update all flags ***/ for (i = 0; i < Object_Flag.MAX.value; i++) if (collect_f.has(i)) state.flags.on(i); /*** Handle stats ***/ /* Calculate stats */ for (i = 0; i < (int)Stat.Max; i++) { int add, top, use, ind; /* Extract modifier */ add = state.stat_add[i]; /* Maximize mode */ if (Option.birth_maximize.value) { /* Modify the stats for race/class */ add += (p_ptr.Race.r_adj[i] + p_ptr.Class.c_adj[i]); } /* Extract the new "stat_top" value for the stat */ top = Birther.modify_stat_value(p_ptr.stat_max[i], add); /* Save the new value */ state.stat_top[i] = (short)top; /* Extract the new "stat_use" value for the stat */ use = Birther.modify_stat_value(p_ptr.stat_cur[i], add); /* Save the new value */ state.stat_use[i] = (short)use; /* Values: n/a */ if (use <= 3) ind = 0; /* Values: 3, 4, ..., 18 */ else if (use <= 18) ind = (use - 3); /* Ranges: 18/00-18/09, ..., 18/210-18/219 */ else if (use <= 18+219) ind = (15 + (use - 18) / 10); /* Range: 18/220+ */ else ind = (37); Misc.assert((0 <= ind) && (ind < Misc.STAT_RANGE)); /* Save the new index */ state.stat_ind[i] = (short)ind; } /*** Temporary flags ***/ /* Apply temporary "stun" */ if (p_ptr.timed[(int)Timed_Effect.STUN] > 50) { state.to_h -= 20; state.dis_to_h -= 20; state.to_d -= 20; state.dis_to_d -= 20; state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 8 / 10); } else if (p_ptr.timed[(int)Timed_Effect.STUN] != 0) { state.to_h -= 5; state.dis_to_h -= 5; state.to_d -= 5; state.dis_to_d -= 5; state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 9 / 10); } /* Invulnerability */ if (p_ptr.timed[(int)Timed_Effect.INVULN] != 0) { state.to_a += 100; state.dis_to_a += 100; } /* Temporary blessing */ if (p_ptr.timed[(int)Timed_Effect.BLESSED] != 0) { state.to_a += 5; state.dis_to_a += 5; state.to_h += 10; state.dis_to_h += 10; state.skills[(int)Skill.DEVICE] = (short) (state.skills[(int)Skill.DEVICE] * 105 / 100); } /* Temporary shield */ if (p_ptr.timed[(int)Timed_Effect.SHIELD] != 0) { state.to_a += 50; state.dis_to_a += 50; } /* Temporary stoneskin */ if (p_ptr.timed[(int)Timed_Effect.STONESKIN] != 0) { state.to_a += 40; state.dis_to_a += 40; state.speed -= 5; } /* Temporary "Hero" */ if (p_ptr.timed[(int)Timed_Effect.HERO] != 0) { state.to_h += 12; state.dis_to_h += 12; state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 105 / 100); } /* Temporary "Berserk" */ if (p_ptr.timed[(int)Timed_Effect.SHERO] != 0) { state.to_h += 24; state.dis_to_h += 24; state.to_a -= 10; state.dis_to_a -= 10; state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 9 / 10); } /* Temporary "fast" */ if (p_ptr.timed[(int)Timed_Effect.FAST] != 0 || p_ptr.timed[(int)Timed_Effect.SPRINT] != 0) state.speed += 10; /* Temporary "slow" */ if (p_ptr.timed[(int)Timed_Effect.SLOW] != 0) state.speed -= 10; /* Temporary infravision boost */ if (p_ptr.timed[(int)Timed_Effect.SINFRA] != 0) state.see_infra += 5; /* Terror - this is necessary because TMD_AFRAID already occupies the * of_ptr.timed slot for Object_Flag.AFRAID */ if (p_ptr.timed[(int)Timed_Effect.TERROR] > p_ptr.timed[(int)Timed_Effect.AFRAID]) p_ptr.timed[(int)Timed_Effect.AFRAID] = p_ptr.timed[(int)Timed_Effect.TERROR]; if (p_ptr.timed[(int)Timed_Effect.TERROR] != 0) state.speed += 5; /* Fear can come from item flags too */ if (p_ptr.check_state(Object_Flag.AFRAID, p_ptr.state.flags)) { state.to_h -= 20; state.dis_to_h -= 20; state.to_a += 8; state.dis_to_a += 8; state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 95 / 100); } /* Confusion */ if (p_ptr.timed[(int)Timed_Effect.CONFUSED] != 0) state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 75 / 100); /* Amnesia */ if (p_ptr.timed[(int)Timed_Effect.AMNESIA] != 0) state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 8 / 10); /* Poison */ if (p_ptr.timed[(int)Timed_Effect.POISONED] != 0) state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 95 / 100); /* Hallucination */ if (p_ptr.timed[(int)Timed_Effect.IMAGE] != 0) state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 8 / 10); /*** Analyze weight ***/ /* Extract the current weight (in tenth pounds) */ j = p_ptr.total_weight; /* Extract the "weight limit" (in tenth pounds) */ i = state.weight_limit(); /* Apply "encumbrance" from weight */ if (j > i / 2) state.speed -= (short)((j - (i / 2)) / (i / 10)); /* Bloating slows the player down (a little) */ if (p_ptr.food >= Misc.PY_FOOD_MAX) state.speed -= 10; /* Searching slows the player down */ if (p_ptr.searching != 0) state.speed -= 10; /* Sanity check on extreme speeds */ if (state.speed < 0) state.speed = 0; if (state.speed > 199) state.speed = 199; /*** Apply modifier bonuses ***/ /* Actual Modifier Bonuses (Un-inflate stat bonuses) */ state.to_a += (short)((int)(adj_dex_ta[state.stat_ind[(int)Stat.Dex]]) - 128); state.to_d += (short)((int)(adj_str_td[state.stat_ind[(int)Stat.Str]]) - 128); state.to_h += (short)((int)(adj_dex_th[state.stat_ind[(int)Stat.Dex]]) - 128); state.to_h += (short)((int)(adj_str_th[state.stat_ind[(int)Stat.Str]]) - 128); /* Displayed Modifier Bonuses (Un-inflate stat bonuses) */ state.dis_to_a += (short)((int)(adj_dex_ta[state.stat_ind[(int)Stat.Dex]]) - 128); state.dis_to_d += (short)((int)(adj_str_td[state.stat_ind[(int)Stat.Str]]) - 128); state.dis_to_h += (short)((int)(adj_dex_th[state.stat_ind[(int)Stat.Dex]]) - 128); state.dis_to_h += (short)((int)(adj_str_th[state.stat_ind[(int)Stat.Str]]) - 128); /*** Modify skills ***/ /* Affect Skill -- stealth (bonus one) */ state.skills[(int)Skill.STEALTH] += 1; /* Affect Skill -- disarming (DEX and INT) */ state.skills[(int)Skill.DISARM] += adj_dex_dis[state.stat_ind[(int)Stat.Dex]]; state.skills[(int)Skill.DISARM] += adj_int_dis[state.stat_ind[(int)Stat.Int]]; /* Affect Skill -- magic devices (INT) */ state.skills[(int)Skill.DEVICE] += adj_int_dev[state.stat_ind[(int)Stat.Int]]; /* Affect Skill -- saving throw (WIS) */ state.skills[(int)Skill.SAVE] += adj_wis_sav[state.stat_ind[(int)Stat.Wis]]; /* Affect Skill -- digging (STR) */ state.skills[(int)Skill.DIGGING] += adj_str_dig[state.stat_ind[(int)Stat.Str]]; /* Affect Skills (Level, by Class) */ for (i = 0; i < (int)Skill.MAX; i++) state.skills[i] += (short)(p_ptr.Class.x_skills[i] * p_ptr.lev / 10); /* Limit Skill -- digging from 1 up */ if (state.skills[(int)Skill.DIGGING] < 1) state.skills[(int)Skill.DIGGING] = 1; /* Limit Skill -- stealth from 0 to 30 */ if (state.skills[(int)Skill.STEALTH] > 30) state.skills[(int)Skill.STEALTH] = 30; if (state.skills[(int)Skill.STEALTH] < 0) state.skills[(int)Skill.STEALTH] = 0; /* Apply Skill -- Extract noise from stealth */ state.noise = (uint)(1L << (30 - state.skills[(int)Skill.STEALTH])); /* Obtain the "hold" value */ hold = adj_str_hold[state.stat_ind[(int)Stat.Str]]; /*** Analyze current bow ***/ /* Examine the "current bow" */ o_ptr = inventory[Misc.INVEN_BOW]; /* Assume not heavy */ state.heavy_shoot = false; /* It is hard to hold a heavy bow */ if (hold < o_ptr.weight / 10) { /* Hard to wield a heavy bow */ state.to_h += (short)(2 * (hold - o_ptr.weight / 10)); state.dis_to_h += (short)(2 * (hold - o_ptr.weight / 10)); /* Heavy Bow */ state.heavy_shoot = true; } /* Analyze launcher */ if (o_ptr.kind != null) { /* Get to shoot */ state.num_shots = 1; /* Analyze the launcher */ switch (o_ptr.sval) { /* Sling and ammo */ case SVal.SV_SLING: { state.ammo_tval = TVal.TV_SHOT; state.ammo_mult = 2; break; } /* Short Bow and Arrow */ case SVal.SV_SHORT_BOW: { state.ammo_tval = TVal.TV_ARROW; state.ammo_mult = 2; break; } /* Long Bow and Arrow */ case SVal.SV_LONG_BOW: { state.ammo_tval = TVal.TV_ARROW; state.ammo_mult = 3; break; } /* Light Crossbow and Bolt */ case SVal.SV_LIGHT_XBOW: { state.ammo_tval = TVal.TV_BOLT; state.ammo_mult = 3; break; } /* Heavy Crossbow and Bolt */ case SVal.SV_HEAVY_XBOW: { state.ammo_tval = TVal.TV_BOLT; state.ammo_mult = 4; break; } } /* Apply special flags */ if (o_ptr.kind != null && !state.heavy_shoot) { /* Extra shots */ state.num_shots += (short)extra_shots; /* Extra might */ state.ammo_mult += (byte)extra_might; /* Hack -- Rangers love Bows */ if (player_has(Misc.PF.EXTRA_SHOT.value) && (state.ammo_tval == TVal.TV_ARROW)) { /* Extra shot at level 20 */ if (p_ptr.lev >= 20) state.num_shots++; /* Extra shot at level 40 */ if (p_ptr.lev >= 40) state.num_shots++; } } /* Require at least one shot */ if (state.num_shots < 1) state.num_shots = 1; } /*** Analyze weapon ***/ /* Examine the "current weapon" */ o_ptr = inventory[Misc.INVEN_WIELD]; /* Assume not heavy */ state.heavy_wield = false; /* It is hard to hold a heavy weapon */ if (hold < o_ptr.weight / 10) { /* Hard to wield a heavy weapon */ state.to_h += (short)(2 * (hold - o_ptr.weight / 10)); state.dis_to_h += (short)(2 * (hold - o_ptr.weight / 10)); /* Heavy weapon */ state.heavy_wield = true; } /* Non-object means barehanded attacks */ if (o_ptr.kind == null) Misc.assert(o_ptr.weight == 0); /* Normal weapons */ if (!state.heavy_wield) { /* Calculate number of blows */ state.num_blows = (short)calc_blows(o_ptr, state, extra_blows); /* Boost digging skill by weapon weight */ state.skills[(int)Skill.DIGGING] += (short)(o_ptr.weight / 10); } /* Assume okay */ state.icky_wield = false; /* Priest weapon penalty for non-blessed edged weapons */ if (player_has(Misc.PF.BLESS_WEAPON.value) && !p_ptr.check_state(Object_Flag.BLESSED, p_ptr.state.flags) && ((o_ptr.tval == TVal.TV_SWORD) || (o_ptr.tval == TVal.TV_POLEARM))) { /* Reduce the real bonuses */ state.to_h -= 2; state.to_d -= 2; /* Reduce the mental bonuses */ state.dis_to_h -= 2; state.dis_to_d -= 2; /* Icky weapon */ state.icky_wield = true; } return; }
public bool FA_would_be_obvious() { if (Misc.p_ptr.player_has(Misc.PF.CUMBER_GLOVE.value) && wield_slot() == Misc.INVEN_HANDS) { Bitflag flags = new Bitflag(Object_Flag.SIZE); object_flags(ref flags); if (!flags.has(Object_Flag.DEX.value) && !flags.has(Object_Flag.SPELLS_OK.value)) return true; } return false; }
/** * Determine whether a flagset includes any curse flags. */ public static bool cursed_p(Bitflag f) { Bitflag f2 = new Bitflag(Object_Flag.SIZE); f2.wipe(); create_mask(f2, false, object_flag_type.CURSE); return f.is_inter(f2); }
/* * Have a monster choose a spell to cast. * * Note that the monster's spell list has already had "useless" spells * (bolts that won't hit the player, summons without room, etc.) removed. * Perhaps that should be done by this function. * * Stupid monsters will just pick a spell randomly. Smart monsters * will choose more "intelligently". * * This function could be an efficiency bottleneck. */ static int choose_attack_spell(int m_idx, Bitflag f) { throw new NotImplementedException(); //monster_type *m_ptr = cave_monster(cave, m_idx); //monster_race *r_ptr = &r_info[m_ptr.r_idx]; //int num = 0; //byte spells[RSF_MAX]; //int i, py = p_ptr.py, px = p_ptr.px; //bool has_escape, has_attack, has_summon, has_tactic; //bool has_annoy, has_haste, has_heal; ///* Smart monsters restrict their spell choices. */ //if (OPT(birth_ai_smart) && !rf_has(r_ptr.flags, RF_STUPID)) //{ // /* What have we got? */ // has_escape = test_spells(f, RST_ESCAPE); // has_attack = test_spells(f, RST_ATTACK | RST_BOLT | RST_BALL | RST_BREATH); // has_summon = test_spells(f, RST_SUMMON); // has_tactic = test_spells(f, RST_TACTIC); // has_annoy = test_spells(f, RST_ANNOY); // has_haste = test_spells(f, RST_HASTE); // has_heal = test_spells(f, RST_HEAL); // /*** Try to pick an appropriate spell type ***/ // /* Hurt badly or afraid, attempt to flee */ // if (has_escape && ((m_ptr.hp < m_ptr.maxhp / 4) || m_ptr.m_timed[MON_TMD_FEAR])) // { // /* Choose escape spell */ // set_spells(f, RST_ESCAPE); // } // /* Still hurt badly, couldn't flee, attempt to heal */ // else if (has_heal && m_ptr.hp < m_ptr.maxhp / 4) // { // /* Choose heal spell */ // set_spells(f, RST_HEAL); // } // /* Player is close and we have attack spells, blink away */ // else if (has_tactic && (distance(py, px, m_ptr.fy, m_ptr.fx) < 4) && // has_attack && (randint0(100) < 75)) // { // /* Choose tactical spell */ // set_spells(f, RST_TACTIC); // } // /* We're hurt (not badly), try to heal */ // else if (has_heal && (m_ptr.hp < m_ptr.maxhp * 3 / 4) && // (randint0(100) < 60)) // { // /* Choose heal spell */ // set_spells(f, RST_HEAL); // } // /* Summon if possible (sometimes) */ // else if (has_summon && (randint0(100) < 50)) // { // /* Choose summon spell */ // set_spells(f, RST_SUMMON); // } // /* Attack spell (most of the time) */ // else if (has_attack && (randint0(100) < 85)) // { // /* Choose attack spell */ // set_spells(f, RST_ATTACK | RST_BOLT | RST_BALL | RST_BREATH); // } // /* Try another tactical spell (sometimes) */ // else if (has_tactic && (randint0(100) < 50)) // { // /* Choose tactic spell */ // set_spells(f, RST_TACTIC); // } // /* Haste self if we aren't already somewhat hasted (rarely) */ // else if (has_haste && (randint0(100) < (20 + r_ptr.speed - m_ptr.mspeed))) // { // /* Choose haste spell */ // set_spells(f, RST_HASTE); // } // /* Annoy player (most of the time) */ // else if (has_annoy && (randint0(100) < 85)) // { // /* Choose annoyance spell */ // set_spells(f, RST_ANNOY); // } // /* Else choose no spell */ // else // { // rsf_wipe(f); // } // /* Anything left? */ // if (rsf_is_empty(f)) return (FLAG_END); //} ///* Extract all spells: "innate", "normal", "bizarre" */ //for (i = FLAG_START, num = 0; i < RSF_MAX; i++) //{ // if (rsf_has(f, i)) spells[num++] = i; //} ///* Paranoia */ //if (num == 0) return 0; ///* Pick at random */ //return (spells[randint0(num)]); }
/* * Creatures can cast spells, shoot missiles, and breathe. * * Returns "true" if a spell (or whatever) was (successfully) cast. * * XXX XXX XXX This function could use some work, but remember to * keep it as optimized as possible, while retaining generic code. * * Verify the various "blind-ness" checks in the code. * * XXX XXX XXX Note that several effects should really not be "seen" * if the player is blind. * * Perhaps monsters should breathe at locations *near* the player, * since this would allow them to inflict "partial" damage. * * Perhaps smart monsters should decline to use "bolt" spells if * there is a monster in the way, unless they wish to kill it. * * It will not be possible to "correctly" handle the case in which a * monster attempts to attack a location which is thought to contain * the player, but which in fact is nowhere near the player, since this * might induce all sorts of messages about the attack itself, and about * the effects of the attack, which the player might or might not be in * a position to observe. Thus, for simplicity, it is probably best to * only allow "faulty" attacks by a monster if one of the important grids * (probably the initial or final grid) is in fact in view of the player. * It may be necessary to actually prevent spell attacks except when the * monster actually has line of sight to the player. Note that a monster * could be left in a bizarre situation after the player ducked behind a * pillar and then teleported away, for example. * * Note that this function attempts to optimize the use of spells for the * cases in which the monster has no spells, or has spells but cannot use * them, or has spells but they will have no "useful" effect. Note that * this function has been an efficiency bottleneck in the past. * * Note the special "MFLAG_NICE" flag, which prevents a monster from using * any spell attacks until the player has had a single chance to move. */ static bool make_attack_spell(int m_idx) { int chance, thrown_spell, rlev, failrate; Bitflag f = new Bitflag(Monster_Spell_Flag.SIZE); Monster m_ptr = Cave.cave_monster(Cave.cave, m_idx); Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; Monster_Lore l_ptr = Misc.l_list[m_ptr.r_idx]; //char m_name[80], m_poss[80], ddesc[80]; string m_name, m_poss, ddesc; /* Player position */ int px = Misc.p_ptr.px; int py = Misc.p_ptr.py; /* Extract the blind-ness */ bool blind = (Misc.p_ptr.timed[(int)Timed_Effect.BLIND] != 0 ? true : false); /* Extract the "see-able-ness" */ bool seen = (!blind && m_ptr.ml); /* Assume "normal" target */ bool normal = true; /* Handle "leaving" */ if (Misc.p_ptr.leaving) return false; /* Cannot cast spells when confused */ if (m_ptr.m_timed[(int)Misc.MON_TMD.CONF] != 0) return (false); /* Cannot cast spells when nice */ if ((m_ptr.mflag & Monster_Flag.MFLAG_NICE) != 0) return false; /* Hack -- Extract the spell probability */ chance = (r_ptr.freq_innate + r_ptr.freq_spell) / 2; /* Not allowed to cast spells */ if (chance == 0) return false; /* Only do spells occasionally */ if (Random.randint0(100) >= chance) return false; /* Hack -- require projectable player */ if (normal) { /* Check range */ if (m_ptr.cdis > Misc.MAX_RANGE) return false; /* Check path */ if (!Cave.projectable(m_ptr.fy, m_ptr.fx, py, px, Spell.PROJECT_NONE)) return false; } /* Extract the monster level */ rlev = ((r_ptr.level >= 1) ? r_ptr.level : 1); /* Extract the racial spell flags */ f.copy(r_ptr.spell_flags); /* Allow "desperate" spells */ if (r_ptr.flags.has(Monster_Flag.SMART.value) && m_ptr.hp < m_ptr.maxhp / 10 && Random.randint0(100) < 50){ throw new NotImplementedException(); ///* Require intelligent spells */ //set_spells(f, RST_HASTE | RST_ANNOY | RST_ESCAPE | RST_HEAL | RST_TACTIC | RST_SUMMON); } /* Remove the "ineffective" spells */ remove_bad_spells(m_idx, f); /* Check whether summons and bolts are worth it. */ if (!r_ptr.flags.has(Monster_Flag.STUPID.value)) { /* Check for a clean bolt shot */ if (Monster_Spell_Flag.test_spells(f, Monster_Spell_Flag.mon_spell_type.RST_BOLT) && !clean_shot(m_ptr.fy, m_ptr.fx, py, px)) /* Remove spells that will only hurt friends */ Monster_Spell_Flag.set_spells(f, ~Monster_Spell_Flag.mon_spell_type.RST_BOLT); /* Check for a possible summon */ if (!(summon_possible(m_ptr.fy, m_ptr.fx))) /* Remove summoning spells */ Monster_Spell_Flag.set_spells(f, ~Monster_Spell_Flag.mon_spell_type.RST_SUMMON); } /* No spells left */ if (f.is_empty()) return false; /* Get the monster name (or "it") */ m_name = m_ptr.monster_desc(0x00); //Nick: Capatilize the first letter. m_name = Char.ToUpper(m_name[0]) + m_name.Substring(1); /* Get the monster possessive ("his"/"her"/"its") */ m_poss = m_ptr.monster_desc(Desc.PRO2 | Desc.POSS); /* Get the "died from" name */ ddesc = m_ptr.monster_desc(Desc.SHOW | Desc.IND2); /* Choose a spell to cast */ thrown_spell = choose_attack_spell(m_idx, f); /* Abort if no spell was chosen */ if (thrown_spell == 0) return false; /* If we see an unaware monster try to cast a spell, become aware of it */ if (m_ptr.unaware) become_aware(m_idx); /* Calculate spell failure rate */ failrate = 25 - (rlev + 3) / 4; if (m_ptr.m_timed[(int)Misc.MON_TMD.FEAR] != 0) failrate += 20; /* Stupid monsters will never fail (for jellies and such) */ if (Option.birth_ai_smart.value || r_ptr.flags.has(Monster_Flag.STUPID.value)) failrate = 0; /* Check for spell failure (innate attacks never fail) */ if ((thrown_spell >= Monster_Spell_Flag.MIN_NONINNATE_SPELL) && (Random.randint0(100) < failrate)) { /* Message */ Utilities.msg("{0} tries to cast a spell, but fails.", m_name); return true; } /* Cast the spell. */ Cave.disturb(Misc.p_ptr, 1, 0); /* Special case RSF_HASTE until TMD_* and MON_TMD_* are rationalised */ if (thrown_spell == Monster_Spell_Flag.HASTE.value) { if (blind) Utilities.msg("{0} mumbles.", m_name); else Utilities.msg("{0} concentrates on {1} body.", m_name, m_poss); mon_inc_timed(m_idx, Misc.MON_TMD.FAST, 50, 0, false); } else Monster_Spell_Flag.do_mon_spell(thrown_spell, m_idx, seen); /* Remember what the monster did to us */ if (seen) { l_ptr.spell_flags.on(thrown_spell); /* Innate spell */ if (thrown_spell < Monster_Spell_Flag.MIN_NONINNATE_SPELL) { if (l_ptr.cast_innate < byte.MaxValue) l_ptr.cast_innate++; } else { /* Bolt or Ball, or Special spell */ if (l_ptr.cast_spell < byte.MaxValue) l_ptr.cast_spell++; } } /* Always take note of monsters that kill you */ if (Misc.p_ptr.is_dead && (l_ptr.deaths < short.MaxValue)) { l_ptr.deaths++; } /* A spell was cast */ return true; }
/* * Determine whether a weapon or missile weapon is obviously {excellent} when * worn. * * XXX Eddie should messages be adhoc all over the place? perhaps the main * loop should check for change in inventory/wieldeds and all messages be * printed from one place */ public void notice_on_wield() { Bitflag f = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); Bitflag obvious_mask = new Bitflag(Object_Flag.SIZE); bool obvious = false; Object_Flag.create_mask(obvious_mask, true, Object_Flag.object_flag_id.WIELD); /* Save time of wield for later */ object_last_wield = Misc.turn; /* Only deal with un-ID'd items */ if (is_known()) return; /* Wear it */ flavor_tried(); if (add_ident_flags(IDENT_WORN)) check_for_ident(); /* CC: may wish to be more subtle about this once we have ego lights * with multiple pvals */ if (is_light() && ego != null) notice_ego(); if (flavor_is_aware() && easy_know()) { notice_everything(); return; } /* Automatically sense artifacts upon wield */ sense_artifact(); /* Note artifacts when found */ if (artifact != null) History.add_artifact(artifact, is_known(), true); /* special case FA, needed at least for mages wielding gloves */ if (FA_would_be_obvious()) obvious_mask.on(Object_Flag.FREE_ACT.value); /* Extract the flags */ object_flags(ref f); /* Find obvious things (disregarding curses) - why do we remove the curses?? */ Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.CURSE); obvious_mask.diff(f2); if (f.is_inter(obvious_mask)) obvious = true; Object_Flag.create_mask(obvious_mask, true, Object_Flag.object_flag_id.WIELD); /* Notice any obvious brands or slays */ Slay.object_notice_slays(this, obvious_mask); /* Learn about obvious flags */ known_flags.union(obvious_mask); /* XXX Eddie should these next NOT call object_check_for_ident due to worries about repairing? */ /* XXX Eddie this is a small hack, but jewelry with anything noticeable really is obvious */ /* XXX Eddie learn =soulkeeping vs =bodykeeping when notice sustain_str */ if (is_jewelry()) { /* Learn the flavor of jewelry with obvious flags */ if (EASY_LEARN && obvious) flavor_aware(); /* Learn all flags on any aware non-artifact jewelry */ if (flavor_is_aware() && artifact == null) know_all_flags(); } check_for_ident(); if (!obvious) return; /* XXX Eddie need to add stealth here, also need to assert/double-check everything is covered */ /* CC: also need to add FA! */ if (f.has(Object_Flag.STR.value)) Utilities.msg("You feel %s!", pval[which_pval( Object_Flag.STR.value)] > 0 ? "stronger" : "weaker"); if (f.has(Object_Flag.INT.value)) Utilities.msg("You feel %s!", pval[which_pval( Object_Flag.INT.value)] > 0 ? "smarter" : "more stupid"); if (f.has(Object_Flag.WIS.value)) Utilities.msg("You feel %s!", pval[which_pval( Object_Flag.WIS.value)] > 0 ? "wiser" : "more naive"); if (f.has(Object_Flag.DEX.value)) Utilities.msg("You feel %s!", pval[which_pval( Object_Flag.DEX.value)] > 0 ? "more dextrous" : "clumsier"); if (f.has(Object_Flag.CON.value)) Utilities.msg("You feel %s!", pval[which_pval( Object_Flag.CON.value)] > 0 ? "healthier" : "sicklier"); if (f.has(Object_Flag.CHR.value)) Utilities.msg("You feel %s!", pval[which_pval( Object_Flag.CHR.value)] > 0 ? "cuter" : "uglier"); if (f.has(Object_Flag.SPEED.value)) Utilities.msg("You feel strangely %s.", pval[which_pval( Object_Flag.SPEED.value)] > 0 ? "quick" : "sluggish"); if (f.has(Object_Flag.BLOWS.value)) Utilities.msg("Your weapon %s in your hands.", pval[which_pval(Object_Flag.BLOWS.value)] > 0 ? "tingles" : "aches"); if (f.has(Object_Flag.SHOTS.value)) Utilities.msg("Your bow %s in your hands.", pval[which_pval(Object_Flag.SHOTS.value)] > 0 ? "tingles" : "aches"); if (f.has(Object_Flag.INFRA.value)) Utilities.msg("Your eyes tingle."); if (f.has(Object_Flag.LIGHT.value)) Utilities.msg("It glows!"); if (f.has(Object_Flag.TELEPATHY.value)) Utilities.msg("Your mind feels strangely sharper!"); /* WARNING -- masking f by obvious mask -- this should be at the end of this function */ /* CC: I think this can safely go, but just in case ... */ /*flags_mask(f, OF_SIZE, OF_OBVIOUS_MASK, FLAG_END); */ /* Remember the flags */ notice_sensing(); /* XXX Eddie should we check_for_ident here? */ }
/* * Remove the "bad" spells from a spell list */ static void remove_bad_spells(int m_idx, Bitflag f) { Monster m_ptr = Cave.cave_monster(Cave.cave, m_idx); Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; Bitflag f2 = new Bitflag(Monster_Spell_Flag.SIZE); Bitflag ai_flags = new Bitflag(Object_Flag.SIZE); int i; uint smart = 0; /* Stupid monsters act randomly */ if (r_ptr.flags.has(Monster_Flag.STUPID.value)) return; /* Take working copy of spell flags */ f2.copy(f); /* Don't heal if full */ if (m_ptr.hp >= m_ptr.maxhp) f2.off(Monster_Spell_Flag.HEAL.value); /* Don't haste if hasted with time remaining */ if (m_ptr.m_timed[(int)Misc.MON_TMD.FAST] > 10) f2.off(Monster_Spell_Flag.HASTE.value); /* Don't teleport to if the player is already next to us */ if (m_ptr.cdis == 1) f2.off(Monster_Spell_Flag.TELE_TO.value); /* Update acquired knowledge */ ai_flags.wipe(); if (Option.birth_ai_learn.value) { /* Occasionally forget player status */ if (Random.one_in_(100)) m_ptr.known_pflags.wipe(); /* Use the memorized flags */ smart = m_ptr.smart; ai_flags.copy(m_ptr.known_pflags); } /* Cheat if requested */ if (Option.birth_ai_cheat.value) { for (i = 0; i < Object_Flag.MAX.value; i++) if (Misc.p_ptr.check_state(Object_Flag.list[i], Misc.p_ptr.state.flags)) ai_flags.on(i); if (Misc.p_ptr.msp == 0) smart |= Misc.SM_IMM_MANA; } /* Cancel out certain flags based on knowledge */ if(!ai_flags.is_empty()) { throw new NotImplementedException(); //unset_spells(f2, ai_flags, r_ptr); } if ((smart & Misc.SM_IMM_MANA) != 0 && Random.randint0(100) < 50 * (r_ptr.flags.has(Monster_Flag.SMART.value) ? 2 : 1)) f2.off(Monster_Spell_Flag.DRAIN_MANA.value); /* use working copy of spell flags */ f.copy(f2); }
/** * 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(); } }
/** * Notice a given special flag on wielded items. * * \param flag is the flag to notice */ public static void wieldeds_notice_flag(Player.Player p, int flag) { int i; /* Sanity check */ if (flag == 0) return; /* XXX Eddie need different naming conventions for starting wieldeds at INVEN_WIELD vs INVEN_WIELD+2 */ for (i = Misc.INVEN_WIELD; i < Misc.ALL_INVEN_TOTAL; i++) { Object o_ptr = p.inventory[i]; Bitflag f = new Bitflag(Object_Flag.SIZE); if (o_ptr.kind == null) continue; o_ptr.object_flags(ref f); if (f.has(flag) && !o_ptr.known_flags.has(flag)) { //char o_name[80]; string o_name = o_ptr.object_desc(Detail.BASE); /* Notice the flag */ o_ptr.notice_flag(flag); /* XXX Eddie should this go before noticing the flag to avoid learning twice? */ if (EASY_LEARN && o_ptr.is_jewelry()) { /* XXX Eddie EASY_LEARN Possible concern: gets =teleportation just from +2 speed */ o_ptr.flavor_aware(); o_ptr.check_for_ident(); } /* Message */ Object_Flag.flag_message(flag, o_name); } else { /* Notice that flag is absent */ o_ptr.notice_flag(flag); } /* XXX Eddie should not need this, should be done in noticing, but will remove later */ o_ptr.check_for_ident(); } return; }
/** * Determine whether an object flag or its timed equivalent are set in the * passed-in flags (which probably come from a state structure). This assumes * that there are no p_ptr.timed effects which can be active yet unknown to * the player. * * \param p player to act upon * \param flag is the object flag for which we are checking. * \param f is the set of flags we're checking */ public bool check_state(Object.Object_Flag flag, Bitflag f) { Object_Flag of_ptr = Object_Flag.list[flag.value]; /* Sanity check */ if (flag == null) return false; if (f.has(flag.value) || (of_ptr.timed != (Timed_Effect)0 && timed[(int)of_ptr.timed] > 0)) return true; return false; }
static int obj_desc_inscrip(Object o_ptr, ref string buf, int max, int end) { string[] u = { "", "", "", "" }; int n = 0; Object.obj_pseudo_t feel = o_ptr.pseudo(); Bitflag flags_known = new Bitflag(Object_Flag.SIZE); Bitflag f2 = new Bitflag(Object_Flag.SIZE); o_ptr.object_flags_known(ref flags_known); /* Get inscription */ if (o_ptr.note != null && o_ptr.note.value != null) { u[n++] = o_ptr.note.ToString(); } /* Use special inscription, if any */ if (!o_ptr.is_known() && feel != 0) { /* cannot tell excellent vs strange vs splendid until wield */ if (!o_ptr.was_worn() && o_ptr.ego != null) { u[n++] = "ego"; } else { u[n++] = Misc.inscrip_text[(int)feel]; //I know that feel bro. } } else if (((o_ptr.ident & Object.IDENT_EMPTY) != 0) && !o_ptr.is_known()) { u[n++] = "empty"; } else if (!o_ptr.is_known() && o_ptr.was_worn()) { if (o_ptr.wield_slot() == Misc.INVEN_WIELD || o_ptr.wield_slot() == Misc.INVEN_BOW) { u[n++] = "wielded"; } else { u[n++] = "worn"; } } else if (!o_ptr.is_known() && o_ptr.was_fired()) { u[n++] = "fired"; } else if (!o_ptr.flavor_is_aware() && o_ptr.flavor_was_tried()) { u[n++] = "tried"; } /* Note curses */ Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.CURSE); if (flags_known.is_inter(f2)) { u[n++] = "cursed"; } /* Note squelch */ if (Squelch.item_ok(o_ptr)) { u[n++] = "squelch"; } if (n != 0) { int i; for (i = 0; i < n; i++) { if (i == 0) { buf = buf + " {"; } buf = buf + u[i]; if (i < n - 1) { buf += ", "; } } buf += "}"; } return(end); }
/* * Evaluate the object's overall power level. */ public int object_power(bool verbose, StreamWriter log_file, bool known) { int p = 0, q = 0, slay_pwr = 0, dice_pwr = 0; int i, j; int extra_stat_bonus = 0, mult = 1, num_slays = 0, k = 1; Bitflag flags = new Bitflag(Object_Flag.SIZE); Bitflag mask = new Bitflag(Object_Flag.SIZE); /* Zero the flag counts */ for (i = 0; i < sets.Length; i++) { sets[i].count = 0; } /* Extract the flags */ if (known) { // log_file.Write("Object is deemed knwon\n"); object_flags(ref flags); } else { // log_file.Write("Object may not be fully known\n"); object_flags_known(ref flags); } /* Log the flags in human-readable form */ //if (verbose) //log_flags(flags, log_file); //meh /* Get the slay power and number of slay/brand types */ Object_Flag.create_mask(mask, false, Object_Flag.object_flag_type.SLAY, Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND); num_slays = Slay.list_slays(flags, mask, null, null, null, true); if (num_slays != 0) { slay_pwr = slay_power(verbose, log_file, known); } /* Start with any damage boost from the item itself */ p += (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() == Misc.INVEN_WIELD || is_ammo()) { dice_pwr = (dd * (ds + 1) * DAMAGE_POWER / 4); // file_putf(log_file, "Adding %d power for dam dice\n", dice_pwr); /* Add 2nd lot of damage power for nonweapons */ } else if (wield_slot() != Misc.INVEN_BOW) { p += (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 != 0 || flags.has(Object_Flag.BLOWS.value) || flags.has(Object_Flag.SHOTS.value) || flags.has(Object_Flag.MIGHT.value)) { dice_pwr = (WEAP_DAMAGE * DAMAGE_POWER); // file_putf(log_file, "Adding %d power for nonweap combat flags\n", dice_pwr); } } p += dice_pwr; /* Add ammo damage for launchers, get multiplier and rescale */ if (wield_slot() == Misc.INVEN_BOW) { p += (archery[sval / 10].ammo_dam * DAMAGE_POWER / 2); // file_putf(log_file, "Adding power from ammo, total is %d\n", p); mult = bow_multiplier(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 (is_ammo()) { if (ego != null) { p += (archery[tval - TVal.TV_SHOT].launch_dam * DAMAGE_POWER / 2); } p = p * archery[tval - 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 (flags.has(Object_Flag.BLOWS.value)) { j = which_pval(Object_Flag.BLOWS.value); if (known || this_pval_is_visible(j)) { if (pval[j] >= INHIBIT_BLOWS) { p += INHIBIT_POWER; // file_putf(log_file, "INHIBITING - too many extra blows - quitting\n"); return(p); } else { p = p * (MAX_BLOWS + pval[j]) / MAX_BLOWS; /* Add boost for assumed off-weapon damage */ p += (NONWEAP_DAMAGE * 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 (flags.has(Object_Flag.SHOTS.value)) { j = which_pval(Object_Flag.SHOTS.value); if (known || this_pval_is_visible(j)) { if (pval[j] >= INHIBIT_SHOTS) { p += INHIBIT_POWER; // file_putf(log_file, "INHIBITING - too many extra shots - quitting\n"); return(p); } else if (pval[j] > 0) { p = (p * (1 + 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 (flags.has(Object_Flag.MIGHT.value)) { j = which_pval(Object_Flag.MIGHT.value); if (known || this_pval_is_visible(j)) { if (pval[j] >= INHIBIT_MIGHT) { p += INHIBIT_POWER; mult = 1; /* don't overflow */ // file_putf(log_file, "INHIBITING - too much extra might - quitting\n"); return(p); } else { mult += 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 != 0) { p += (dice_pwr * (slay_pwr / 100)) / (Eval.tot_mon_power / 100); // 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() == Misc.INVEN_BOW) { p /= MAX_BLOWS; // file_putf(log_file, "Rescaling bow power, total is %d\n", p); } /* Add power for +to_hit */ p += (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 (ac != 0) { p += BASE_ARMOUR_POWER; q += (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 (weight > 0) { i = 750 * (ac + to_a) / 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 += (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 (to_a > HIGH_TO_AC) { p += ((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 (to_a > VERYHIGH_TO_AC) { p += ((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 (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() == Misc.INVEN_LIGHT) { p += BASE_LIGHT_POWER; /* Artifact lights have larger radius so add more */ if (artifact != null) { p += BASE_LIGHT_POWER; } // file_putf(log_file, "Adding power for light radius, total is %d\n", p); } /* Add base power for jewelry */ if (is_jewelry()) { 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 = flags.next(Bitflag.FLAG_START); i != Bitflag.FLAG_null; i = flags.next(i + 1)) { if (Object_Flag.flag_uses_pval(i)) { j = which_pval(i); if (known || this_pval_is_visible(j)) { k = pval[j]; extra_stat_bonus += (k * Object_Flag.pval_mult(i)); } } else { k = 1; } if (Object_Flag.flag_power(i) != 0) { p += (k * Object_Flag.flag_power(i) * Object_Flag.slot_mult(i, wield_slot())); //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 < sets.Length; j++) { if ((sets[j].type == Object_Flag.obj_flag_type(i)) && (i != Object_Flag.SUST_CHR.value)) { 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 < sets.Length; i++) { if (sets[i].count > 1) { q = (sets[i].factor * sets[i].count * sets[i].count); /* Scale damage-dependent set bonuses by damage dice power */ if (sets[i].dam_dep) { q = q * dice_pwr / (DAMAGE_POWER * 5); } p += q; // file_putf(log_file, "Adding power for multiple %s, total is %d\n", sets[i].desc, 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 %s, total is %d\n", sets[i].desc, p); } } /* add power for effect */ if (known || effect_is_known()) { if (artifact != null && artifact.effect != null) { p += artifact.effect.effect_power(); // file_putf(log_file, "Adding power for artifact activation, total is %d\n", p); } else { p += kind.effect.effect_power(); // 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); }
/* * Remove the "bad" spells from a spell list */ static void remove_bad_spells(int m_idx, Bitflag f) { Monster m_ptr = Cave.cave_monster(Cave.cave, m_idx); Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx]; Bitflag f2 = new Bitflag(Monster_Spell_Flag.SIZE); Bitflag ai_flags = new Bitflag(Object_Flag.SIZE); int i; uint smart = 0; /* Stupid monsters act randomly */ if (r_ptr.flags.has(Monster_Flag.STUPID.value)) { return; } /* Take working copy of spell flags */ f2.copy(f); /* Don't heal if full */ if (m_ptr.hp >= m_ptr.maxhp) { f2.off(Monster_Spell_Flag.HEAL.value); } /* Don't haste if hasted with time remaining */ if (m_ptr.m_timed[(int)Misc.MON_TMD.FAST] > 10) { f2.off(Monster_Spell_Flag.HASTE.value); } /* Don't teleport to if the player is already next to us */ if (m_ptr.cdis == 1) { f2.off(Monster_Spell_Flag.TELE_TO.value); } /* Update acquired knowledge */ ai_flags.wipe(); if (Option.birth_ai_learn.value) { /* Occasionally forget player status */ if (Random.one_in_(100)) { m_ptr.known_pflags.wipe(); } /* Use the memorized flags */ smart = m_ptr.smart; ai_flags.copy(m_ptr.known_pflags); } /* Cheat if requested */ if (Option.birth_ai_cheat.value) { for (i = 0; i < Object_Flag.MAX.value; i++) { if (Misc.p_ptr.check_state(Object_Flag.list[i], Misc.p_ptr.state.flags)) { ai_flags.on(i); } } if (Misc.p_ptr.msp == 0) { smart |= Misc.SM_IMM_MANA; } } /* Cancel out certain flags based on knowledge */ if (!ai_flags.is_empty()) { throw new NotImplementedException(); //unset_spells(f2, ai_flags, r_ptr); } if ((smart & Misc.SM_IMM_MANA) != 0 && Random.randint0(100) < 50 * (r_ptr.flags.has(Monster_Flag.SMART.value) ? 2 : 1)) { f2.off(Monster_Spell_Flag.DRAIN_MANA.value); } /* use working copy of spell flags */ f.copy(f2); }
/* * Obtain the flags for an item */ public void object_flags(ref Bitflag flags) { flags.wipe(); if (kind == null) return; flags.copy(this.flags); }