Example #1
0
        /**
         * Clears the timed effect `ef_idx`.
         *
         * Returns true if the monster's timer was changed.
         */
        public static bool mon_clear_timed(int m_idx, Misc.MON_TMD ef_idx, ushort flag, bool id)
        {
            Monster m_ptr;

            Misc.assert(ef_idx >= 0 && ef_idx < Misc.MON_TMD.MAX);

            Misc.assert(m_idx > 0);
            m_ptr = Cave.cave_monster(Cave.cave, m_idx);

            if (m_ptr.m_timed[(int)ef_idx] == 0)
            {
                return(false);
            }

            /* Clearing never fails */
            flag |= Misc.MON_TMD_FLG_NOFAIL;

            return(mon_set_timed(m_ptr, ef_idx, 0, flag, id));
        }
Example #2
0
        /**
         * Increases the timed effect `ef_idx` by `timer`.
         *
         * Calculates the new timer, then passes that to mon_set_timed().
         * Note that each effect has a maximum number of turns it can be active for.
         * If this function would put an effect timer over that cap, it sets it for
         * that cap instead.
         *
         * Returns true if the monster's timer changed.
         */
        public static bool mon_inc_timed(int m_idx, Misc.MON_TMD ef_idx, int timer, ushort flag, bool id)
        {
            Monster          m_ptr;
            mon_timed_effect effect;

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

            Misc.assert(m_idx > 0);
            m_ptr = Cave.cave_monster(Cave.cave, m_idx);

            /* For negative amounts, we use mon_dec_timed instead */
            Misc.assert(timer > 0);

            /* Make it last for a mimimum # of turns if it is a new effect */
            if ((m_ptr.m_timed[(int)ef_idx] == 0) && (timer < 2))
            {
                timer = 2;
            }

            /* New counter amount - prevent overflow */
            if (short.MaxValue - timer < m_ptr.m_timed[(int)ef_idx])
            {
                timer = short.MaxValue;
            }
            else
            {
                timer += m_ptr.m_timed[(int)ef_idx];
            }

            /* Reduce to max_timer if necessary*/
            if (timer > effect.max_timer)
            {
                timer = effect.max_timer;
            }

            return(mon_set_timed(m_ptr, ef_idx, timer, flag, id));
        }
Example #3
0
        /**
         * Decreases the timed effect `ef_idx` by `timer`.
         *
         * Calculates the new timer, then passes that to mon_set_timed().
         * If a timer would be set to a negative number, it is set to 0 instead.
         * Note that decreasing a timed effect should never fail.
         *
         * Returns true if the monster's timer changed.
         */
        public static bool mon_dec_timed(int m_idx, Misc.MON_TMD ef_idx, int timer, ushort flag, bool id)
        {
            Monster m_ptr;

            Misc.assert(ef_idx >= 0 && ef_idx < Misc.MON_TMD.MAX);

            Misc.assert(m_idx > 0);
            m_ptr = Cave.cave_monster(Cave.cave, m_idx);

            Misc.assert(timer > 0);

            /* Decreasing is never resisted */
            flag |= Misc.MON_TMD_FLG_NOFAIL;

            /* New counter amount */
            timer = m_ptr.m_timed[(int)ef_idx] - timer;
            if (timer < 0)
            {
                timer = 0;
            }

            return(mon_set_timed(m_ptr, ef_idx, timer, flag, id));
        }
Example #4
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);
        }
Example #5
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);
        }