示例#1
0
        /**
         * Attack the monster at the given location
         *
         * We get blows until energy drops below that required for another blow, or
         * until the target monster dies. Each blow is handled by py_attack_real().
         * We don't allow @ to spend more than 100 energy in one go, to avoid slower
         * monsters getting double moves.
         */
        public static void py_attack(int y, int x)
        {
            int  blow_energy = 10000 / Misc.p_ptr.state.num_blows;
            int  blows       = 0;
            bool fear        = false;

            Monster.Monster m_ptr = Cave.cave_monster(Cave.cave, Cave.cave.m_idx[y][x]);

            /* disturb the player */
            Cave.disturb(Misc.p_ptr, 0, 0);

            /* Initialize the energy used */
            Misc.p_ptr.energy_use = 0;

            /* Attack until energy runs out or enemy dies. We limit energy use to 100
             * to avoid giving monsters a possible double move. */
            while (Misc.p_ptr.energy >= blow_energy * (blows + 1))
            {
                bool stop = py_attack_real(y, x, ref fear);
                Misc.p_ptr.energy_use += (short)blow_energy;
                if (stop || Misc.p_ptr.energy_use + blow_energy > 100)
                {
                    break;
                }
                blows++;
            }

            /* Hack - delay fear messages */
            if (fear && m_ptr.ml)
            {
                //char m_name[80];
                string m_name = m_ptr.monster_desc(0);
                Monster_Message.add_monster_message(m_name, Cave.cave.m_idx[y][x], MON_MSG.FLEE_IN_TERROR, true);
            }
        }
示例#2
0
        public static void wr_monsters()
        {
            int i;
            int j;

            if (Misc.p_ptr.is_dead)
            {
                return;
            }

            /* Total monsters */
            wr_u16b((ushort)Cave.cave_monster_max(Cave.cave));

            /* Dump the monsters */
            for (i = 1; i < Cave.cave_monster_max(Cave.cave); i++)
            {
                byte unaware = 0;

                Monster.Monster m_ptr = Cave.cave_monster(Cave.cave, i);

                wr_s16b(m_ptr.r_idx);
                wr_byte(m_ptr.fy);
                wr_byte(m_ptr.fx);
                wr_s16b(m_ptr.hp);
                wr_s16b(m_ptr.maxhp);
                wr_byte(m_ptr.mspeed);
                wr_byte(m_ptr.energy);
                wr_byte((byte)Misc.MON_TMD.MAX);

                for (j = 0; j < (byte)Misc.MON_TMD.MAX; j++)
                {
                    wr_s16b(m_ptr.m_timed[j]);
                }

                if (m_ptr.unaware)
                {
                    unaware |= 0x01;
                }
                wr_byte(unaware);

                for (j = 0; j < Object.Object_Flag.BYTES && j < Object.Object_Flag.SIZE; j++)
                {
                    wr_byte(m_ptr.known_pflags[j]);
                }
                if (j < Object.Object_Flag.BYTES)
                {
                    Savefile.pad_bytes(Object.Object_Flag.BYTES - j);
                }

                wr_byte(0);
            }
        }
示例#3
0
        /*
         * Redraw the "monster health bar"
         *
         * The "monster health bar" provides visual feedback on the "health"
         * of the monster currently being "tracked".  There are several ways
         * to "track" a monster, including targetting it, attacking it, and
         * affecting it (and nobody else) with a ranged attack.  When nothing
         * is being tracked, we clear the health bar.  If the monster being
         * tracked is not currently visible, a special health bar is shown.
         */
        static void prt_health(int row, int col)
        {
            ConsoleColor attr = monster_health_attr();

            Monster.Monster mon;

            /* Not tracking */
            if (Misc.p_ptr.health_who == 0)
            {
                /* Erase the health bar */
                Term.erase(col, row, 12);
                return;
            }

            mon = Cave.cave_monster(Cave.cave, Misc.p_ptr.health_who);

            /* Tracking an unseen, hallucinatory, or dead monster */
            if ((!mon.ml) ||                                        /* Unseen */
                (Misc.p_ptr.timed[(int)Timed_Effect.IMAGE] != 0) || /* Hallucination */
                (mon.hp < 0))                                       /* Dead (?) */
            {
                /* The monster health is "unknown" */
                Term.putstr(col, row, 12, attr, "[----------]");
            }

            /* Tracking a visible monster */
            else
            {
                int pct, len;

                Monster.Monster m_ptr = Cave.cave_monster(Cave.cave, Misc.p_ptr.health_who);

                /* Extract the "percent" of health */
                pct = (int)(100L * m_ptr.hp / m_ptr.maxhp);

                /* Convert percent into "health" */
                len = (pct < 10) ? 1 : (pct < 90) ? (pct / 10 + 1) : 10;

                /* Default to "unknown" */
                Term.putstr(col, row, 12, ConsoleColor.White, "[----------]");

                /* Dump the current "health" (use '*' symbols) */
                Term.putstr(col + 1, row, len, attr, "**********");
            }
        }
示例#4
0
        /**
         * Helper function used with ranged_helper by do_cmd_fire.
         */
        public static attack_result make_ranged_shot(Object.Object o_ptr, int y, int x)
        {
            attack_result result = new attack_result(false, 0, 0, "hit");

            Object.Object j_ptr = Misc.p_ptr.inventory[Misc.INVEN_BOW];

            Monster.Monster m_ptr = Cave.cave_monster(Cave.cave, Cave.cave.m_idx[y][x]);
            Monster_Race    r_ptr = Misc.r_info[m_ptr.r_idx];

            int bonus   = Misc.p_ptr.state.to_h + o_ptr.to_h + j_ptr.to_h;
            int chance  = Misc.p_ptr.state.skills[(int)Skill.TO_HIT_BOW] + bonus * Misc.BTH_PLUS_ADJ;
            int chance2 = chance - Cave.distance(Misc.p_ptr.py, Misc.p_ptr.px, y, x);

            int  multiplier = Misc.p_ptr.state.ammo_mult;
            Slay best_s_ptr = null;

            /* Did we hit it (penalize distance travelled) */
            if (!test_hit(chance2, r_ptr.ac, m_ptr.ml))
            {
                return(result);
            }

            result.success = true;

            Slay.improve_attack_modifier(o_ptr, m_ptr, ref best_s_ptr, true, false);
            Slay.improve_attack_modifier(j_ptr, m_ptr, ref best_s_ptr, true, false);

            /* If we have a slay, modify the multiplier appropriately */
            if (best_s_ptr != null)
            {
                result.hit_verb = best_s_ptr.range_verb;
                multiplier     += best_s_ptr.mult;
            }

            /* Apply damage: multiplier, slays, criticals, bonuses */
            result.dmg  = Random.damroll(o_ptr.dd, o_ptr.ds);
            result.dmg += o_ptr.to_d + j_ptr.to_d;
            result.dmg *= multiplier;
            result.dmg  = critical_shot(o_ptr.weight, o_ptr.to_h, result.dmg, ref result.msg_type);

            Misc.p_ptr.inventory[Misc.INVEN_BOW].notice_attack_plusses();

            return(result);
        }
