/** * 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)); }
/** * 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; }
/* * 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); }
/* * 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); } }
/** * 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); }
/** * 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; }
/* * Obtain the flags for an item */ public void object_flags(ref Bitflag flags) { flags.wipe(); if (kind == null) return; flags.copy(this.flags); }
/* * 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); }
/** * 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; } } }