Пример #1
0
        /**
         * Notice curses on an object.
         *
         * \param o_ptr is the object to notice curses on
         */
        bool notice_curses()
        {
            Bitflag f  = new Bitflag(Object_Flag.SIZE);
            Bitflag f2 = new Bitflag(Object_Flag.SIZE);

            object_flags(ref f);

            /* Gather whatever curse flags there are to know */
            Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.CURSE);

            /* Remove everything except the curse flags */
            f.inter(f2);

            /* give knowledge of which curses are present */
            notice_flags(f);

            check_for_ident();

            Misc.p_ptr.notice |= Misc.PN_SQUELCH;

            return(!f.is_empty());
        }
Пример #2
0
        /*
         * 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);
        }
Пример #3
0
        /*
         * Creatures can cast spells, shoot missiles, and breathe.
         *
         * Returns "true" if a spell (or whatever) was (successfully) cast.
         *
         * XXX XXX XXX This function could use some work, but remember to
         * keep it as optimized as possible, while retaining generic code.
         *
         * Verify the various "blind-ness" checks in the code.
         *
         * XXX XXX XXX Note that several effects should really not be "seen"
         * if the player is blind.
         *
         * Perhaps monsters should breathe at locations *near* the player,
         * since this would allow them to inflict "partial" damage.
         *
         * Perhaps smart monsters should decline to use "bolt" spells if
         * there is a monster in the way, unless they wish to kill it.
         *
         * It will not be possible to "correctly" handle the case in which a
         * monster attempts to attack a location which is thought to contain
         * the player, but which in fact is nowhere near the player, since this
         * might induce all sorts of messages about the attack itself, and about
         * the effects of the attack, which the player might or might not be in
         * a position to observe.  Thus, for simplicity, it is probably best to
         * only allow "faulty" attacks by a monster if one of the important grids
         * (probably the initial or final grid) is in fact in view of the player.
         * It may be necessary to actually prevent spell attacks except when the
         * monster actually has line of sight to the player.  Note that a monster
         * could be left in a bizarre situation after the player ducked behind a
         * pillar and then teleported away, for example.
         *
         * Note that this function attempts to optimize the use of spells for the
         * cases in which the monster has no spells, or has spells but cannot use
         * them, or has spells but they will have no "useful" effect.  Note that
         * this function has been an efficiency bottleneck in the past.
         *
         * Note the special "MFLAG_NICE" flag, which prevents a monster from using
         * any spell attacks until the player has had a single chance to move.
         */
        static bool make_attack_spell(int m_idx)
        {
            int chance, thrown_spell, rlev, failrate;

            Bitflag f = new Bitflag(Monster_Spell_Flag.SIZE);

            Monster m_ptr = Cave.cave_monster(Cave.cave, m_idx);
            Monster_Race r_ptr = Misc.r_info[m_ptr.r_idx];
            Monster_Lore l_ptr = Misc.l_list[m_ptr.r_idx];

            //char m_name[80], m_poss[80], ddesc[80];
            string m_name, m_poss, ddesc;

            /* Player position */
            int px = Misc.p_ptr.px;
            int py = Misc.p_ptr.py;

            /* Extract the blind-ness */
            bool blind = (Misc.p_ptr.timed[(int)Timed_Effect.BLIND] != 0 ? true : false);

            /* Extract the "see-able-ness" */
            bool seen = (!blind && m_ptr.ml);

            /* Assume "normal" target */
            bool normal = true;

            /* Handle "leaving" */
            if (Misc.p_ptr.leaving) return false;

            /* Cannot cast spells when confused */
            if (m_ptr.m_timed[(int)Misc.MON_TMD.CONF] != 0) return (false);

            /* Cannot cast spells when nice */
            if ((m_ptr.mflag & Monster_Flag.MFLAG_NICE) != 0) return false;

            /* Hack -- Extract the spell probability */
            chance = (r_ptr.freq_innate + r_ptr.freq_spell) / 2;

            /* Not allowed to cast spells */
            if (chance == 0) return false;

            /* Only do spells occasionally */
            if (Random.randint0(100) >= chance) return false;

            /* Hack -- require projectable player */
            if (normal)
            {
                /* Check range */
                if (m_ptr.cdis > Misc.MAX_RANGE) return false;

                /* Check path */
                if (!Cave.projectable(m_ptr.fy, m_ptr.fx, py, px, Spell.PROJECT_NONE))
                    return false;
            }

            /* Extract the monster level */
            rlev = ((r_ptr.level >= 1) ? r_ptr.level : 1);

            /* Extract the racial spell flags */
            f.copy(r_ptr.spell_flags);

            /* Allow "desperate" spells */
            if (r_ptr.flags.has(Monster_Flag.SMART.value) &&
                m_ptr.hp < m_ptr.maxhp / 10 &&
                Random.randint0(100) < 50){

                throw new NotImplementedException();

                ///* Require intelligent spells */
                //set_spells(f, RST_HASTE | RST_ANNOY | RST_ESCAPE | RST_HEAL | RST_TACTIC | RST_SUMMON);
            }

            /* Remove the "ineffective" spells */
            remove_bad_spells(m_idx, f);

            /* Check whether summons and bolts are worth it. */
            if (!r_ptr.flags.has(Monster_Flag.STUPID.value))
            {
                /* Check for a clean bolt shot */
                if (Monster_Spell_Flag.test_spells(f, Monster_Spell_Flag.mon_spell_type.RST_BOLT) &&
                    !clean_shot(m_ptr.fy, m_ptr.fx, py, px))

                    /* Remove spells that will only hurt friends */
                    Monster_Spell_Flag.set_spells(f, ~Monster_Spell_Flag.mon_spell_type.RST_BOLT);

                /* Check for a possible summon */
                if (!(summon_possible(m_ptr.fy, m_ptr.fx)))

                    /* Remove summoning spells */
                    Monster_Spell_Flag.set_spells(f, ~Monster_Spell_Flag.mon_spell_type.RST_SUMMON);
            }

            /* No spells left */
            if (f.is_empty()) return false;

            /* Get the monster name (or "it") */
            m_name = m_ptr.monster_desc(0x00);
            //Nick: Capatilize the first letter.
            m_name = Char.ToUpper(m_name[0]) + m_name.Substring(1);

            /* Get the monster possessive ("his"/"her"/"its") */
            m_poss = m_ptr.monster_desc(Desc.PRO2 | Desc.POSS);

            /* Get the "died from" name */
            ddesc = m_ptr.monster_desc(Desc.SHOW | Desc.IND2);

            /* Choose a spell to cast */
            thrown_spell = choose_attack_spell(m_idx, f);

            /* Abort if no spell was chosen */
            if (thrown_spell == 0) return false;

            /* If we see an unaware monster try to cast a spell, become aware of it */
            if (m_ptr.unaware)
                become_aware(m_idx);

            /* Calculate spell failure rate */
            failrate = 25 - (rlev + 3) / 4;
            if (m_ptr.m_timed[(int)Misc.MON_TMD.FEAR] != 0)
                failrate += 20;

            /* Stupid monsters will never fail (for jellies and such) */
            if (Option.birth_ai_smart.value || r_ptr.flags.has(Monster_Flag.STUPID.value))
                failrate = 0;

            /* Check for spell failure (innate attacks never fail) */
            if ((thrown_spell >= Monster_Spell_Flag.MIN_NONINNATE_SPELL) && (Random.randint0(100) < failrate))
            {
                /* Message */
                Utilities.msg("{0} tries to cast a spell, but fails.", m_name);

                return true;
            }

            /* Cast the spell. */
            Cave.disturb(Misc.p_ptr, 1, 0);

            /* Special case RSF_HASTE until TMD_* and MON_TMD_* are rationalised */
            if (thrown_spell == Monster_Spell_Flag.HASTE.value) {
                if (blind)
                    Utilities.msg("{0} mumbles.", m_name);
                else
                    Utilities.msg("{0} concentrates on {1} body.", m_name, m_poss);

                mon_inc_timed(m_idx, Misc.MON_TMD.FAST, 50, 0, false);
            } else
                Monster_Spell_Flag.do_mon_spell(thrown_spell, m_idx, seen);

            /* Remember what the monster did to us */
            if (seen) {
                l_ptr.spell_flags.on(thrown_spell);

                /* Innate spell */
                if (thrown_spell < Monster_Spell_Flag.MIN_NONINNATE_SPELL) {
                    if (l_ptr.cast_innate < byte.MaxValue)
                        l_ptr.cast_innate++;
                } else {
                /* Bolt or Ball, or Special spell */
                    if (l_ptr.cast_spell < byte.MaxValue)
                        l_ptr.cast_spell++;
                }
            }
            /* Always take note of monsters that kill you */
            if (Misc.p_ptr.is_dead && (l_ptr.deaths < short.MaxValue)) {
                l_ptr.deaths++;
            }

            /* A spell was cast */
            return true;
        }