示例#5
0
        /*
         * Hack -- compare the "strength" of two monsters XXX XXX XXX
         */
        static int compare_monsters(Monster m_ptr, Monster n_ptr)
        {
            Monster_Race r_ptr;

            int mexp1, mexp2;

            /* Race 1 */
            r_ptr = Misc.r_info[m_ptr.r_idx];

            /* Extract mexp */
            mexp1 = r_ptr.mexp;

            /* Race 2 */
            r_ptr = Misc.r_info[n_ptr.r_idx];

            /* Extract mexp */
            mexp2 = r_ptr.mexp;

            /* Compare */
            if (mexp1 < mexp2) return (-1);
            if (mexp1 > mexp2) return (1);

            /* Assume equal */
            return (0);
        }
示例#6
0
 internal void COPY(Monster n_ptr)
 {
     throw new NotImplementedException();
 }
示例#7
0
        /**
         * Place a copy of a monster in the dungeon XXX XXX
         */
        public static short place_monster(int y, int x, Monster n_ptr, byte origin)
        {
            short m_idx;

            Monster_Race r_ptr;

            /* Paranoia XXX XXX */
            if (Cave.cave.m_idx[y][x] != 0) return 0;

            /* Get a new record */
            m_idx = mon_pop();

            if (m_idx == 0) return 0;
            n_ptr.midx = m_idx;

            /* Make a new monster */
            Cave.cave.m_idx[y][x] = m_idx;

            /* Get the new monster */
            //m_ptr = Cave.cave_monster(Cave.cave, m_idx);

            /* Copy the monster XXX */
            //m_ptr.COPY(n_ptr);

            //Nick: Set the new monster... Much better than the above two steps...
            Cave.cave_monster_set(Cave.cave, m_idx, n_ptr);

            /* Location */
            n_ptr.fy = (byte)y;
            n_ptr.fx = (byte)x;

            /* Update the monster */
            Monster.update_mon(m_idx, true);

            /* Get the new race */
            r_ptr = Misc.r_info[n_ptr.r_idx];

            /* Hack -- Count the number of "reproducers" */
            if (r_ptr.flags.has(Monster_Flag.MULTIPLY.value)) Misc.num_repro++;

            /* Count racial occurances */
            r_ptr.cur_num++;

            /* Create the monster's drop, if any */
            if(origin != 0) {
                mon_create_drop(m_idx, origin);
            }

            /* Make mimics start mimicking */
            if (origin != 0 && r_ptr.mimic_kinds != null) {
                throw new NotImplementedException();
                //object_type *i_ptr;
                //object_type object_type_body;
                //object_kind *kind = r_ptr.mimic_kinds.kind;
                //struct monster_mimic *mimic_kind;
                //int i = 1;

                ///* Pick a random object kind to mimic */
                //for (mimic_kind = r_ptr.mimic_kinds; mimic_kind; mimic_kind = mimic_kind.next, i++) {
                //    if (one_in_(i)) kind = mimic_kind.kind;
                //}

                //i_ptr = &object_type_body;

                //if (kind.tval == TV_GOLD) {
                //    make_gold(i_ptr, p_ptr.depth, kind.sval);
                //} else {
                //    object_prep(i_ptr, kind, r_ptr.level, RANDOMISE);
                //    apply_magic(i_ptr, r_ptr.level, true, false, false);
                //    i_ptr.number = 1;
                //}

                //i_ptr.mimicking_m_idx = m_idx;
                //m_ptr.mimicked_o_idx = floor_carry(cave, y, x, i_ptr);
            }

            /* Result */
            return m_idx;
        }
示例#8
0
        /*
         * Attempt to place a monster of the given race at the given location.
         *
         * To give the player a sporting chance, any monster that appears in
         * line-of-sight and is extremely dangerous can be marked as
         * "FORCE_SLEEP", which will cause them to be placed with low energy,
         * which often (but not always) lets the player move before they do.
         *
         * This routine refuses to place out-of-depth "FORCE_DEPTH" monsters.
         *
         * XXX XXX XXX Use special "here" and "dead" flags for unique monsters,
         * remove old "cur_num" and "max_num" fields.
         *
         * XXX XXX XXX Actually, do something similar for artifacts, to simplify
         * the "preserve" mode, and to make the "what artifacts" flag more useful.
         *
         * This is the only function which may place a monster in the dungeon,
         * except for the savefile loading code.
         */
        static bool place_new_monster_one(int y, int x, int r_idx, bool slp, byte origin)
        {
            int i;

            Monster_Race r_ptr;
            Monster n_ptr;
            //Monster monster_type_body;

            string name;

            /* Paranoia */
            if (!Cave.in_bounds(y, x)) return (false);

            /* Require empty space */
            if (!Cave.cave_empty_bold(y, x)) return (false);

            /* No creation on glyph of warding */
            if (Cave.cave.feat[y][x] == Cave.FEAT_GLYPH) return (false);

            /* Paranoia */
            if (r_idx == 0) return (false);

            /* Race */
            r_ptr = Misc.r_info[r_idx];
            if (r_ptr == null) return (false);

            /* Paranoia */
            if (r_ptr.Name == null) return (false);

            name = r_ptr.Name;

            /* "unique" monsters must be "unique" */
            if (r_ptr.flags.has(Monster_Flag.UNIQUE.value) && r_ptr.cur_num >= r_ptr.max_num)
                return (false);

            /* Depth monsters may NOT be created out of depth */
            if (r_ptr.flags.has(Monster_Flag.FORCE_DEPTH.value) && Misc.p_ptr.depth < r_ptr.level)
                return (false);

            /* Add to level feeling */
            Cave.cave.mon_rating += (uint)(r_ptr.power / 20);

            /* Check out-of-depth-ness */
            if (r_ptr.level > Misc.p_ptr.depth) {
                if (r_ptr.flags.has(Monster_Flag.UNIQUE.value)) { /* OOD unique */
                    if (Option.cheat_hear.value)
                        Utilities.msg("Deep Unique (%s).", name);
                } else { /* Normal monsters but OOD */
                    if (Option.cheat_hear.value)
                        Utilities.msg("Deep Monster (%s).", name);
                }
                /* Boost rating by power per 10 levels OOD */
                Cave.cave.mon_rating += (uint)((r_ptr.level - Misc.p_ptr.depth) * r_ptr.power / 200);
            }
            /* Note uniques for cheaters */
            else if (r_ptr.flags.has(Monster_Flag.UNIQUE.value) && Option.cheat_hear.value)
                Utilities.msg("Unique (%s).", name);

            /* Get local monster */
            n_ptr = new Monster();//&monster_type_body;

            /* Clean out the monster */
            n_ptr.WIPE();
            //(void)WIPE(n_ptr, monster_type);

            /* Save the race */
            n_ptr.r_idx = (short)r_idx;

            /* Enforce sleeping if needed */
            if (slp && r_ptr.sleep != 0) {
                int val = r_ptr.sleep;
                n_ptr.m_timed[(int)Misc.MON_TMD.SLEEP] = (short)((val * 2) + Random.randint1(val * 10));
            }

            /* Uniques get a fixed amount of HP */
            if (r_ptr.flags.has(Monster_Flag.UNIQUE.value))
                n_ptr.maxhp = (short)r_ptr.avg_hp;
            else {
                n_ptr.maxhp = (short)mon_hp(r_ptr, aspect.RANDOMISE);
                n_ptr.maxhp = (short)Math.Max((int)n_ptr.maxhp, 1);
            }

            /* And start out fully healthy */
            n_ptr.hp = n_ptr.maxhp;

            /* Extract the monster base speed */
            n_ptr.mspeed = r_ptr.speed;

            /* Hack -- small racial variety */
            if (!r_ptr.flags.has(Monster_Flag.UNIQUE.value)) {
                /* Allow some small variation per monster */
                i = Misc.extract_energy[r_ptr.speed] / 10;
                if (i != 0) n_ptr.mspeed += (byte)Random.rand_spread(0, i);
            }

            /* Give a random starting energy */
            n_ptr.energy = (byte)Random.randint0(50);

            /* Force monster to wait for player */
            if (r_ptr.flags.has(Monster_Flag.FORCE_SLEEP.value))
                n_ptr.mflag |= (Monster_Flag.MFLAG_NICE);

            /* Radiate light? */
            if (r_ptr.flags.has(Monster_Flag.HAS_LIGHT.value))
                Misc.p_ptr.update |= Misc.PU_UPDATE_VIEW;

            /* Is this obviously a monster? (Mimics etc. aren't) */
            if (r_ptr.flags.has(Monster_Flag.UNAWARE.value))
                n_ptr.unaware = true;
            else
                n_ptr.unaware = false;

            /* Set the color if necessary */
            if (r_ptr.flags.has(Monster_Flag.ATTR_RAND.value))
                n_ptr.attr = Utilities.num_to_attr(Random.randint1(Enum.GetValues(typeof(ConsoleColor)).Length - 1));

            /* Place the monster in the dungeon */
            if (place_monster(y, x, n_ptr, origin) == 0)
                return (false);

            /* Success */
            return (true);
        }
示例#9
0
 static int mdam(Monster.Monster m)
 {
     return m.Race.blow[0].d_dice;
 }