Пример #4
0
        /**
         * Notice curses on an object.
         *
         * \param o_ptr is the object to notice curses on
         */
        bool notice_curses()
        {
            Bitflag f = new Bitflag(Object_Flag.SIZE);
            Bitflag f2 = new Bitflag(Object_Flag.SIZE);

            object_flags(ref f);

            /* Gather whatever curse flags there are to know */
            Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.CURSE);

            /* Remove everything except the curse flags */
            f.inter(f2);

            /* give knowledge of which curses are present */
            notice_flags(f);

            check_for_ident();

            Misc.p_ptr.notice |= Misc.PN_SQUELCH;

            return !f.is_empty();
        }
Пример #5
0
        /**
         * Add a pval to an object, rearranging flags as necessary. Returns true
         * if the number of pvals is now different, false if it is the same.
         *
         * \param o_ptr is the object we're adjusting
         * \param pval is the pval we are adding
         * \param flag is the flag to which we are adding the pval
         */
        bool add_pval(int pval, int flag)
        {
            Bitflag f = new Bitflag(Object_Flag.SIZE);
            int a = -1, best_pval;

            /* Sanity check (we may be called with 0 - see ticket #1451) */
            if (pval == 0) return false;

            Object_Flag.create_mask(f, false, Object_Flag.object_flag_type.PVAL, Object_Flag.object_flag_type.STAT);

            if (flags.has(flag)) {
                /* See if any other flags are associated with this pval */
                a = which_pval(flag);
                f.off(flag);
                f.inter(pval_flags[a]);
                if (f.is_empty()) { /* Safe to increment and finish */
                    this.pval[a] += (short)pval;
                    if (this.pval[a] == 0) { /* Remove the flag */
                        flags.off(flag);
                        pval_flags[a].off(flag);
                    }
                    return (object_dedup_pvals());
                }
            }

            /* So it doesn't have the flag, or it does but that pval also has others */

            /* Create a new pval if we can */
            if (this.num_pvals < Misc.MAX_PVALS) {
                this.pval[this.num_pvals] = (short)pval;
                this.pval_flags[this.num_pvals].on(flag);
                if (a != -1) { /* then we need to move the flag to the new pval */
                    this.pval[this.num_pvals] += this.pval[a];
                    this.pval_flags[a].off(flag);
                } else /* We need to add it to object_flags */
                    this.flags.on(flag);
                this.num_pvals++; /* We do this last because pvals start from zero */
                /* We invert the logic because we've already added a pval */
                return (!object_dedup_pvals());
            } else { /* we use the closest existing pval */
                best_pval = object_closest_pval((pval + (a == -1 ? 0 : this.pval[a])));
                if (best_pval != a) { /* turn on the flag on the new pval */
                    this.pval_flags[best_pval].on(flag);
                    if(a != -1) /* turn it off on its old pval */
                        this.pval_flags[a].off(flag);
                    else /* add it to object_flags */
                        this.flags.on(flag);
                }
                return false; /* We haven't changed any pvals, so no need to de-dup */
            }
        }