示例#10
0
        /*
         * Update the current "run" path
         *
         * Return true if the running should be stopped
         */
        static bool run_test()
        {
            int py = Misc.p_ptr.py;
            int px = Misc.p_ptr.px;

            int prev_dir;
            int new_dir;

            int  row, col;
            int  i, max;
            bool inv;
            int  option, option2;


            /* No options yet */
            option  = 0;
            option2 = 0;

            /* Where we came from */
            prev_dir = Misc.p_ptr.run_old_dir;


            /* Range of newly adjacent grids */
            max = (prev_dir & 0x01) + 1;


            /* Look at every newly adjacent square. */
            for (i = -max; i <= max; i++)
            {
                Object.Object o_ptr;


                /* New direction */
                new_dir = cycle[chome[prev_dir] + i];

                /* New location */
                row = py + Misc.ddy[new_dir];
                col = px + Misc.ddx[new_dir];


                /* Visible monsters abort running */
                if (Cave.cave.m_idx[row][col] > 0)
                {
                    Monster.Monster m_ptr = Cave.cave_monster(Cave.cave, Cave.cave.m_idx[row][col]);

                    /* Visible monster */
                    if (m_ptr.ml)
                    {
                        return(true);
                    }
                }

                /* Visible objects abort running */
                for (o_ptr = Object.Object.get_first_object(row, col); o_ptr != null; o_ptr = Object.Object.get_next_object(o_ptr))
                {
                    /* Visible object */
                    if (o_ptr.marked != 0 && !Squelch.item_ok(o_ptr))
                    {
                        return(true);
                    }
                }


                /* Assume unknown */
                inv = true;

                /* Check memorized grids */
                if ((Cave.cave.info[row][col] & (Cave.CAVE_MARK)) != 0)
                {
                    bool notice = true;

                    /* Examine the terrain */
                    switch (Cave.cave.feat[row][col])
                    {
                    /* Floors */
                    case Cave.FEAT_FLOOR:

                    /* Invis traps */
                    case Cave.FEAT_INVIS:

                    /* Secret doors */
                    case Cave.FEAT_SECRET:

                    /* Normal veins */
                    case Cave.FEAT_MAGMA:
                    case Cave.FEAT_QUARTZ:

                    /* Hidden treasure */
                    case Cave.FEAT_MAGMA_H:
                    case Cave.FEAT_QUARTZ_H:

                    /* Walls */
                    case Cave.FEAT_WALL_EXTRA:
                    case Cave.FEAT_WALL_INNER:
                    case Cave.FEAT_WALL_OUTER:
                    case Cave.FEAT_WALL_SOLID:
                    case Cave.FEAT_PERM_EXTRA:
                    case Cave.FEAT_PERM_INNER:
                    case Cave.FEAT_PERM_OUTER:
                    case Cave.FEAT_PERM_SOLID:
                    {
                        /* Ignore */
                        notice = false;

                        /* Done */
                        break;
                    }
                    }

                    /* Interesting feature */
                    if (notice)
                    {
                        return(true);
                    }

                    /* The grid is "visible" */
                    inv = false;
                }

                /* Analyze unknown grids and floors */
                if (inv || Cave.cave_floor_bold(row, col))
                {
                    /* Looking for open area */
                    if (Misc.p_ptr.run_open_area)
                    {
                        /* Nothing */
                    }

                    /* The first new direction. */
                    else if (option == 0)
                    {
                        option = new_dir;
                    }

                    /* Three new directions. Stop running. */
                    else if (option2 != 0)
                    {
                        return(true);
                    }

                    /* Two non-adjacent new directions.  Stop running. */
                    else if (option != cycle[chome[prev_dir] + i - 1])
                    {
                        return(true);
                    }

                    /* Two new (adjacent) directions (case 1) */
                    else if ((new_dir & 0x01) != 0)
                    {
                        option2 = new_dir;
                    }

                    /* Two new (adjacent) directions (case 2) */
                    else
                    {
                        option2 = option;
                        option  = new_dir;
                    }
                }

                /* Obstacle, while looking for open area */
                else
                {
                    if (Misc.p_ptr.run_open_area)
                    {
                        if (i < 0)
                        {
                            /* Break to the right */
                            Misc.p_ptr.run_break_right = true;
                        }

                        else if (i > 0)
                        {
                            /* Break to the left */
                            Misc.p_ptr.run_break_left = true;
                        }
                    }
                }
            }


            /* Look at every soon to be newly adjacent square. */
            for (i = -max; i <= max; i++)
            {
                /* New direction */
                new_dir = cycle[chome[prev_dir] + i];

                /* New location */
                row = py + Misc.ddy[prev_dir] + Misc.ddy[new_dir];
                col = px + Misc.ddx[prev_dir] + Misc.ddx[new_dir];

                /* HACK: Ugh. Sometimes we come up with illegal bounds. This will
                 * treat the symptom but not the disease. */
                if (row >= Cave.DUNGEON_HGT || col >= Cave.DUNGEON_WID)
                {
                    continue;
                }
                if (row < 0 || col < 0)
                {
                    continue;
                }

                /* Visible monsters abort running */
                if (Cave.cave.m_idx[row][col] > 0)
                {
                    Monster.Monster m_ptr = Cave.cave_monster(Cave.cave, Cave.cave.m_idx[row][col]);

                    /* Visible monster */
                    if (m_ptr.ml)
                    {
                        return(true);
                    }
                }
            }

            /* Looking for open area */
            if (Misc.p_ptr.run_open_area)
            {
                /* Hack -- look again */
                for (i = -max; i < 0; i++)
                {
                    new_dir = cycle[chome[prev_dir] + i];

                    row = py + Misc.ddy[new_dir];
                    col = px + Misc.ddx[new_dir];

                    /* Unknown grid or non-wall */
                    /* Was: cave_floor_bold(row, col) */
                    if ((Cave.cave.info[row][col] & (Cave.CAVE_MARK)) == 0 ||
                        (Cave.cave.feat[row][col] < Cave.FEAT_SECRET))
                    {
                        /* Looking to break right */
                        if (Misc.p_ptr.run_break_right)
                        {
                            return(true);
                        }
                    }

                    /* Obstacle */
                    else
                    {
                        /* Looking to break left */
                        if (Misc.p_ptr.run_break_left)
                        {
                            return(true);
                        }
                    }
                }

                /* Hack -- look again */
                for (i = max; i > 0; i--)
                {
                    new_dir = cycle[chome[prev_dir] + i];

                    row = py + Misc.ddy[new_dir];
                    col = px + Misc.ddx[new_dir];

                    /* Unknown grid or non-wall */
                    /* Was: cave_floor_bold(row, col) */
                    if ((Cave.cave.info[row][col] & (Cave.CAVE_MARK)) == 0 ||
                        (Cave.cave.feat[row][col] < Cave.FEAT_SECRET))
                    {
                        /* Looking to break left */
                        if (Misc.p_ptr.run_break_left)
                        {
                            return(true);
                        }
                    }

                    /* Obstacle */
                    else
                    {
                        /* Looking to break right */
                        if (Misc.p_ptr.run_break_right)
                        {
                            return(true);
                        }
                    }
                }
            }


            /* Not looking for open area */
            else
            {
                /* No options */
                if (option == 0)
                {
                    return(true);
                }

                /* One option */
                else if (option2 == 0)
                {
                    /* Primary option */
                    Misc.p_ptr.run_cur_dir = (short)option;

                    /* No other options */
                    Misc.p_ptr.run_old_dir = (short)option;
                }

                /* Two options, examining corners */
                else
                {
                    /* Primary option */
                    Misc.p_ptr.run_cur_dir = (short)option;

                    /* Hack -- allow curving */
                    Misc.p_ptr.run_old_dir = (short)option2;
                }
            }


            /* About to hit a known wall, stop */
            if (see_wall(Misc.p_ptr.run_cur_dir, py, px))
            {
                return(true);
            }


            /* Failure */
            return(false);
        }
示例#11
0
        /*
         * Calculate the monster bar color separately, for ports.
         */
        static ConsoleColor monster_health_attr()
        {
            ConsoleColor attr = ConsoleColor.White;

            /* Not tracking */
            if (Misc.p_ptr.health_who == 0)
            {
                attr = ConsoleColor.Gray;            //TERM_DARK;
            }
            /* Tracking an unseen, hallucinatory, or dead monster */
            else if ((!Cave.cave_monster(Cave.cave, Misc.p_ptr.health_who).ml) ||
                     (Misc.p_ptr.timed[(int)Timed_Effect.IMAGE]) != 0 ||
                     (Cave.cave_monster(Cave.cave, Misc.p_ptr.health_who).hp < 0))
            {
                /* The monster health is "unknown" */
                attr = ConsoleColor.White;
            }

            else
            {
                Monster.Monster mon = Cave.cave_monster(Cave.cave, Misc.p_ptr.health_who);
                int             pct;

                /* Default to almost dead */
                attr = ConsoleColor.Red;

                /* Extract the "percent" of health */
                pct = (int)(100L * mon.hp / mon.maxhp);

                /* Badly wounded */
                if (pct >= 10)
                {
                    attr = ConsoleColor.Red;
                }

                /* Wounded */
                if (pct >= 25)
                {
                    attr = ConsoleColor.DarkYellow;
                }

                /* Somewhat Wounded */
                if (pct >= 60)
                {
                    attr = ConsoleColor.Yellow;
                }

                /* Healthy */
                if (pct >= 100)
                {
                    attr = ConsoleColor.Green;
                }

                /* Afraid */
                if (mon.m_timed[(int)Misc.MON_TMD.FEAR] != 0)
                {
                    attr = ConsoleColor.Magenta;
                }

                /* Confused */
                if (mon.m_timed[(int)Misc.MON_TMD.CONF] != 0)
                {
                    attr = ConsoleColor.DarkRed;                                                       //UMBER
                }
                /* Stunned */
                if (mon.m_timed[(int)Misc.MON_TMD.STUN] != 0)
                {
                    attr = ConsoleColor.Blue;                                                       //Light Blue
                }
                /* Asleep */
                if (mon.m_timed[(int)Misc.MON_TMD.SLEEP] != 0)
                {
                    attr = ConsoleColor.DarkBlue;                                                        //Blue
                }
            }

            return(attr);
        }
示例#12
0
 /**
  * Set a monster on the current level by its index.
  */
 public static void cave_monster_set(Cave c, int idx, Monster.Monster m)
 {
     c.monsters[idx] = m;
 }
示例#13
0
        /**
         * Attempts to set the timer of the given monster effect to `timer`.
         *
         * Checks to see if the monster resists the effect, using mon_resist_effect().
         * If not, the effect is set to `timer` turns. If `timer` is 0, or if the
         * effect timer was 0, or if MON_TMD_FLG_NOTIFY is set in `flag`, then a
         * message is printed, unless MON_TMD_FLG_NOMESSAGE is set in `flag`.
         *
         * Set a timed monster event to 'v'.  Give messages if the right flags are set.
         * Check if the monster is able to resist the spell.  Mark the lore.
         * Returns true if the monster was affected.
         * Return false if the monster was unaffected.
         */
        static bool mon_set_timed(Monster m_ptr, Misc.MON_TMD ef_idx, int timer, ushort flag, bool id)
        {
            mon_timed_effect effect;

            MON_MSG m_note = 0;
            int resisted;
            int old_timer;

            Misc.assert(ef_idx >= 0 && ef_idx < Misc.MON_TMD.MAX);
            effect = effects[(int)ef_idx];

            Misc.assert(m_ptr != null);
            old_timer = m_ptr.m_timed[(int)ef_idx];

            /* Ignore dead monsters */
            if (m_ptr.r_idx == 0) return false;

            /* No change */
            if (old_timer == timer) return false;

            if (timer == 0) {
                /* Turning off, usually mention */
                m_note = effect.message_end;
                flag |= Misc.MON_TMD_FLG_NOTIFY;
            } else if (old_timer == 0) {
                /* Turning on, usually mention */
                flag |= Misc.MON_TMD_FLG_NOTIFY;
                m_note = effect.message_begin;
            } else if (timer > old_timer) {
                /* Different message for increases, but don't automatically mention. */
                m_note = effect.message_increase;
            }

            /* Determine if the monster resisted or not */
            resisted = mon_resist_effect(m_ptr, ef_idx, timer, flag)?1:0;

            if (resisted != 0)
                m_note = MON_MSG.UNAFFECTED;
            else
                m_ptr.m_timed[(int)ef_idx] = (short)timer;

            if (Misc.p_ptr.health_who == m_ptr.midx) Misc.p_ptr.redraw |= (Misc.PR_HEALTH);

            /* Update the visuals, as appropriate. */
            Misc.p_ptr.redraw |= (Misc.PR_MONLIST);

            /* Print a message if there is one, if the effect allows for it, and if
             * either the monster is visible, or we're trying to ID something */
            if (m_note != 0 && (m_ptr.ml || id) && (flag & Misc.MON_TMD_FLG_NOMESSAGE) == 0 && (flag & Misc.MON_TMD_FLG_NOTIFY) != 0) {
                //char m_name[80];
                string m_name;

                m_name = m_ptr.monster_desc((Desc)0x04);
                Monster_Message.add_monster_message(m_name, m_ptr.midx, m_note, true);
            }

            return resisted == 0;
        }