Пример #6
0
        /*
         * Given an object, return a short identifier which gives some idea of what
         * the item is.
         */
        public obj_pseudo_t pseudo()
        {
            Bitflag flags = new Bitflag(Object_Flag.SIZE);
            Bitflag f2 = new Bitflag(Object_Flag.SIZE);

            /* Get the known and obvious flags on the object,
             * not including curses or properties of the kind.
             */
            object_flags_known(ref flags);
            Object_Flag.create_mask(f2, true, Object_Flag.object_flag_id.WIELD);

            /* FA on gloves is obvious to mage casters */
            if (FA_would_be_obvious())
                f2.on(Object_Flag.FREE_ACT.value);

            /* Now we remove the non-obvious known flags */
            flags.inter(f2);

            /* Now we remove the cursed flags and the kind flags */
            Object_Flag.create_mask(f2, false, Object_Flag.object_flag_type.CURSE);
            flags.diff(f2);
            flags.diff(kind.flags);

            if ((ident & IDENT_INDESTRUCT) != 0)
                return obj_pseudo_t.INSCRIP_SPECIAL;
            if ((was_sensed() || was_worn()) && artifact != null)
                return obj_pseudo_t.INSCRIP_SPECIAL;

            /* jewelry does not pseudo */
            if (is_jewelry())
                return obj_pseudo_t.INSCRIP_null;

            /* XXX Eddie should also check for flags with pvals where the pval exceeds
             * the base pval for things like picks of digging, though for now acid brand gets those
             */
            if (!flags.is_empty())
                return obj_pseudo_t.INSCRIP_SPLENDID;

            if (!is_known() && !was_sensed())
                return obj_pseudo_t.INSCRIP_null;

            if (ego != null)
            {
                /* uncursed bad egos are not excellent */
                if (ego.flags.is_inter(f2))
                    return obj_pseudo_t.INSCRIP_STRANGE; /* XXX Eddie need something worse */
                else
                    return obj_pseudo_t.INSCRIP_EXCELLENT;
            }

            if (to_a == Random.randcalc(kind.to_a, 0, aspect.MINIMISE) &&
                to_h == Random.randcalc(kind.to_h, 0, aspect.MINIMISE) &&
                 to_d == Random.randcalc(kind.to_d, 0, aspect.MINIMISE))
                return obj_pseudo_t.INSCRIP_AVERAGE;

            if (to_a >= Random.randcalc(kind.to_a, 0, aspect.MINIMISE) &&
                to_h >= Random.randcalc(kind.to_h, 0, aspect.MINIMISE) &&
                to_d >= Random.randcalc(kind.to_d, 0, aspect.MINIMISE))
                return obj_pseudo_t.INSCRIP_MAGICAL;

            if (to_a <= Random.randcalc(kind.to_a, 0, aspect.MINIMISE) &&
                to_h <= Random.randcalc(kind.to_h, 0, aspect.MINIMISE) &&
                to_d <= Random.randcalc(kind.to_d, 0, aspect.MINIMISE))
                return obj_pseudo_t.INSCRIP_MAGICAL;

            return obj_pseudo_t.INSCRIP_STRANGE;
        }