示例#14
0
        /**
         * Determines whether the given monster successfully resists the given effect.
         *
         * If MON_TMD_FLG_NOFAIL is set in `flag`, this returns false.
         * Then we determine if the monster resists the effect for some racial
         * reason. For example, the monster might have the NO_SLEEP flag, in which
         * case it always resists sleep. Or if it breathes chaos, it always resists
         * confusion. If the given monster doesn't resist for any of these reasons,
         * then it makes a saving throw. If MON_TMD_MON_SOURCE is set in `flag`,
         * indicating that another monster caused this effect, then the chance of
         * success on the saving throw just depends on the monster's native depth.
         * Otherwise, the chance of success decreases as `timer` increases.
         *
         * Also marks the lore for any appropriate resists.
         */
        static bool mon_resist_effect(Monster m_ptr, Misc.MON_TMD ef_idx, int timer, ushort flag)
        {
            mon_timed_effect effect;
            int resist_chance;
            Monster_Race r_ptr;
            Monster_Lore l_ptr;

            Misc.assert(ef_idx >= 0 && ef_idx < Misc.MON_TMD.MAX);
            effect = effects[(int)ef_idx];

            Misc.assert(m_ptr != null);
            r_ptr = Misc.r_info[m_ptr.r_idx];
            l_ptr = Misc.l_list[m_ptr.r_idx];

            /* Hasting never fails */
            if (ef_idx == Misc.MON_TMD.FAST) return (false);

            /* Some effects are marked to never fail */
            if ((flag & Misc.MON_TMD_FLG_NOFAIL) != 0) return (false);

            /* A sleeping monster resists further sleeping */
            if (ef_idx == (int)Misc.MON_TMD.SLEEP && m_ptr.m_timed[(int)ef_idx] != 0) return (true);

            /* If the monster resists innately, learn about it */
            if (r_ptr.flags.has((int)effect.flag_resist)) {
                if (m_ptr.ml)
                    l_ptr.flags.on((int)effect.flag_resist);

                return (true);
            }

            /* Monsters with specific breaths resist stunning*/
            if (ef_idx == Misc.MON_TMD.STUN && (r_ptr.spell_flags.has(Monster_Spell_Flag.BR_SOUN.value) ||
                    r_ptr.spell_flags.has(Monster_Spell_Flag.BR_WALL.value)))
            {
                /* Add the lore */
                if (m_ptr.ml)
                {
                    if (r_ptr.spell_flags.has(Monster_Spell_Flag.BR_SOUN.value))
                        l_ptr.spell_flags.on(Monster_Spell_Flag.BR_SOUN.value);
                    if (r_ptr.spell_flags.has(Monster_Spell_Flag.BR_WALL.value))
                        l_ptr.spell_flags.on(Monster_Spell_Flag.BR_WALL.value);
                }

                return (true);
            }

            /* Monsters with specific breaths resist confusion */
            if ((ef_idx == Misc.MON_TMD.CONF) &&
                ((r_ptr.spell_flags.has(Monster_Spell_Flag.BR_CHAO.value)) ||
                 (r_ptr.spell_flags.has(Monster_Spell_Flag.BR_CONF.value))) )
            {
                /* Add the lore */
                if (m_ptr.ml)
                {
                    if (r_ptr.spell_flags.has(Monster_Spell_Flag.BR_CHAO.value))
                        l_ptr.spell_flags.on(Monster_Spell_Flag.BR_CHAO.value);
                    if (r_ptr.spell_flags.has(Monster_Spell_Flag.BR_CONF.value))
                        l_ptr.spell_flags.on(Monster_Spell_Flag.BR_CONF.value);
                }

                return (true);
            }

            /* Inertia breathers resist slowing */
            if (ef_idx == Misc.MON_TMD.SLOW && r_ptr.spell_flags.has(Monster_Spell_Flag.BR_INER.value))
            {
                l_ptr.spell_flags.on(Monster_Spell_Flag.BR_INER.value);
                return (true);
            }

            /* Calculate the chance of the monster making its saving throw. */
            if (ef_idx == (int)Misc.MON_TMD.SLEEP)
                timer /= 25; /* Hack - sleep uses much bigger numbers */

            if ((flag & (int)Misc.MON_TMD_MON_SOURCE) != 0)
                resist_chance = r_ptr.level;
            else
                resist_chance = r_ptr.level + 40 - (timer / 2);

            if (Random.randint0(100) < resist_chance) return (true);

            /* Uniques are doubly hard to affect */
            if (r_ptr.flags.has(Monster_Flag.UNIQUE.value))
                if (Random.randint0(100) < resist_chance) return (true);

            return (false);
        }
示例#15
0
        /**
         * This is a helper function used by do_cmd_throw and do_cmd_fire.
         *
         * It abstracts out the projectile path, display code, identify and clean up
         * logic, while using the 'attack' parameter to do work particular to each
         * kind of attack.
         */
        public static void ranged_helper(int item, int dir, int range, int shots, ranged_attack attack)
        {
            /* Get the ammo */
            Object.Object o_ptr = Object.Object.object_from_item_idx(item);

            int          i, j;
            ConsoleColor missile_attr = o_ptr.object_attr();
            char         missile_char = o_ptr.object_char();

            //object_type object_type_body;
            Object.Object i_ptr = new Object.Object();            //&object_type_body;

            //char o_name[80];
            string o_name;

            int           path_n;
            List <ushort> path_g = new List <ushort>();          //[256];

            int msec = Player.Player_Other.instance.delay_factor;

            /* Start at the player */
            int x = Misc.p_ptr.px;
            int y = Misc.p_ptr.py;

            /* Predict the "target" location */
            short ty = (short)(y + 99 * Misc.ddy[dir]);
            short tx = (short)(x + 99 * Misc.ddx[dir]);

            bool hit_target = false;

            /* Check for target validity */
            if ((dir == 5) && Target.okay())
            {
                int taim;
                //char msg[80];
                string msg;
                Target.get(out tx, out ty);
                taim = Cave.distance(y, x, ty, tx);
                if (taim > range)
                {
                    msg = String.Format("Target out of range by {0} squares. Fire anyway? ", taim - range);
                    if (!Utilities.get_check(msg))
                    {
                        return;
                    }
                }
            }

            /* Sound */
            //sound(MSG_SHOOT); //later

            o_ptr.notice_on_firing();

            /* Describe the object */
            o_name = o_ptr.object_desc(Object.Object.Detail.FULL | Object.Object.Detail.SINGULAR);

            /* Actually "fire" the object -- Take a partial turn */
            Misc.p_ptr.energy_use = (short)(100 / shots);

            /* Calculate the path */
            path_n = Cave.project_path(out path_g, range, y, x, ty, tx, 0);

            /* Hack -- Handle stuff */
            Misc.p_ptr.handle_stuff();

            /* Start at the player */
            x = Misc.p_ptr.px;
            y = Misc.p_ptr.py;

            /* Project along the path */
            for (i = 0; i < path_n; ++i)
            {
                int ny = Cave.GRID_Y(path_g[i]);
                int nx = Cave.GRID_X(path_g[i]);

                /* Hack -- Stop before hitting walls */
                if (!Cave.cave_floor_bold(ny, nx))
                {
                    break;
                }

                /* Advance */
                x = nx;
                y = ny;

                /* Only do visuals if the player can "see" the missile */
                if (Cave.player_can_see_bold(y, x))
                {
                    Cave.print_rel(missile_char, missile_attr, y, x);
                    Cave.move_cursor_relative(y, x);

                    Term.fresh();
                    if (Misc.p_ptr.redraw != 0)
                    {
                        Misc.p_ptr.redraw_stuff();
                    }

                    Term.xtra(TERM_XTRA.DELAY, msec);
                    Cave.cave_light_spot(Cave.cave, y, x);

                    Term.fresh();
                    if (Misc.p_ptr.redraw != 0)
                    {
                        Misc.p_ptr.redraw_stuff();
                    }
                }
                else
                {
                    /* Delay anyway for consistency */
                    Term.xtra(TERM_XTRA.DELAY, msec);
                }

                /* Handle monster */
                if (Cave.cave.m_idx[y][x] > 0)
                {
                    break;
                }
            }

            /* Try the attack on the monster at (x, y) if any */
            if (Cave.cave.m_idx[y][x] > 0)
            {
                Monster.Monster m_ptr   = Cave.cave_monster(Cave.cave, Cave.cave.m_idx[y][x]);
                Monster_Race    r_ptr   = Misc.r_info[m_ptr.r_idx];
                bool            visible = m_ptr.ml;

                bool fear = false;
                //char m_name[80];
                string m_name;
                string note_dies = r_ptr.monster_is_unusual() ? " is destroyed." : " dies.";

                attack_result result   = attack(o_ptr, y, x);
                int           dmg      = result.dmg;
                Message_Type  msg_type = result.msg_type;
                string        hit_verb = result.hit_verb;

                if (result.success)
                {
                    hit_target = true;

                    /* Get "the monster" or "it" */
                    m_name = m_ptr.monster_desc(0);

                    o_ptr.notice_attack_plusses();

                    /* No negative damage; change verb if no damage done */
                    if (dmg <= 0)
                    {
                        dmg      = 0;
                        hit_verb = "fail to harm";
                    }

                    if (!visible)
                    {
                        /* Invisible monster */
                        Utilities.msgt(Message_Type.MSG_SHOOT_HIT, "The {0} finds a mark.", o_name);
                    }
                    else
                    {
                        /* Visible monster */
                        if ((Message_Type)msg_type == Message_Type.MSG_SHOOT_HIT)
                        {
                            Utilities.msgt(Message_Type.MSG_SHOOT_HIT, "The {0} {1} {2}.", o_name, hit_verb, m_name);
                        }
                        else if ((Message_Type)msg_type == Message_Type.MSG_HIT_GOOD)
                        {
                            Utilities.msgt(Message_Type.MSG_HIT_GOOD, "The {0} {1} {2}. {3}", o_name, hit_verb, m_name,
                                           "It was a good hit!");
                        }
                        else if ((Message_Type)msg_type == Message_Type.MSG_HIT_GREAT)
                        {
                            Utilities.msgt(Message_Type.MSG_HIT_GREAT, "The {0} {1} {2}. {3}", o_name, hit_verb, m_name,
                                           "It was a great hit!");
                        }
                        else if ((Message_Type)msg_type == Message_Type.MSG_HIT_SUPERB)
                        {
                            Utilities.msgt(Message_Type.MSG_HIT_SUPERB, "The {0} {1} {2}. {3}", o_name, hit_verb, m_name,
                                           "It was a superb hit!");
                        }

                        /* Track this monster */
                        if (m_ptr.ml)
                        {
                            Cave.monster_race_track(m_ptr.r_idx);
                        }
                        if (m_ptr.ml)
                        {
                            Cave.health_track(Misc.p_ptr, Cave.cave.m_idx[y][x]);
                        }
                    }

                    /* Complex message */
                    if (Misc.p_ptr.wizard)
                    {
                        Utilities.msg("You do {0} (out of {1}) damage.", dmg, m_ptr.hp);
                    }

                    /* Hit the monster, check for death */
                    if (!Monster_Make.mon_take_hit(Cave.cave.m_idx[y][x], dmg, ref fear, note_dies))
                    {
                        Monster_Message.message_pain(Cave.cave.m_idx[y][x], dmg);
                        if (fear && m_ptr.ml)
                        {
                            Monster_Message.add_monster_message(m_name, Cave.cave.m_idx[y][x], MON_MSG.FLEE_IN_TERROR, true);
                        }
                    }
                }
            }

            /* Obtain a local object */
            i_ptr = o_ptr.copy();
            i_ptr.split(o_ptr, 1);

            /* See if the ammunition broke or not */
            j = i_ptr.breakage_chance(hit_target);

            /* Drop (or break) near that location */
            Object.Object.drop_near(Cave.cave, i_ptr, j, y, x, true);

            if (item >= 0)
            {
                /* The ammo is from the inventory */
                Object.Object.inven_item_increase(item, -1);
                Object.Object.inven_item_describe(item);
                Object.Object.inven_item_optimize(item);
            }
            else
            {
                /* The ammo is from the floor */
                Object.Object.floor_item_increase(0 - item, -1);
                Object.Object.floor_item_optimize(0 - item);
            }
        }
示例#16
0
 static int take1(Player.Player p, Monster.Monster m, RBM blow, RBE eff)
 {
     int oldv, newv;
     m.Race.blow[0].effect = eff;
     m.Race.blow[0].method = blow;
     p.chp = p.mhp;
     oldv = p.chp;
     m.make_attack_normal(p);
     newv = p.chp;
     p.chp = p.mhp;
     return oldv - newv;
 }