Пример #7
0
        /**
         * Create a cache of slay combinations found on ego items, and the values of
         * these combinations. This is to speed up slay_power(), which will be called
         * many times for ego items during the game.
         *
         * \param items is the set of ego types from which we are extracting slay
         * combinations
         */
        public static int create_slay_cache(Ego_Item[] items)
        {
            int     count     = 0;
            Bitflag cacheme   = new Bitflag(Object_Flag.SIZE);
            Bitflag slay_mask = new Bitflag(Object_Flag.SIZE);

            /* Build the slay mask */
            Object_Flag.create_mask(slay_mask, false, Object_Flag.object_flag_type.SLAY,
                                    Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND);

            /* Calculate necessary size of slay_cache */
            Bitflag[] dupcheck = new Bitflag[Misc.z_info.e_max];

            for (int i = 0; i < Misc.z_info.e_max; i++)
            {
                dupcheck[i] = new Bitflag(Object_Flag.SIZE);
                Ego_Item e_ptr = items[i];

                //Some items are null... I guess we should just skip them...?
                //TODO: Find out why they are null, and see if we actually should just skip them...
                if (e_ptr == null)
                {
                    continue;
                }

                /* Find the slay flags on this ego */
                cacheme.copy(e_ptr.flags);
                cacheme.inter(slay_mask);

                /* Only consider non-empty combinations of slay flags */
                if (!cacheme.is_empty())
                {
                    /* Skip previously scanned combinations */
                    for (int j = 0; j < i; j++)
                    {
                        if (cacheme.is_equal(dupcheck[j]))
                        {
                            continue;
                        }
                    }

                    /* msg("Found a new slay combo on an ego item"); */
                    count++;
                    dupcheck[i].copy(cacheme);
                }
            }

            /* Allocate slay_cache with an extra empty element for an iteration stop */
            slay_cache = new flag_cache[count + 1];
            count      = 0;

            /* Populate the slay_cache */
            for (int i = 0; i < Misc.z_info.e_max; i++)
            {
                if (!dupcheck[i].is_empty())
                {
                    slay_cache[count] = new flag_cache();
                    slay_cache[count].flags.copy(dupcheck[i]);
                    slay_cache[count].value = 0;
                    count++;
                    /*msg("Cached a slay combination");*/
                }
            }

            //From a time without garbage collection...

            /*for (i = 0; i < z_info.e_max; i++)
             *  FREE(dupcheck[i]);
             * FREE(dupcheck);*/

            /* Success */
            return(0);
        }