示例#17
0
        /**
         * Attack the monster at the given location with a single blow.
         */
        static bool py_attack_real(int y, int x, ref bool fear)
        {
            /* Information about the target of the attack */
            Monster.Monster m_ptr = Cave.cave_monster(Cave.cave, Cave.cave.m_idx[y][x]);
            Monster_Race    r_ptr = Misc.r_info[m_ptr.r_idx];
            //char m_name[80];
            string m_name;
            bool   stop = false;

            /* The weapon used */
            Object.Object o_ptr = Misc.p_ptr.inventory[Misc.INVEN_WIELD];

            /* Information about the attack */
            int  bonus    = Misc.p_ptr.state.to_h + o_ptr.to_h;
            int  chance   = Misc.p_ptr.state.skills[(int)Skill.TO_HIT_MELEE] + bonus * Misc.BTH_PLUS_ADJ;
            bool do_quake = false;
            bool success  = false;

            /* Default to punching for one damage */
            string       hit_verb = "punch";
            int          dmg      = 1;
            Message_Type msg_type = Message_Type.MSG_HIT;

            /* Extract monster name (or "it") */
            m_name = m_ptr.monster_desc(0);

            /* Auto-Recall if possible and visible */
            if (m_ptr.ml)
            {
                Cave.monster_race_track(m_ptr.r_idx);
            }

            /* Track a new monster */
            if (m_ptr.ml)
            {
                Cave.health_track(Misc.p_ptr, Cave.cave.m_idx[y][x]);
            }

            /* Handle player fear (only for invisible monsters) */
            if (Misc.p_ptr.check_state(Object_Flag.AFRAID, Misc.p_ptr.state.flags))
            {
                Utilities.msgt(Message_Type.MSG_AFRAID, "You are too afraid to attack {0}!", m_name);
                return(false);
            }

            /* Disturb the monster */
            Monster.Monster.mon_clear_timed(Cave.cave.m_idx[y][x], (int)Misc.MON_TMD.SLEEP, Misc.MON_TMD_FLG_NOMESSAGE, false);

            /* See if the player hit */
            success = test_hit(chance, (int)r_ptr.ac, m_ptr.ml);

            /* If a miss, skip this hit */
            if (!success)
            {
                Utilities.msgt(Message_Type.MSG_MISS, "You miss {0}.", m_name);
                return(false);
            }

            /* Handle normal weapon */
            if (o_ptr.kind != null)
            {
                int  i;
                Slay best_s_ptr = null;

                hit_verb = "hit";

                /* Get the best attack from all slays or
                 * brands on all non-launcher equipment */
                for (i = Misc.INVEN_LEFT; i < Misc.INVEN_TOTAL; i++)
                {
                    Object.Object obj = Misc.p_ptr.inventory[i];
                    if (obj.kind != null)
                    {
                        Slay.improve_attack_modifier(obj, m_ptr, ref best_s_ptr, true, false);
                    }
                }

                Slay.improve_attack_modifier(o_ptr, m_ptr, ref best_s_ptr, true, false);
                if (best_s_ptr != null)
                {
                    hit_verb = best_s_ptr.melee_verb;
                }

                dmg  = Random.damroll(o_ptr.dd, o_ptr.ds);
                dmg *= (best_s_ptr == null) ? 1 : best_s_ptr.mult;

                dmg += o_ptr.to_d;
                dmg  = critical_norm(o_ptr.weight, o_ptr.to_h, dmg, ref msg_type);

                /* Learn by use for the weapon */
                o_ptr.notice_attack_plusses();

                if (Misc.p_ptr.check_state(Object_Flag.IMPACT, Misc.p_ptr.state.flags) && dmg > 50)
                {
                    do_quake = true;
                    Object.Object.wieldeds_notice_flag(Misc.p_ptr, Object_Flag.IMPACT.value);
                }
            }

            /* Learn by use for other equipped items */
            Object.Object.wieldeds_notice_on_attack();

            /* Apply the player damage bonuses */
            dmg += Misc.p_ptr.state.to_d;

            /* No negative damage */
            if (dmg <= 0)
            {
                dmg = 0;
            }

            /* Tell the player what happened */
            if (dmg <= 0)
            {
                Utilities.msgt(Message_Type.MSG_MISS, "You fail to harm {0}.", m_name);
            }
            else if (msg_type == Message_Type.MSG_HIT)
            {
                Utilities.msgt(Message_Type.MSG_HIT, "You {0} {1}.", hit_verb, m_name);
            }
            else if (msg_type == Message_Type.MSG_HIT_GOOD)
            {
                Utilities.msgt(Message_Type.MSG_HIT_GOOD, "You {0} {1}. {2}", hit_verb, m_name, "It was a good hit!");
            }
            else if (msg_type == Message_Type.MSG_HIT_GREAT)
            {
                Utilities.msgt(Message_Type.MSG_HIT_GREAT, "You {0} {1}. {2}", hit_verb, m_name, "It was a great hit!");
            }
            else if (msg_type == Message_Type.MSG_HIT_SUPERB)
            {
                Utilities.msgt(Message_Type.MSG_HIT_SUPERB, "You {0} {1}. {2}", hit_verb, m_name, "It was a superb hit!");
            }
            else if (msg_type == Message_Type.MSG_HIT_HI_GREAT)
            {
                Utilities.msgt(Message_Type.MSG_HIT_HI_GREAT, "You {0} {1}. {2}", hit_verb, m_name, "It was a *GREAT* hit!");
            }
            else if (msg_type == Message_Type.MSG_HIT_HI_SUPERB)
            {
                Utilities.msgt(Message_Type.MSG_HIT_HI_SUPERB, "You {0} {1}. {2}", hit_verb, m_name, "It was a *SUPERB* hit!");
            }

            /* Complex message */
            if (Misc.p_ptr.wizard)
            {
                Utilities.msg("You do {0} (out of {1}) damage.", dmg, m_ptr.hp);
            }

            /* Confusion attack */
            if (Misc.p_ptr.confusing != 0)
            {
                Misc.p_ptr.confusing = 0;                //false;
                Utilities.msg("Your hands stop glowing.");

                Monster.Monster.mon_inc_timed(Cave.cave.m_idx[y][x], Misc.MON_TMD.CONF,
                                              (10 + Random.randint0(Misc.p_ptr.lev) / 10), Misc.MON_TMD_FLG_NOTIFY, false);
            }

            /* Damage, check for fear and death */
            stop = Monster.Monster_Make.mon_take_hit(Cave.cave.m_idx[y][x], dmg, ref fear, null);

            if (stop)
            {
                fear = false;
            }

            /* Apply earthquake brand */
            if (do_quake)
            {
                throw new NotImplementedException();
                //earthquake(Misc.p_ptr.py, Misc.p_ptr.px, 10);
                //if (Cave.cave.m_idx[y][x] == 0) stop = true;
            }

            return(stop);
        }
示例#18
0
        /**
         * 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;
                }
            }
        }