Пример #8
0
        /*
         * 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);
        }
Пример #9
0
        /**
         * Create a cache of slay combinations found on ego items, and the values of
         * these combinations. This is to speed up slay_power(), which will be called
         * many times for ego items during the game.
         *
         * \param items is the set of ego types from which we are extracting slay
         * combinations
         */
        public static int create_slay_cache(Ego_Item[] items)
        {
            int count = 0;
            Bitflag cacheme = new Bitflag(Object_Flag.SIZE);
            Bitflag slay_mask = new Bitflag(Object_Flag.SIZE);

            /* Build the slay mask */
            Object_Flag.create_mask(slay_mask, false, Object_Flag.object_flag_type.SLAY,
                Object_Flag.object_flag_type.KILL, Object_Flag.object_flag_type.BRAND);

            /* Calculate necessary size of slay_cache */
            Bitflag[] dupcheck = new Bitflag[Misc.z_info.e_max];

            for (int i = 0; i < Misc.z_info.e_max; i++) {
                dupcheck[i] = new Bitflag(Object_Flag.SIZE);
                Ego_Item e_ptr = items[i];

                //Some items are null... I guess we should just skip them...?
                //TODO: Find out why they are null, and see if we actually should just skip them...
                if(e_ptr == null) {
                    continue;
                }

                /* Find the slay flags on this ego */
                cacheme.copy(e_ptr.flags);
                cacheme.inter(slay_mask);

                /* Only consider non-empty combinations of slay flags */
                if (!cacheme.is_empty()) {
                    /* Skip previously scanned combinations */
                    for (int j = 0; j < i; j++)
                        if (cacheme.is_equal(dupcheck[j])) continue;

                    /* msg("Found a new slay combo on an ego item"); */
                    count++;
                    dupcheck[i].copy(cacheme);
                }
            }

            /* Allocate slay_cache with an extra empty element for an iteration stop */
            slay_cache = new flag_cache[count + 1];
            count = 0;

            /* Populate the slay_cache */
            for (int i = 0; i < Misc.z_info.e_max; i++) {
                if (!dupcheck[i].is_empty()) {
                    slay_cache[count] = new flag_cache();
                    slay_cache[count].flags.copy(dupcheck[i]);
                    slay_cache[count].value = 0;
                    count++;
                    /*msg("Cached a slay combination");*/
                }
            }

            //From a time without garbage collection...
            /*for (i = 0; i < z_info.e_max; i++)
                FREE(dupcheck[i]);
            FREE(dupcheck);*/

            /* Success */
            return 0;
        }