Example #1
0
        /*
         * Learn about an "observed" resistance or other player state property, or
         * lack of it.
         */
        public void update_smart_learn(Player.Player p, Object_Flag what)
        {
            Monster_Race r_ptr = Misc.r_info[r_idx];

            /* Sanity check */
            if (what != null)
            {
                return;
            }

            /* anything a monster might learn, the player should learn */
            Object.Object.wieldeds_notice_flag(p, what.value);

            /* Not allowed to learn */
            if (!Option.birth_ai_learn.value)
            {
                return;
            }

            /* Too stupid to learn anything */
            if (r_ptr.flags.has(Monster_Flag.STUPID.value))
            {
                return;
            }

            /* Not intelligent, only learn sometimes */
            if (!r_ptr.flags.has(Monster_Flag.SMART.value) && Random.one_in_(2))
            {
                return;
            }

            /* Analyze the knowledge; fail very rarely */
            if (p.check_state(what, p.state.flags) && !Random.one_in_(100))
            {
                known_pflags.on(what.value);
            }
            else
            {
                known_pflags.off(what.value);
            }
        }
Example #2
0
        /*
         * Build a string describing a monster in some way.
         *
         * We can correctly describe monsters based on their visibility.
         * We can force all monsters to be treated as visible or invisible.
         * We can build nominatives, objectives, possessives, or reflexives.
         * We can selectively pronominalize hidden, visible, or all monsters.
         * We can use definite or indefinite descriptions for hidden monsters.
         * We can use definite or indefinite descriptions for visible monsters.
         *
         * Pronominalization involves the gender whenever possible and allowed,
         * so that by cleverly requesting pronominalization / visibility, you
         * can get messages like "You hit someone.  She screams in agony!".
         *
         * Reflexives are acquired by requesting Objective plus Possessive.
         *
         * I am assuming that no monster name is more than 65 characters long,
         * so that "char desc[80];" is sufficiently large for any result, even
         * when the "offscreen" notation is added.
         *
         * Note that the "possessive" for certain unique monsters will look
         * really silly, as in "Morgoth, King of Darkness's".  We should
         * perhaps add a flag to "remove" any "descriptives" in the name.
         *
         * Note that "offscreen" monsters will get a special "(offscreen)"
         * notation in their name if they are visible but offscreen.  This
         * may look silly with possessives, as in "the rat's (offscreen)".
         * Perhaps the "offscreen" descriptor should be abbreviated.
         *
         * Mode Flags:
         *   0x01 -. Objective (or Reflexive)
         *   0x02 -. Possessive (or Reflexive)
         *   0x04 -. Use indefinites for hidden monsters ("something")
         *   0x08 -. Use indefinites for visible monsters ("a kobold")
         *   0x10 -. Pronominalize hidden monsters
         *   0x20 -. Pronominalize visible monsters
         *   0x40 -. Assume the monster is hidden
         *   0x80 -. Assume the monster is visible
         *
         * Useful Modes:
         *   0x00 -. Full nominative name ("the kobold") or "it"
         *   0x04 -. Full nominative name ("the kobold") or "something"
         *   0x80 -. Banishment resistance name ("the kobold")
         *   0x88 -. Killing name ("a kobold")
         *   0x22 -. Possessive, genderized if visable ("his") or "its"
         *   0x23 -. Reflexive, genderized if visable ("himself") or "itself"
         */
        public string monster_desc(Desc in_mode)
        {
            string res  = "ERROR IN MONSTER_DESC";
            int    mode = (int)in_mode;

            Monster_Race r_ptr = Misc.r_info[r_idx];

            string name = r_ptr.Name;

            /* Can we "see" it (forced, or not hidden + visible) */
            bool seen = (((mode & (0x80)) != 0) || (((mode & (0x40)) == 0) && ml));

            /* Sexed Pronouns (seen and forced, or unseen and allowed) */
            bool pron = ((seen && ((mode & (0x20)) != 0)) || (!seen && ((mode & (0x10)) != 0)));


            /* First, try using pronouns, or describing hidden monsters */
            if (!seen || pron)
            {
                /* an encoding of the monster "sex" */
                int kind = 0x00;

                /* Extract the gender (if applicable) */
                if (r_ptr.flags.has(Monster_Flag.FEMALE.value))
                {
                    kind = 0x20;
                }
                else if (r_ptr.flags.has(Monster_Flag.MALE.value))
                {
                    kind = 0x10;
                }

                /* Ignore the gender (if desired) */
                if (!pron)
                {
                    kind = 0x00;
                }


                /* Assume simple result */
                res = "it";

                /* Brute force: split on the possibilities */
                switch (kind + (mode & 0x07))
                {
                /* Neuter, or unknown */
                case 0x00: res = "it"; break;

                case 0x01: res = "it"; break;

                case 0x02: res = "its"; break;

                case 0x03: res = "itself"; break;

                case 0x04: res = "something"; break;

                case 0x05: res = "something"; break;

                case 0x06: res = "something's"; break;

                case 0x07: res = "itself"; break;

                /* Male (assume human if vague) */
                case 0x10: res = "he"; break;

                case 0x11: res = "him"; break;

                case 0x12: res = "his"; break;

                case 0x13: res = "himself"; break;

                case 0x14: res = "someone"; break;

                case 0x15: res = "someone"; break;

                case 0x16: res = "someone's"; break;

                case 0x17: res = "himself"; break;

                /* Female (assume human if vague) */
                case 0x20: res = "she"; break;

                case 0x21: res = "her"; break;

                case 0x22: res = "her"; break;

                case 0x23: res = "herself"; break;

                case 0x24: res = "someone"; break;

                case 0x25: res = "someone"; break;

                case 0x26: res = "someone's"; break;

                case 0x27: res = "herself"; break;
                }
            }


            /* Handle visible monsters, "reflexive" request */
            else if ((mode & 0x02) != 0 && (mode & 0x01) != 0)
            {
                /* The monster is visible, so use its gender */
                if (r_ptr.flags.has(Monster_Flag.FEMALE.value))
                {
                    res = "herself";
                }
                else if (r_ptr.flags.has(Monster_Flag.MALE.value))
                {
                    res = "himself";
                }
                else
                {
                    res = "itself";
                }
            }


            /* Handle all other visible monster requests */
            else
            {
                /* It could be a Unique */
                if (r_ptr.flags.has(Monster_Flag.UNIQUE.value))
                {
                    res = name;
                }

                /* It could be an indefinite monster */
                else if ((mode & 0x08) != 0)
                {
                    /* XXX Check plurality for "some" */

                    /* Indefinite monsters need an indefinite article */
                    res  = "aeiouAEIOU".Contains(name[0]) ? "an" : "a";
                    res += name;
                }

                /* It could be a normal, definite, monster */
                else
                {
                    /* Definite monsters need a definite article */
                    res = "the " + name;
                }

                /* Handle the Possessive as a special afterthought */
                if ((mode & 0x02) != 0)
                {
                    /* XXX Check for trailing "s" */

                    /* Simply append "apostrophe" and "s" */
                    res += "'s";
                }

                /* Mention "offscreen" monsters XXX XXX */
                if (!Term.panel_contains(fy, fx))
                {
                    /* Append special notation */
                    res += " (offscreen)";
                }
            }

            /* Return the result */
            return(res);
        }
Example #3
0
        /**
         * Calculate hp for a monster. This function assumes that the Rand_normal
         * function has limits of +/- 4x std_dev. If that changes, this function
         * will become inaccurate.
         *
         * \param r_ptr is the race of the monster in question.
         * \param hp_aspect is the hp calc we want (min, max, avg, random).
         */
        public static int mon_hp(Monster_Race r_ptr, aspect hp_aspect)
        {
            int std_dev = (((r_ptr.avg_hp * 10) / 8) + 5) / 10;

                if (r_ptr.avg_hp > 1) std_dev++;

                switch (hp_aspect) {
                    case aspect.MINIMISE:
                        return (r_ptr.avg_hp - (4 * std_dev));
                    case aspect.MAXIMISE:
                    case aspect.EXTREMIFY:
                        return (r_ptr.avg_hp + (4 * std_dev));
                    case aspect.AVERAGE:
                        return r_ptr.avg_hp;
                    default:
                        return Random.Rand_normal(r_ptr.avg_hp, std_dev);
                }
        }
Example #4
0
        /**
         * Return the coin type of a monster race, based on the monster being
         * killed.
         */
        static int get_coin_type(Monster_Race r_ptr)
        {
            string name = r_ptr.Name;

            if (!r_ptr.flags.has(Monster_Flag.METAL.value)) return (int)SVal.sval_gold.SV_GOLD_ANY;

            /* Look for textual clues */
            if (name.Contains("copper "))	return (int)SVal.sval_gold.SV_COPPER;
            if (name.Contains("silver "))	return (int)SVal.sval_gold.SV_SILVER;
            if (name.Contains("gold "))		return (int)SVal.sval_gold.SV_GOLD;
            if (name.Contains("mithril "))	return (int)SVal.sval_gold.SV_MITHRIL;
            if (name.Contains("adamantite "))	return (int)SVal.sval_gold.SV_ADAMANTITE;

            /* Assume nothing */
            return (int)SVal.sval_gold.SV_GOLD_ANY;
        }
Example #5
0
        /*
         * This function updates the monster record of the given monster
         *
         * This involves extracting the distance to the player (if requested),
         * and then checking for visibility (natural, infravision, see-invis,
         * telepathy), updating the monster visibility flag, redrawing (or
         * erasing) the monster when its visibility changes, and taking note
         * of any interesting monster flags (cold-blooded, invisible, etc).
         *
         * Note the new "mflag" field which encodes several monster state flags,
         * including "view" for when the monster is currently in line of sight,
         * and "mark" for when the monster is currently visible via detection.
         *
         * The only monster fields that are changed here are "cdis" (the
         * distance from the player), "ml" (visible to the player), and
         * "mflag" (to maintain the "MFLAG_VIEW" flag).
         *
         * Note the special "update_monsters()" function which can be used to
         * call this function once for every monster.
         *
         * Note the "full" flag which requests that the "cdis" field be updated,
         * this is only needed when the monster (or the player) has moved.
         *
         * Every time a monster moves, we must call this function for that
         * monster, and update the distance, and the visibility.  Every time
         * the player moves, we must call this function for every monster, and
         * update the distance, and the visibility.  Whenever the player "state"
         * changes in certain ways ("blindness", "infravision", "telepathy",
         * and "see invisible"), we must call this function for every monster,
         * and update the visibility.
         *
         * Routines that change the "illumination" of a grid must also call this
         * function for any monster in that grid, since the "visibility" of some
         * monsters may be based on the illumination of their grid.
         *
         * Note that this function is called once per monster every time the
         * player moves.  When the player is running, this function is one
         * of the primary bottlenecks, along with "update_view()" and the
         * "process_monsters()" code, so efficiency is important.
         *
         * Note the optimized "inline" version of the "distance()" function.
         *
         * A monster is "visible" to the player if (1) it has been detected
         * by the player, (2) it is close to the player and the player has
         * telepathy, or (3) it is close to the player, and in line of sight
         * of the player, and it is "illuminated" by some combination of
         * infravision, torch light, or permanent light (invisible monsters
         * are only affected by "light" if the player can see invisible).
         *
         * Monsters which are not on the current panel may be "visible" to
         * the player, and their descriptions will include an "offscreen"
         * reference.  Currently, offscreen monsters cannot be targeted
         * or viewed directly, but old targets will remain set.  XXX XXX
         *
         * The player can choose to be disturbed by several things, including
         * "OPT(disturb_move)" (monster which is viewable moves in some way), and
         * "OPT(disturb_near)" (monster which is "easily" viewable moves in some
         * way).  Note that "moves" includes "appears" and "disappears".
         */
        public static void update_mon(int m_idx, bool full)
        {
            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];

            if (l_ptr == null)
            {
                l_ptr = Misc.l_list[m_ptr.r_idx] = new Monster_Lore();
            }

            int d;

            /* Current location */
            int fy = m_ptr.fy;
            int fx = m_ptr.fx;

            /* Seen at all */
            bool flag = false;

            /* Seen by vision */
            bool easy = false;


            /* Compute distance */
            if (full)
            {
                int py = Misc.p_ptr.py;
                int px = Misc.p_ptr.px;

                /* Distance components */
                int dy = (py > fy) ? (py - fy) : (fy - py);
                int dx = (px > fx) ? (px - fx) : (fx - px);

                /* Approximate distance */
                d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));

                /* Restrict distance */
                if (d > 255)
                {
                    d = 255;
                }

                /* Save the distance */
                m_ptr.cdis = (byte)d;
            }

            /* Extract distance */
            else
            {
                /* Extract the distance */
                d = m_ptr.cdis;
            }


            /* Detected */
            if ((m_ptr.mflag & (Monster_Flag.MFLAG_MARK)) != 0)
            {
                flag = true;
            }


            /* Nearby */
            if (d <= Misc.MAX_SIGHT)
            {
                /* Basic telepathy */
                if (Misc.p_ptr.check_state(Object_Flag.TELEPATHY, Misc.p_ptr.state.flags))
                {
                    /* Empty mind, no telepathy */
                    if (r_ptr.flags.has(Monster_Flag.EMPTY_MIND.value))
                    {
                        /* Nothing! */
                    }

                    /* Weird mind, occasional telepathy */
                    else if (r_ptr.flags.has(Monster_Flag.WEIRD_MIND.value))
                    {
                        throw new NotImplementedException();
                        ///* One in ten individuals are detectable */
                        //if ((m_idx % 10) == 5)
                        //{
                        //    /* Detectable */
                        //    flag = true;

                        //    /* Check for LOS so that MFLAG_VIEW is set later */
                        //    if (player_has_los_bold(fy, fx)) easy = true;
                        //}
                    }

                    /* Normal mind, allow telepathy */
                    else
                    {
                        throw new NotImplementedException();
                        ///* Detectable */
                        //flag = true;

                        ///* Check for LOS to that MFLAG_VIEW is set later */
                        //if (player_has_los_bold(fy, fx)) easy = true;
                    }
                }

                /* Normal line of sight and player is not blind */
                if (Cave.player_has_los_bold(fy, fx) && Misc.p_ptr.timed[(int)Timed_Effect.BLIND] == 0)
                {
                    /* Use "infravision" */
                    if (d <= Misc.p_ptr.state.see_infra)
                    {
                        /* Learn about warm/cold blood */
                        l_ptr.flags.on(Monster_Flag.COLD_BLOOD.value);

                        /* Handle "warm blooded" monsters */
                        if (!r_ptr.flags.has(Monster_Flag.COLD_BLOOD.value))
                        {
                            /* Easy to see */
                            easy = flag = true;
                        }
                    }

                    /* See if the monster is emitting light */
                    /*if (rf_has(r_ptr.flags, RF_HAS_LIGHT)) easy = flag = true;*/

                    /* Use "illumination" */
                    if (Cave.player_can_see_bold(fy, fx))
                    {
                        /* Learn it emits light */
                        l_ptr.flags.on(Monster_Flag.HAS_LIGHT.value);

                        /* Learn about invisibility */
                        l_ptr.flags.on(Monster_Flag.INVISIBLE.value);

                        /* Handle "invisible" monsters */
                        if (r_ptr.flags.has(Monster_Flag.INVISIBLE.value))
                        {
                            /* See invisible */
                            if (Misc.p_ptr.check_state(Object_Flag.SEE_INVIS, Misc.p_ptr.state.flags))
                            {
                                /* Easy to see */
                                easy = flag = true;
                            }
                        }

                        /* Handle "normal" monsters */
                        else
                        {
                            /* Easy to see */
                            easy = flag = true;
                        }
                    }
                }
            }

            /* If a mimic looks like a squelched item, it's not seen */
            if (is_mimicking(m_idx))
            {
                throw new NotImplementedException();
                //object_type *o_ptr = object_byid(m_ptr.mimicked_o_idx);
                //if (squelch_item_ok(o_ptr))
                //    easy = flag = false;
            }

            /* The monster is now visible */
            if (flag)
            {
                /* Learn about the monster's mind */
                if (Misc.p_ptr.check_state(Object_Flag.TELEPATHY, Misc.p_ptr.state.flags))
                {
                    l_ptr.flags.set(Monster_Flag.EMPTY_MIND.value, Monster_Flag.WEIRD_MIND.value,
                                    Monster_Flag.SMART.value, Monster_Flag.STUPID.value);
                }

                /* It was previously unseen */
                if (!m_ptr.ml)
                {
                    /* Mark as visible */
                    m_ptr.ml = true;

                    /* Draw the monster */
                    Cave.cave_light_spot(Cave.cave, fy, fx);

                    /* Update health bar as needed */
                    if (Misc.p_ptr.health_who == m_idx)
                    {
                        Misc.p_ptr.redraw |= (Misc.PR_HEALTH);
                    }

                    /* Hack -- Count "fresh" sightings */
                    if (l_ptr.sights < short.MaxValue)
                    {
                        l_ptr.sights++;
                    }

                    /* Disturb on appearance */
                    if (Option.disturb_move.value)
                    {
                        Cave.disturb(Misc.p_ptr, 1, 0);
                    }

                    /* Window stuff */
                    Misc.p_ptr.redraw |= Misc.PR_MONLIST;
                }
            }

            /* The monster is not visible */
            else
            {
                /* It was previously seen */
                if (m_ptr.ml)
                {
                    /* Treat mimics differently */
                    if (m_ptr.mimicked_o_idx == 0 || Squelch.item_ok(Object.Object.byid(m_ptr.mimicked_o_idx)))
                    {
                        /* Mark as not visible */
                        m_ptr.ml = false;

                        /* Erase the monster */
                        Cave.cave_light_spot(Cave.cave, fy, fx);

                        /* Update health bar as needed */
                        if (Misc.p_ptr.health_who == m_idx)
                        {
                            Misc.p_ptr.redraw |= (Misc.PR_HEALTH);
                        }

                        /* Disturb on disappearance */
                        if (Option.disturb_move.value)
                        {
                            Cave.disturb(Misc.p_ptr, 1, 0);
                        }

                        /* Window stuff */
                        Misc.p_ptr.redraw |= Misc.PR_MONLIST;
                    }
                }
            }


            /* The monster is now easily visible */
            if (easy)
            {
                /* Change */
                if ((m_ptr.mflag & (Monster_Flag.MFLAG_VIEW)) == 0)
                {
                    /* Mark as easily visible */
                    m_ptr.mflag |= (Monster_Flag.MFLAG_VIEW);

                    /* Disturb on appearance */
                    if (Option.disturb_near.value)
                    {
                        Cave.disturb(Misc.p_ptr, 1, 0);
                    }

                    /* Re-draw monster window */
                    Misc.p_ptr.redraw |= Misc.PR_MONLIST;
                }
            }

            /* The monster is not easily visible */
            else
            {
                /* Change */
                if ((m_ptr.mflag & (Monster_Flag.MFLAG_VIEW)) != 0)
                {
                    /* Mark as not easily visible */
                    m_ptr.mflag &= ~(Monster_Flag.MFLAG_VIEW);

                    /* Disturb on disappearance */
                    if (Option.disturb_near.value)
                    {
                        Cave.disturb(Misc.p_ptr, 1, 0);
                    }

                    /* Re-draw monster list window */
                    Misc.p_ptr.redraw |= Misc.PR_MONLIST;
                }
            }
        }
Example #6
0
        /*
         * Reset the "visual" lists
         *
         * This involves resetting various things to their "default" state.
         *
         * If the "prefs" flag is true, then we will also load the appropriate
         * "user pref file" based on the current setting of the "use_graphics"
         * flag.  This is useful for switching "graphics" on/off.
         */
        /* XXX this does not belong here */
        //Todo: Figure out where it goes. At a glance, init seems nice.
        //Nick: Was previously in "obj-util.c"... lulz
        public static void reset_visuals(bool load_prefs)
        {
            int    i;
            Flavor f;

            /* Extract default attr/char code for features */
            for (i = 0; i < Misc.z_info.f_max; i++)
            {
                int     j;
                Feature f_ptr = Misc.f_info[i];

                /* Assume we will use the underlying values */
                for (j = 0; j < (int)Grid_Data.grid_light_level.FEAT_LIGHTING_MAX; j++)
                {
                    f_ptr.x_attr[j] = f_ptr.d_attr;
                    f_ptr.x_char[j] = f_ptr.d_char;
                }
            }

            /* Extract default attr/char code for objects */
            for (i = 0; i < Misc.z_info.k_max; i++)
            {
                Object.Object_Kind k_ptr = Misc.k_info[i];
                if (k_ptr == null)
                {
                    continue;
                }

                /* Default attr/char */
                k_ptr.x_attr = k_ptr.d_attr;
                k_ptr.x_char = k_ptr.d_char;
            }

            /* Extract default attr/char code for monsters */
            for (i = 0; i < Misc.z_info.r_max; i++)
            {
                Monster.Monster_Race r_ptr = Misc.r_info[i];
                if (r_ptr == null)
                {
                    continue;
                }

                /* Default attr/char */
                r_ptr.x_attr = r_ptr.d_attr;
                r_ptr.x_char = r_ptr.d_char;
            }

            /* Extract default attr/char code for flavors */
            for (f = Misc.flavors; f != null; f = f.next)
            {
                f.x_attr = f.d_attr;
                f.x_char = f.d_char;
            }

            /* Extract attr/chars for inventory objects (by tval) */
            for (i = 0; i < Misc.tval_to_attr.Length; i++)
            {
                /* Default to white */
                Misc.tval_to_attr[i] = ConsoleColor.White;
            }

            if (!load_prefs)
            {
                return;
            }



            /* Graphic symbols */
            if (Misc.use_graphics != 0)
            {
                Prefs.process_pref_file("graf.prf", false, false);
            }

            /* Normal symbols */
            else
            {
                Prefs.process_pref_file("font.prf", false, false);
            }

            //#ifdef ALLOW_BORG_GRAPHICS
            //    /* Initialize the translation table for the borg */
            //    init_translate_visuals();
            //#endif /* ALLOW_BORG_GRAPHICS */
        }
Example #7
0
        /*
         * Attack the player via physical attacks.
         */
        //TODO: Submit this function to the Guiness book of world records for "Longest f*****g function"
        //TODO: Refactor this. Refactor this so f*****g hard.
        public bool make_attack_normal(Player.Player p)
        {
            Monster_Race r_ptr = Misc.r_info[r_idx];

            Monster_Lore l_ptr = Misc.l_list[r_idx];

            int i, tmp;

            short gold;

            string o_name;


            // Not allowed to attack
            if (r_ptr.flags.has(Monster_Flag.NEVER_BLOW.value))
            {
                return(false);
            }

            // Total armor
            int ac = p.state.ac + p.state.to_a;

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


            // Get the monster name (or "it")
            string m_name = monster_desc(0);

            // Get the "died from" information (i.e. "a kobold")
            string ddesc = monster_desc(Desc.SHOW | Desc.IND2);

            // Assume no blink
            bool blinked = false;

            // Scan through all blows
            for (int ap_cnt = 0; ap_cnt < Monster_Blow.MONSTER_BLOW_MAX; ap_cnt++)
            {
                bool visible  = false;
                bool obvious  = false;
                bool do_break = false;

                int power  = 0;
                int damage = 0;

                string act = null;

                if (r_ptr.blow[ap_cnt] == null)
                {
                    continue;
                }

                // Extract the attack infomation
                RBE effect = r_ptr.blow[ap_cnt].effect;
                RBM method = r_ptr.blow[ap_cnt].method;
                int d_dice = r_ptr.blow[ap_cnt].d_dice;
                int d_side = r_ptr.blow[ap_cnt].d_side;


                // Hack -- no more attacks
                if (method == RBM.NONE)
                {
                    break;
                }

                // Handle "leaving"
                if (p.leaving)
                {
                    break;
                }

                // Extract visibility (before blink)
                if (ml)
                {
                    visible = true;
                }

                // Extract visibility from carrying light
                if (r_ptr.flags.has(Monster_Flag.HAS_LIGHT.value))
                {
                    visible = true;
                }

                power = effect.power;

                // Monster hits player
                if (effect == null || check_hit(p, power, rlev))
                {
                    // Always disturbing
                    Cave.disturb(p, 1, 0);

                    // Hack -- Apply "protection from evil"
                    if (p.timed[(int)Timed_Effect.PROTEVIL] > 0)
                    {
                        // Learn about the evil flag
                        if (ml)
                        {
                            l_ptr.flags.on(Monster_Flag.EVIL.value);
                        }

                        if (r_ptr.flags.has(Monster_Flag.EVIL.value) && p.lev >= rlev && Random.randint0(100) + p.lev > 50)
                        {
                            // Message
                            Utilities.msg("%^s is repelled.", m_name);

                            // Hack -- Next attack
                            continue;
                        }
                    }


                    // Assume no cut or stun
                    bool do_cut  = method.do_cut;
                    bool do_stun = method.do_stun;

                    // Assume no sound
                    Message_Type sound_msg = method.sound_msg;

                    act = method.action;

                    // Describe the attack method
                    if (method == RBM.INSULT)
                    {
                        throw new NotImplementedException();
                        //act = desc_insult[Random.randint0(Misc.MAX_DESC_INSULT)];
                    }
                    else if (method == RBM.MOAN)
                    {
                        throw new NotImplementedException();
                        //act = desc_moan[Random.randint0(Misc.MAX_DESC_MOAN)];
                    }

                    // Message
                    if (act != null)
                    {
                        string name = Char.ToUpper(m_name[0]) + m_name.Substring(1);
                        Utilities.msgt(sound_msg, "{0} {1}", name, act);
                    }


                    // Hack -- assume all attacks are obvious
                    obvious = true;

                    // Roll out the damage
                    if (d_dice > 0 && d_side > 0)
                    {
                        damage = Random.damroll(d_dice, d_side);
                    }
                    else
                    {
                        damage = 0;
                    }

                    // Apply appropriate damage
                    if (effect.value == 0)
                    {
                        // Hack -- Assume obvious
                        obvious = true;

                        // Hack -- No damage
                        damage = 0;
                    }
                    else if (effect.value == RBE.HURT.value)
                    {
                        // Obvious
                        obvious = true;

                        // Hack -- Player armor reduces total damage
                        damage -= (damage * ((ac < 240) ? ac : 240) / 400);

                        // Take damage
                        Spell.take_hit(p, damage, ddesc);
                    }
                    else if (effect.value == RBE.POISON.value)
                    {
                        damage = Spell.adjust_dam(p, GF.POIS, damage, aspect.RANDOMISE,
                                                  Spell.check_for_resist(p, GF.POIS, p.state.flags, true));

                        // Take damage
                        Spell.take_hit(p, damage, ddesc);

                        // Take "poison" effect
                        if (p.inc_timed(Timed_Effect.POISONED, Random.randint1(rlev) + 5, true, true))
                        {
                            obvious = true;
                        }

                        // Learn about the player
                        monster_learn_resists(p, GF.POIS);
                    }
                    else if (effect.value == RBE.UN_BONUS.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Allow complete resist
                        //if (!check_state(p, OF_RES_DISEN, p.state.flags))
                        //{
                        //    // Apply disenchantment
                        //    if (apply_disenchant(0)) obvious = true;
                        //}

                        //// Learn about the player
                        //monster_learn_resists(m_ptr, p, GF_DISEN);
                    }
                    else if (effect.value == RBE.UN_POWER.value)
                    {
                        throw new NotImplementedException();
                        //int unpower = 0, newcharge;

                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Find an item
                        //for (k = 0; k < 10; k++)
                        //{
                        //    // Pick an item
                        //    i = randint0(INVEN_PACK);

                        //    // Obtain the item
                        //    o_ptr = &p.inventory[i];

                        //    // Skip non-objects
                        //    if (!o_ptr.kind) continue;

                        //    // Drain charged wands/staves
                        //    if ((o_ptr.tval == TV_STAFF) ||
                        //        (o_ptr.tval == TV_WAND))
                        //    {
                        //        // Charged?
                        //        if (o_ptr.pval[DEFAULT_PVAL])
                        //        {
                        //            // Get number of charge to drain
                        //            unpower = (rlev / (o_ptr.kind.level + 2)) + 1;

                        //            // Get new charge value, don't allow negative
                        //            newcharge = MAX((o_ptr.pval[DEFAULT_PVAL]
                        //                    - unpower),0);

                        //            // Remove the charges
                        //            o_ptr.pval[DEFAULT_PVAL] = newcharge;
                        //        }
                        //    }

                        //    if (unpower)
                        //    {
                        //        int heal = rlev * unpower;

                        //        msg("Energy drains from your pack!");

                        //        obvious = true;

                        //        // Don't heal more than max hp
                        //        heal = MIN(heal, maxhp - hp);

                        //        // Heal
                        //        hp += heal;

                        //        // Redraw (later) if needed
                        //        if (cave_monster(cave, p.health_who) == m_ptr)
                        //            p.redraw |= (PR_HEALTH);

                        //        // Combine / Reorder the pack
                        //        p.notice |= (PN_COMBINE | PN_REORDER);

                        //        // Redraw stuff
                        //        p.redraw |= (PR_INVEN);

                        //        // Affect only a single inventory slot
                        //        break;
                        //    }
                        //}
                    }
                    else if (effect.value == RBE.EAT_GOLD.value)
                    {
                        // Take damage
                        Spell.take_hit(p, damage, ddesc);

                        // Obvious
                        obvious = true;

                        // Saving throw (unless paralyzed) based on dex and level
                        if (p.timed[(int)Timed_Effect.PARALYZED] == 0 &&
                            (Random.randint0(100) < (Player.Player.adj_dex_safe[p.state.stat_ind[(int)Stat.Dex]] + p.lev)))
                        {
                            // Saving throw message
                            Utilities.msg("You quickly protect your money pouch!");

                            // Occasional blink anyway
                            if (Random.randint0(3) != 0)
                            {
                                blinked = true;
                            }
                        }

                        // Eat gold
                        else
                        {
                            gold = (short)((p.au / 10) + Random.randint1(25));
                            if (gold < 2)
                            {
                                gold = 2;
                            }
                            if (gold > 5000)
                            {
                                gold = (short)((p.au / 20) + Random.randint1(3000));
                            }
                            if (gold > p.au)
                            {
                                gold = (short)p.au;
                            }
                            p.au -= gold;
                            if (gold <= 0)
                            {
                                Utilities.msg("Nothing was stolen.");
                                break;
                            }
                            // Let the player know they were robbed
                            Utilities.msg("Your purse feels lighter.");
                            if (p.au != 0)
                            {
                                Utilities.msg("{0} coins were stolen!", (long)gold);
                            }
                            else
                            {
                                Utilities.msg("All of your coins were stolen!");
                            }

                            // While we have gold, put it in objects
                            while (gold > 0)
                            {
                                int amt;

                                // Create a new temporary object
                                //object_type o;
                                //object_wipe(&o);
                                Object.Object o = new Object.Object();
                                o.prep(Object.Object_Kind.objkind_get(TVal.TV_GOLD, (int)SVal.sval_gold.SV_GOLD), 0, aspect.MINIMISE);

                                // Amount of gold to put in this object
                                amt = gold > Misc.MAX_PVAL ? Misc.MAX_PVAL : gold;
                                o.pval[Misc.DEFAULT_PVAL] = (short)amt;
                                gold -= (short)amt;

                                // Set origin to stolen, so it is not confused with
                                // dropped treasure in monster_death
                                o.origin = Origin.STOLEN;

                                // Give the gold to the monster
                                carry(o);
                            }

                            // Redraw gold
                            p.redraw |= (Misc.PR_GOLD);

                            // Blink away
                            blinked = true;
                        }
                    }
                    else if (effect.value == RBE.EAT_ITEM.value)
                    {
                        // Take damage
                        Spell.take_hit(p, damage, ddesc);

                        // Saving throw (unless paralyzed) based on dex and level
                        if (p.timed[(int)Timed_Effect.PARALYZED] == 0 &&
                            (Random.randint0(100) < (Player.Player.adj_dex_safe[p.state.stat_ind[(int)Stat.Dex]] +
                                                     p.lev)))
                        {
                            // Saving throw message
                            Utilities.msg("You grab hold of your backpack!");

                            // Occasional "blink" anyway
                            blinked = true;

                            // Obvious
                            obvious = true;

                            // Done
                            break;
                        }

                        // Find an item
                        for (int k = 0; k < 10; k++)
                        {
                            Object.Object i_ptr;
                            //object_type object_type_body;

                            // Pick an item
                            i = Random.randint0(Misc.INVEN_PACK);

                            // Obtain the item
                            Object.Object o_ptr = p.inventory[i];

                            // Skip non-objects
                            if (o_ptr.kind == null)
                            {
                                continue;
                            }

                            // Skip artifacts
                            if (o_ptr.artifact != null)
                            {
                                continue;
                            }

                            // Get a description
                            o_name = o_ptr.object_desc(Object.Object.Detail.FULL);

                            // Message
                            Utilities.msg("{0}our {1} ({2}) was stolen!",
                                          ((o_ptr.number > 1) ? "One of y" : "Y"),
                                          o_name, Object.Object.index_to_label(i));

                            // Get local object
                            i_ptr = new Object.Object();                        //&object_type_body;

                            // Obtain local object
                            i_ptr = o_ptr.copy();

                            // Modify number
                            i_ptr.number = 1;

                            // Hack -- If a rod, staff, or wand, allocate total
                            // maximum timeouts or charges between those
                            // stolen and those missed. -LM-
                            o_ptr.distribute_charges(i_ptr, 1);

                            // Carry the object
                            carry(i_ptr);

                            // Steal the items
                            Object.Object.inven_item_increase(i, -1);
                            Object.Object.inven_item_optimize(i);

                            // Obvious
                            obvious = true;

                            // Blink away
                            blinked = true;

                            // Done
                            break;
                        }
                    }
                    else if (effect.value == RBE.EAT_FOOD.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Steal some food
                        //for (k = 0; k < 10; k++)
                        //{
                        //    // Pick an item from the pack
                        //    i = randint0(INVEN_PACK);

                        //    // Get the item
                        //    o_ptr = &p.inventory[i];

                        //    // Skip non-objects
                        //    if (!o_ptr.kind) continue;

                        //    // Skip non-food objects
                        //    if (o_ptr.tval != TV_FOOD) continue;

                        //    // Get a description
                        //    object_desc(o_name, sizeof(o_name), o_ptr,
                        //                ODESC_PREFIX | ODESC_BASE);

                        //    // Message
                        //    msg("%sour %s (%c) was eaten!",
                        //                ((o_ptr.number > 1) ? "One of y" : "Y"),
                        //                o_name, index_to_label(i));

                        //    // Steal the items
                        //    inven_item_increase(i, -1);
                        //    inven_item_optimize(i);

                        //    // Obvious
                        //    obvious = true;

                        //    // Done
                        //    break;
                        //}
                    }
                    else if (effect.value == RBE.EAT_LIGHT.value)
                    {
                        throw new NotImplementedException();
                        //bitflag f[OF_SIZE];

                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Get the light, and its flags
                        //o_ptr = &p.inventory[INVEN_LIGHT];
                        //object_flags(o_ptr, f);

                        //// Drain fuel where applicable
                        //if (!of_has(f, OF_NO_FUEL) && (o_ptr.timeout > 0))
                        //{
                        //    // Reduce fuel
                        //    o_ptr.timeout -= (250 + randint1(250));
                        //    if (o_ptr.timeout < 1) o_ptr.timeout = 1;

                        //    // Notice
                        //    if (!p.timed[TMD_BLIND])
                        //    {
                        //        msg("Your light dims.");
                        //        obvious = true;
                        //    }

                        //    // Redraw stuff
                        //    p.redraw |= (PR_EQUIP);
                        //}
                    }
                    else if (effect.value == RBE.ACID.value)
                    {
                        throw new NotImplementedException();
                        //// Obvious
                        //obvious = true;

                        //// Message
                        //msg("You are covered in acid!");

                        //// Special damage
                        //damage = adjust_dam(p, GF_ACID, damage, RANDOMISE,
                        //    check_for_resist(p, GF_ACID, p.state.flags, true));
                        //if (damage) {
                        //    take_hit(p, damage, ddesc);
                        //    inven_damage(p, GF_ACID, MIN(damage * 5, 300));
                        //}

                        //// Learn about the player
                        //monster_learn_resists(m_ptr, p, GF_ACID);
                    }
                    else if (effect.value == RBE.ELEC.value)
                    {
                        throw new NotImplementedException();
                        //// Obvious
                        //obvious = true;

                        //// Message
                        //msg("You are struck by electricity!");

                        //// Take damage (special)
                        //damage = adjust_dam(p, GF_ELEC, damage, RANDOMISE,
                        //    check_for_resist(p, GF_ELEC, p.state.flags, true));
                        //if (damage) {
                        //    take_hit(p, damage, ddesc);
                        //    inven_damage(p, GF_ELEC, MIN(damage * 5, 300));
                        //}

                        //// Learn about the player
                        //monster_learn_resists(m_ptr, p, GF_ELEC);
                    }
                    else if (effect.value == RBE.FIRE.value)
                    {
                        throw new NotImplementedException();
                        //// Obvious
                        //obvious = true;

                        //// Message
                        //msg("You are enveloped in flames!");

                        //// Take damage (special)
                        //damage = adjust_dam(p, GF_FIRE, damage, RANDOMISE,
                        //    check_for_resist(p, GF_FIRE, p.state.flags, true));
                        //if (damage) {
                        //    take_hit(p, damage, ddesc);
                        //    inven_damage(p, GF_FIRE, MIN(damage * 5, 300));
                        //}

                        //// Learn about the player
                        //monster_learn_resists(m_ptr, p, GF_FIRE);
                    }
                    else if (effect.value == RBE.COLD.value)
                    {
                        throw new NotImplementedException();
                        //// Obvious
                        //obvious = true;

                        //// Message
                        //msg("You are covered with frost!");

                        //// Take damage (special)
                        //damage = adjust_dam(p, GF_COLD, damage, RANDOMISE,
                        //    check_for_resist(p, GF_COLD, p.state.flags, true));
                        //if (damage) {
                        //    take_hit(p, damage, ddesc);
                        //    inven_damage(p, GF_COLD, MIN(damage * 5, 300));
                        //}

                        //// Learn about the player
                        //monster_learn_resists(m_ptr, p, GF_COLD);
                    }
                    else if (effect.value == RBE.BLIND.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Increase "blind"
                        //if (player_inc_timed(p, TMD_BLIND, 10 + randint1(rlev), true, true))
                        //    obvious = true;

                        //// Learn about the player
                        //update_smart_learn(m_ptr, p, OF_RES_BLIND);
                    }
                    else if (effect.value == RBE.CONFUSE.value)
                    {
                        // Take damage
                        Spell.take_hit(p, damage, ddesc);

                        // Increase "confused"
                        if (p.inc_timed(Timed_Effect.CONFUSED, 3 + Random.randint1(rlev), true, true))
                        {
                            obvious = true;
                        }

                        // Learn about the player
                        update_smart_learn(p, Object.Object_Flag.RES_CONFU);
                    }
                    else if (effect.value == RBE.TERRIFY.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Increase "afraid"
                        //if (randint0(100) < p.state.skills[SKILL_SAVE])
                        //{
                        //    msg("You stand your ground!");
                        //    obvious = true;
                        //}
                        //else
                        //{
                        //    if (player_inc_timed(p, TMD_AFRAID, 3 + randint1(rlev), true,
                        //            true))
                        //        obvious = true;
                        //}

                        //// Learn about the player
                        //update_smart_learn(m_ptr, p, OF_RES_FEAR);
                    }
                    else if (effect.value == RBE.PARALYZE.value)
                    {
                        // Hack -- Prevent perma-paralysis via damage
                        if (p.timed[(int)Timed_Effect.PARALYZED] != 0 && (damage < 1))
                        {
                            damage = 1;
                        }

                        // Take damage
                        Spell.take_hit(p, damage, ddesc);

                        // Increase "paralyzed"
                        if (Random.randint0(100) < p.state.skills[(int)Skill.SAVE])
                        {
                            Utilities.msg("You resist the effects!");
                            obvious = true;
                        }
                        else
                        {
                            if (p.inc_timed(Timed_Effect.PARALYZED, 3 + Random.randint1(rlev), true, true))
                            {
                                obvious = true;
                            }
                        }

                        // Learn about the player
                        update_smart_learn(p, Object_Flag.FREE_ACT);
                    }
                    else if (effect.value == RBE.LOSE_STR.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Damage (stat)
                        //if (do_dec_stat(A_STR, false)) obvious = true;
                    }
                    else if (effect.value == RBE.LOSE_INT.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Damage (stat)
                        //if (do_dec_stat(A_INT, false)) obvious = true;
                    }
                    else if (effect.value == RBE.LOSE_WIS.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Damage (stat)
                        //if (do_dec_stat(A_WIS, false)) obvious = true;
                    }
                    else if (effect.value == RBE.LOSE_DEX.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Damage (stat)
                        //if (do_dec_stat(A_DEX, false)) obvious = true;
                    }
                    else if (effect.value == RBE.LOSE_CON.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Damage (stat)
                        //if (do_dec_stat(A_CON, false)) obvious = true;
                    }
                    else if (effect.value == RBE.LOSE_CHR.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Damage (stat)
                        //if (do_dec_stat(A_CHR, false)) obvious = true;
                    }
                    else if (effect.value == RBE.LOSE_ALL.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Damage (stats)
                        //if (do_dec_stat(A_STR, false)) obvious = true;
                        //if (do_dec_stat(A_DEX, false)) obvious = true;
                        //if (do_dec_stat(A_CON, false)) obvious = true;
                        //if (do_dec_stat(A_INT, false)) obvious = true;
                        //if (do_dec_stat(A_WIS, false)) obvious = true;
                        //if (do_dec_stat(A_CHR, false)) obvious = true;
                    }
                    else if (effect.value == RBE.SHATTER.value)
                    {
                        throw new NotImplementedException();
                        //// Obvious
                        //obvious = true;

                        //// Hack -- Reduce damage based on the player armor class
                        //damage -= (damage * ((ac < 240) ? ac : 240) / 400);

                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Radius 8 earthquake centered at the monster
                        //if (damage > 23)
                        //{
                        //    int px_old = p.px;
                        //    int py_old = p.py;

                        //    earthquake(fy, fx, 8);

                        //    // Stop the blows if the player is pushed away
                        //    if ((px_old != p.px) ||
                        //        (py_old != p.py))
                        //        do_break = true;
                        //}
                    }
                    else if (effect.value == RBE.EXP_10.value)
                    {
                        throw new NotImplementedException();
                        //// Obvious
                        //obvious = true;

                        //// Take damage
                        //take_hit(p, damage, ddesc);
                        //update_smart_learn(m_ptr, p_ptr, OF_HOLD_LIFE);

                        //if (check_state(p, OF_HOLD_LIFE, p.state.flags) && (randint0(100) < 95))
                        //{
                        //    msg("You keep hold of your life force!");
                        //}
                        //else
                        //{
                        //    s32b d = damroll(10, 6) + (p.exp/100) * MON_DRAIN_LIFE;
                        //    if (check_state(p, OF_HOLD_LIFE, p.state.flags))
                        //    {
                        //        msg("You feel your life slipping away!");
                        //        player_exp_lose(p, d / 10, false);
                        //    }
                        //    else
                        //    {
                        //        msg("You feel your life draining away!");
                        //        player_exp_lose(p, d, false);
                        //    }
                        //}
                    }
                    else if (effect.value == RBE.EXP_20.value)
                    {
                        throw new NotImplementedException();
                        //// Obvious
                        //obvious = true;

                        //// Take damage
                        //take_hit(p, damage, ddesc);
                        //update_smart_learn(m_ptr, p_ptr, OF_HOLD_LIFE);

                        //if (check_state(p, OF_HOLD_LIFE, p.state.flags) && (randint0(100) < 90))
                        //{
                        //    msg("You keep hold of your life force!");
                        //}
                        //else
                        //{
                        //    s32b d = damroll(20, 6) + (p.exp / 100) * MON_DRAIN_LIFE;

                        //    if (check_state(p, OF_HOLD_LIFE, p.state.flags))
                        //    {
                        //        msg("You feel your life slipping away!");
                        //        player_exp_lose(p, d / 10, false);
                        //    }
                        //    else
                        //    {
                        //        msg("You feel your life draining away!");
                        //        player_exp_lose(p, d, false);
                        //    }
                        //}
                    }
                    else if (effect.value == RBE.EXP_40.value)
                    {
                        throw new NotImplementedException();
                        //// Obvious
                        //obvious = true;

                        //// Take damage
                        //take_hit(p, damage, ddesc);
                        //update_smart_learn(m_ptr, p_ptr, OF_HOLD_LIFE);

                        //if (check_state(p, OF_HOLD_LIFE, p.state.flags) && (randint0(100) < 75))
                        //{
                        //    msg("You keep hold of your life force!");
                        //}
                        //else
                        //{
                        //    s32b d = damroll(40, 6) + (p.exp / 100) * MON_DRAIN_LIFE;

                        //    if (check_state(p, OF_HOLD_LIFE, p.state.flags))
                        //    {
                        //        msg("You feel your life slipping away!");
                        //        player_exp_lose(p, d / 10, false);
                        //    }
                        //    else
                        //    {
                        //        msg("You feel your life draining away!");
                        //        player_exp_lose(p, d, false);
                        //    }
                        //}
                    }
                    else if (effect.value == RBE.EXP_80.value)
                    {
                        throw new NotImplementedException();
                        //// Obvious
                        //obvious = true;

                        //// Take damage
                        //take_hit(p, damage, ddesc);
                        //update_smart_learn(m_ptr, p_ptr, OF_HOLD_LIFE);

                        //if (check_state(p, OF_HOLD_LIFE, p.state.flags) && (randint0(100) < 50))
                        //{
                        //    msg("You keep hold of your life force!");
                        //}
                        //else
                        //{
                        //    s32b d = damroll(80, 6) + (p.exp / 100) * MON_DRAIN_LIFE;

                        //    if (check_state(p, OF_HOLD_LIFE, p.state.flags))
                        //    {
                        //        msg("You feel your life slipping away!");
                        //        player_exp_lose(p, d / 10, false);
                        //    }
                        //    else
                        //    {
                        //        msg("You feel your life draining away!");
                        //        player_exp_lose(p, d, false);
                        //    }
                        //}
                    }
                    else if (effect.value == RBE.HALLU.value)
                    {
                        throw new NotImplementedException();
                        //// Take damage
                        //take_hit(p, damage, ddesc);

                        //// Increase "image"
                        //if (player_inc_timed(p, TMD_IMAGE, 3 + randint1(rlev / 2), true, true))
                        //    obvious = true;

                        //// Learn about the player
                        //monster_learn_resists(m_ptr, p, GF_CHAOS);
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }


                    // Hack -- only one of cut or stun
                    if (do_cut && do_stun)
                    {
                        // Cancel cut
                        if (Random.randint0(100) < 50)
                        {
                            do_cut = false;
                        }

                        // Cancel stun
                        else
                        {
                            do_stun = false;
                        }
                    }

                    // Handle cut
                    if (do_cut)
                    {
                        int k = 0;

                        // Critical hit (zero if non-critical)
                        tmp = monster_critical(d_dice, d_side, damage);

                        // Roll for damage
                        switch (tmp)
                        {
                        case 0: k = 0; break;

                        case 1: k = Random.randint1(5); break;

                        case 2: k = Random.randint1(5) + 5; break;

                        case 3: k = Random.randint1(20) + 20; break;

                        case 4: k = Random.randint1(50) + 50; break;

                        case 5: k = Random.randint1(100) + 100; break;

                        case 6: k = 300; break;

                        default: k = 500; break;
                        }

                        // Apply the cut
                        if (k != 0)
                        {
                            p.inc_timed(Timed_Effect.CUT, k, true, true);
                        }
                    }

                    // Handle stun
                    if (do_stun)
                    {
                        int k;

                        // Critical hit (zero if non-critical)
                        tmp = monster_critical(d_dice, d_side, damage);

                        // Roll for damage
                        switch (tmp)
                        {
                        case 0: k = 0; break;

                        case 1: k = Random.randint1(5); break;

                        case 2: k = Random.randint1(10) + 10; break;

                        case 3: k = Random.randint1(20) + 20; break;

                        case 4: k = Random.randint1(30) + 30; break;

                        case 5: k = Random.randint1(40) + 40; break;

                        case 6: k = 100; break;

                        default: k = 200; break;
                        }

                        // Apply the stun
                        if (k != 0)
                        {
                            p.inc_timed(Timed_Effect.STUN, k, true, true);
                        }
                    }
                }

                // Monster missed player
                else
                {
                    // Analyze failed attacks
                    if (method == RBM.HIT ||
                        method == RBM.TOUCH ||
                        method == RBM.PUNCH ||
                        method == RBM.KICK ||
                        method == RBM.CLAW ||
                        method == RBM.BITE ||
                        method == RBM.STING ||
                        method == RBM.BUTT ||
                        method == RBM.CRUSH ||
                        method == RBM.ENGULF)
                    {
                        // Visible monsters
                        if (ml)
                        {
                            // Disturbing
                            Cave.disturb(p, 1, 0);

                            // Message
                            //Utilities.msg("%^s misses you.", m_name);
                            Utilities.msg("{0} misses you.", m_name);
                        }
                    }
                }


                // Analyze "visible" monsters only
                if (visible)
                {
                    // Count "obvious" attacks (and ones that cause damage)
                    if (obvious || damage != 0 || (l_ptr.blows[ap_cnt] > 10))
                    {
                        // Count attacks of this type
                        if (l_ptr.blows[ap_cnt] < byte.MaxValue)
                        {
                            l_ptr.blows[ap_cnt]++;
                        }
                    }
                }

                // Skip the other blows if necessary
                if (do_break)
                {
                    break;
                }
            }


            // Blink away
            if (blinked)
            {
                Utilities.msg("There is a puff of smoke!");
                throw new NotImplementedException();
                //teleport_away(m_ptr, MAX_SIGHT * 2 + 5);
            }


            // Always notice cause of death
            if (p.is_dead && (l_ptr.deaths < short.MaxValue))
            {
                l_ptr.deaths++;
            }


            // Assume we attacked
            // Nick: Because, based on the length of this function,
            // literally a million other things could have happened
            return(true);
        }
Example #8
0
        static long max_dam(Monster_Race r_ptr)
        {
            int rlev, i;
            int melee_dam = 0, atk_dam = 0, spell_dam = 0;
            int dam = 1;

            /* Extract the monster level, force 1 for town monsters */
            rlev = ((r_ptr.level >= 1) ? r_ptr.level : 1);

            /* Assume single resist for the elemental attacks */
            spell_dam = Monster_Spell_Flag.best_spell_power(r_ptr, 1);

            /* Hack - Apply over 10 rounds */
            spell_dam *= 10;

            /* Scale for frequency and availability of mana / ammo */
            if (spell_dam != 0)
            {
                int freq = r_ptr.freq_spell;

                /* Hack -- always get 1 shot */
                if (freq < 10)
                {
                    freq = 10;
                }

                /* Adjust for frequency */
                spell_dam = spell_dam * freq / 100;
            }

            /* Check attacks */
            for (i = 0; i < 4; i++)
            {
                if (r_ptr.blow[i] == null)
                {
                    continue;
                }
                /* Extract the attack infomation */
                Monster_Blow.RBE effect = r_ptr.blow[i].effect;
                Monster_Blow.RBM method = r_ptr.blow[i].method;
                int d_dice = r_ptr.blow[i].d_dice;
                int d_side = r_ptr.blow[i].d_side;

                /* Hack -- no more attacks */
                if (method == null)
                {
                    continue;
                }

                /* Assume maximum damage*/
                atk_dam = (int)blow_effect(effect, d_dice * d_side, r_ptr.level);

                /*stun definitely most dangerous*/
                if (method == Monster_Blow.RBM.PUNCH || method == Monster_Blow.RBM.KICK ||
                    method == Monster_Blow.RBM.BUTT || method == Monster_Blow.RBM.CRUSH)
                {
                    atk_dam *= 4;
                    atk_dam /= 3;
                }
                else if (method == Monster_Blow.RBM.CLAW || method == Monster_Blow.RBM.BITE)
                {
                    atk_dam *= 7;
                    atk_dam /= 5;
                }


                /* Normal melee attack */
                if (!r_ptr.flags.has(Monster_Flag.NEVER_BLOW.value))
                {
                    /* Keep a running total */
                    melee_dam += atk_dam;
                }
            }

            /*
             * Apply damage over 10 rounds. We assume that the monster has to make contact first.
             * Hack - speed has more impact on melee as has to stay in contact with player.
             * Hack - this is except for pass wall and kill wall monsters which can always get to the player.
             * Hack - use different values for huge monsters as they strike out to range 2.
             */
            if (r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.KILL_WALL.value, Monster_Flag.PASS_WALL.value))
            {
                melee_dam *= 10;
            }
            else
            {
                melee_dam = melee_dam * 3 + melee_dam * Misc.extract_energy[r_ptr.speed + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] / 7;
            }

            /*
             * Scale based on attack accuracy. We make a massive number of assumptions here and just use monster level.
             */
            melee_dam = melee_dam * Math.Min(45 + rlev * 3, 95) / 100;

            /* Hack -- Monsters that multiply ignore the following reductions */
            if (!r_ptr.flags.has(Monster_Flag.MULTIPLY.value))
            {
                /*Reduce damamge potential for monsters that move randomly */
                if (r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.RAND_25.value, Monster_Flag.RAND_50.value))
                {
                    int reduce = 100;

                    if (r_ptr.flags.has(Monster_Flag.RAND_25.value))
                    {
                        reduce -= 25;
                    }
                    if (r_ptr.flags.has(Monster_Flag.RAND_50.value))
                    {
                        reduce -= 50;
                    }

                    /*even moving randomly one in 8 times will hit the player*/
                    reduce += (100 - reduce) / 8;

                    /* adjust the melee damage*/
                    melee_dam = (melee_dam * reduce) / 100;
                }

                /*monsters who can't move aren't nearly as much of a combat threat*/
                if (r_ptr.flags.has(Monster_Flag.NEVER_MOVE.value))
                {
                    if (r_ptr.spell_flags.has(Monster_Spell_Flag.TELE_TO.value) ||
                        r_ptr.spell_flags.has(Monster_Spell_Flag.BLINK.value))
                    {
                        /* Scale for frequency */
                        melee_dam = melee_dam / 5 + 4 * melee_dam * r_ptr.freq_spell / 500;

                        /* Incorporate spell failure chance */
                        if (!r_ptr.flags.has(Monster_Flag.STUPID.value))
                        {
                            melee_dam = melee_dam / 5 + 4 * melee_dam * Math.Min(75 + (rlev + 3) / 4, 100) / 500;
                        }
                    }
                    else if (r_ptr.flags.has(Monster_Flag.INVISIBLE.value))
                    {
                        melee_dam /= 3;
                    }
                    else
                    {
                        melee_dam /= 5;
                    }
                }
            }

            /* But keep at a minimum */
            if (melee_dam < 1)
            {
                melee_dam = 1;
            }

            /*
             * Combine spell and melee damage
             */
            dam = (spell_dam + melee_dam);

            r_ptr.highest_threat = (short)dam;
            r_ptr.spell_dam      = spell_dam;           /*AMF:DEBUG*/
            r_ptr.melee_dam      = melee_dam;           /*AMF:DEBUG*/

            /*
             * Adjust for speed.  Monster at speed 120 will do double damage,
             * monster at speed 100 will do half, etc.  Bonus for monsters who can haste self.
             */
            dam = (dam * Misc.extract_energy[r_ptr.speed + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)]) / 10;

            /*
             * Adjust threat for speed -- multipliers are more threatening.
             */
            if (r_ptr.flags.has(Monster_Flag.MULTIPLY.value))
            {
                r_ptr.highest_threat = (short)((r_ptr.highest_threat * Misc.extract_energy[r_ptr.speed + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)]) / 5);
            }

            /*
             * Adjust threat for friends.
             */
            if (r_ptr.flags.has(Monster_Flag.FRIENDS.value))
            {
                r_ptr.highest_threat *= 2;
            }
            else if (r_ptr.flags.has(Monster_Flag.FRIEND.value))
            {
                r_ptr.highest_threat = (short)(r_ptr.highest_threat * 3 / 2);
            }

            /*but deep in a minimum*/
            if (dam < 1)
            {
                dam = 1;
            }

            /* We're done */
            return(dam);
        }
Example #9
0
 /* Parsing functions for monster.txt */
 public static Parser.Error parse_r_n(Parser p)
 {
     Monster_Race h = p.priv as Monster_Race;
     Monster_Race r = new Monster_Race();
     r.Next = h;
     r.ridx = p.getuint("index");
     r.Name = p.getstr("name");
     p.priv = r;
     return Parser.Error.NONE;
 }
Example #10
0
        static long hp_adjust(Monster_Race r_ptr)
        {
            long hp;
            int  resists    = 1;
            int  hide_bonus = 0;

            /* Get the monster base hitpoints */
            hp = r_ptr.avg_hp;

            /* Never moves with no ranged attacks - high hit points count for less */
            if (r_ptr.flags.has(Monster_Flag.NEVER_MOVE.value) && !(r_ptr.freq_innate != 0 || r_ptr.freq_spell != 0))
            {
                hp /= 2;
                if (hp < 1)
                {
                    hp = 1;
                }
            }

            /* Just assume healers have more staying power */
            if (r_ptr.spell_flags.has(Monster_Spell_Flag.HEAL.value))
            {
                hp = (hp * 6) / 5;
            }

            /* Miscellaneous improvements */
            if (r_ptr.flags.has(Monster_Flag.REGENERATE.value))
            {
                hp *= 10; hp /= 9;
            }
            if (r_ptr.flags.has(Monster_Flag.PASS_WALL.value))
            {
                hp *= 3; hp /= 2;
            }

            /* Calculate hide bonus */
            if (r_ptr.flags.has(Monster_Flag.EMPTY_MIND.value))
            {
                hide_bonus += 2;
            }
            else
            {
                if (r_ptr.flags.has(Monster_Flag.COLD_BLOOD.value))
                {
                    hide_bonus += 1;
                }
                if (r_ptr.flags.has(Monster_Flag.WEIRD_MIND.value))
                {
                    hide_bonus += 1;
                }
            }

            /* Invisibility */
            if (r_ptr.flags.has(Monster_Flag.INVISIBLE.value))
            {
                hp = (hp * (r_ptr.level + hide_bonus + 1)) / Math.Max(1, (int)r_ptr.level);
            }

            /* Monsters that can teleport are a hassle, and can easily run away */
            if (r_ptr.spell_flags.test(Monster_Spell_Flag.SIZE, Monster_Spell_Flag.TPORT.value, Monster_Spell_Flag.TELE_AWAY.value,
                                       Monster_Spell_Flag.TELE_LEVEL.value))
            {
                hp = (hp * 6) / 5;
            }

            /*
             * Monsters that multiply are tougher to kill
             */
            if (r_ptr.flags.has(Monster_Flag.MULTIPLY.value))
            {
                hp *= 2;
            }

            /* Monsters with resistances are harder to kill.
             * Therefore effective slays / brands against them are worth more. */
            if (r_ptr.flags.has(Monster_Flag.IM_ACID.value))
            {
                resists += 2;
            }
            if (r_ptr.flags.has(Monster_Flag.IM_FIRE.value))
            {
                resists += 2;
            }
            if (r_ptr.flags.has(Monster_Flag.IM_COLD.value))
            {
                resists += 2;
            }
            if (r_ptr.flags.has(Monster_Flag.IM_ELEC.value))
            {
                resists += 2;
            }
            if (r_ptr.flags.has(Monster_Flag.IM_POIS.value))
            {
                resists += 2;
            }

            /* Bonus for multiple basic resists and weapon resists */
            if (resists >= 12)
            {
                resists *= 6;
            }
            else if (resists >= 10)
            {
                resists *= 4;
            }
            else if (resists >= 8)
            {
                resists *= 3;
            }
            else if (resists >= 6)
            {
                resists *= 2;
            }

            /* If quite resistant, reduce resists by defense holes */
            if (resists >= 6)
            {
                if (r_ptr.flags.has(Monster_Flag.HURT_ROCK.value))
                {
                    resists -= 1;
                }
                if (r_ptr.flags.has(Monster_Flag.HURT_LIGHT.value))
                {
                    resists -= 1;
                }
                if (!r_ptr.flags.has(Monster_Flag.NO_SLEEP.value))
                {
                    resists -= 3;
                }
                if (!r_ptr.flags.has(Monster_Flag.NO_FEAR.value))
                {
                    resists -= 2;
                }
                if (!r_ptr.flags.has(Monster_Flag.NO_CONF.value))
                {
                    resists -= 2;
                }
                if (!r_ptr.flags.has(Monster_Flag.NO_STUN.value))
                {
                    resists -= 1;
                }

                if (resists < 5)
                {
                    resists = 5;
                }
            }

            /* If quite resistant, bonus for high resists */
            if (resists >= 3)
            {
                if (r_ptr.flags.has(Monster_Flag.IM_WATER.value))
                {
                    resists += 1;
                }
                if (r_ptr.flags.has(Monster_Flag.RES_NETH.value))
                {
                    resists += 1;
                }
                if (r_ptr.flags.has(Monster_Flag.RES_NEXUS.value))
                {
                    resists += 1;
                }
                if (r_ptr.flags.has(Monster_Flag.RES_DISE.value))
                {
                    resists += 1;
                }
            }

            /* Scale resists */
            resists = resists * 25;

            /* Monster resistances */
            if (resists < (r_ptr.ac + resists) / 3)
            {
                hp += (hp * resists) / (150 + r_ptr.level);
            }
            else
            {
                hp += (hp * (r_ptr.ac + resists) / 3) / (150 + r_ptr.level);
            }

            /*boundry control*/
            if (hp < 1)
            {
                hp = 1;
            }

            return(hp);
        }
Example #11
0
        public static int r_power(Monster_Race[] races)
        {
            //God damn it C...

            /*
             * ang_file *mon_fp;
             * char buf[1024];*/
            bool dump = false;

            /* Allocate space for power */
            long[] power     = new long[Misc.z_info.r_max];
            long[] tot_hp    = new long[Misc.MAX_DEPTH];
            long[] tot_dam   = new long[Misc.MAX_DEPTH];
            long[] mon_count = new long[Misc.MAX_DEPTH];

            for (int iteration = 0; iteration < 3; iteration++)
            {
                /* Reset the sum of all monster power values */
                tot_mon_power = 0;

                /* Make sure all arrays start at zero */
                for (int i = 0; i < Misc.MAX_DEPTH; i++)
                {
                    tot_hp[i]    = 0;
                    tot_dam[i]   = 0;
                    mon_count[i] = 0;
                }

                /* Go through r_info and evaluate power ratings & flows. */
                for (int i = 0; i < Misc.z_info.r_max; i++)
                {
                    /* Point at the "info" */
                    Monster_Race r_ptr = races[i];
                    if (r_ptr == null)
                    {
                        continue;
                    }

                    /* Set the current level */
                    byte lvl = r_ptr.level;

                    /* Maximum damage this monster can do in 10 game turns */
                    long dam = max_dam(r_ptr);

                    /* Adjust hit points based on resistances */
                    long hp = hp_adjust(r_ptr);

                    /* Hack -- set exp */
                    if (lvl == 0)
                    {
                        r_ptr.mexp = 0;
                    }
                    else
                    {
                        /* Compute depths of non-unique monsters */
                        if (r_ptr.flags.has(Monster_Flag.UNIQUE.value))
                        {
                            long mexp   = (hp * dam) / 25;
                            long threat = r_ptr.highest_threat;

                            /* Compute level algorithmically */
                            int j;
                            for (j = 1; (mexp > j + 4) || (threat > j + 5);
                                 mexp -= j * j, threat -= (j + 4), j++)
                            {
                                ;
                            }

                            /* Set level */
                            lvl = (byte)Math.Min((j > 250 ? 90 + (j - 250) / 20 :                       /* Level 90+ */
                                                  (j > 130 ? 70 + (j - 130) / 6 :                       /* Level 70+ */
                                                   (j > 40 ? 40 + (j - 40) / 3 :                        /* Level 40+ */
                                                    j))), 99);

                            /* Set level */
                            if (Misc.arg_rebalance)
                            {
                                r_ptr.level = lvl;
                            }
                        }

                        if (Misc.arg_rebalance)
                        {
                            /* Hack -- for Ungoliant */
                            if (hp > 10000)
                            {
                                r_ptr.mexp = (int)((hp / 25) * (dam / lvl));
                            }
                            else
                            {
                                r_ptr.mexp = (int)((hp * dam) / (lvl * 25));
                            }

                            /* Round to 2 significant figures */
                            if (r_ptr.mexp > 100)
                            {
                                if (r_ptr.mexp < 1000)
                                {
                                    r_ptr.mexp  = (r_ptr.mexp + 5) / 10;
                                    r_ptr.mexp *= 10;
                                }
                                else if (r_ptr.mexp < 10000)
                                {
                                    r_ptr.mexp  = (r_ptr.mexp + 50) / 100;
                                    r_ptr.mexp *= 100;
                                }
                                else if (r_ptr.mexp < 100000)
                                {
                                    r_ptr.mexp  = (r_ptr.mexp + 500) / 1000;
                                    r_ptr.mexp *= 1000;
                                }
                                else if (r_ptr.mexp < 1000000)
                                {
                                    r_ptr.mexp  = (r_ptr.mexp + 5000) / 10000;
                                    r_ptr.mexp *= 10000;
                                }
                                else if (r_ptr.mexp < 10000000)
                                {
                                    r_ptr.mexp  = (r_ptr.mexp + 50000) / 100000;
                                    r_ptr.mexp *= 100000;
                                }
                            }
                        }
                    }

                    /* If we're rebalancing, this is a nop, if not, we restore the orig value */
                    lvl = r_ptr.level;
                    if ((lvl != 0) && (r_ptr.mexp < 1L))
                    {
                        r_ptr.mexp = 1;
                    }

                    /*
                     * Hack - We have to use an adjustment factor to prevent overflow.
                     * Try to scale evenly across all levels instead of scaling by level.
                     */
                    hp /= 2;
                    if (hp < 1)
                    {
                        hp = 1;
                    }
                    r_ptr.hp = hp;                              /*AMF:DEBUG*/

                    /* Define the power rating */
                    power[i] = hp * dam;

                    /* Adjust for group monsters.  Average in-level group size is 5 */
                    if (!r_ptr.flags.has(Monster_Flag.UNIQUE.value))
                    {
                        if (r_ptr.flags.has(Monster_Flag.FRIEND.value))
                        {
                            power[i] *= 2;
                        }
                        else if (r_ptr.flags.has(Monster_Flag.FRIENDS.value))
                        {
                            power[i] *= 5;
                        }
                    }

                    /* Adjust for escorts */
                    if (r_ptr.flags.has(Monster_Flag.ESCORTS.value))
                    {
                        power[i] *= 3;
                    }
                    if (r_ptr.flags.has(Monster_Flag.ESCORT.value) && !r_ptr.flags.has(Monster_Flag.ESCORTS.value))
                    {
                        power[i] *= 2;
                    }

                    /* Adjust for multiplying monsters. This is modified by the speed,
                     * as fast multipliers are much worse than slow ones. We also adjust for
                     * ability to bypass walls or doors.
                     */
                    if (r_ptr.flags.has(Monster_Flag.MULTIPLY.value))
                    {
                        if (r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.KILL_WALL.value, Monster_Flag.PASS_WALL.value))
                        {
                            power[i] = Math.Max(power[i], power[i] * Misc.extract_energy[r_ptr.speed
                                                                                         + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)]);
                        }
                        else if (r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.OPEN_DOOR.value, Monster_Flag.BASH_DOOR.value))
                        {
                            power[i] = Math.Max(power[i], power[i] * Misc.extract_energy[r_ptr.speed
                                                                                         + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] * 3 / 2);
                        }
                        else
                        {
                            power[i] = Math.Max(power[i], power[i] * Misc.extract_energy[r_ptr.speed
                                                                                         + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] / 2);
                        }
                    }

                    /*
                     * Update the running totals - these will be used as divisors later
                     * Total HP / dam / count for everything up to the current level
                     */
                    for (int j = lvl; j < (lvl == 0 ? lvl + 1 : Misc.MAX_DEPTH); j++)
                    {
                        int count = 10;

                        /* Uniques don't count towards monster power on the level. */
                        if (r_ptr.flags.has(Monster_Flag.UNIQUE.value))
                        {
                            continue;
                        }

                        /* Specifically placed monsters don't count towards monster power
                         * on the level. */
                        if (!(r_ptr.rarity != 0))
                        {
                            continue;
                        }

                        /* Hack -- provide adjustment factor to prevent overflow */
                        if ((j == 90) && (r_ptr.level < 90))
                        {
                            hp  /= 10;
                            dam /= 10;
                        }

                        if ((j == 65) && (r_ptr.level < 65))
                        {
                            hp  /= 10;
                            dam /= 10;
                        }

                        if ((j == 40) && (r_ptr.level < 40))
                        {
                            hp  /= 10;
                            dam /= 10;
                        }

                        /*
                         * Hack - if it's a group monster or multiplying monster, add several to the count
                         * so that the averages don't get thrown off
                         */

                        if (r_ptr.flags.has(Monster_Flag.FRIEND.value))
                        {
                            count = 20;
                        }
                        else if (r_ptr.flags.has(Monster_Flag.FRIENDS.value))
                        {
                            count = 50;
                        }

                        if (r_ptr.flags.has(Monster_Flag.MULTIPLY.value))
                        {
                            if (r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.KILL_WALL.value, Monster_Flag.PASS_WALL.value))
                            {
                                count = Math.Max(1, (int)Misc.extract_energy[r_ptr.speed
                                                                             + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)]) * count;
                            }
                            else if (r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.OPEN_DOOR.value, Monster_Flag.BASH_DOOR.value))
                            {
                                count = Math.Max(1, Misc.extract_energy[r_ptr.speed
                                                                        + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] * 3 / 2) * count;
                            }
                            else
                            {
                                count = Math.Max(1, Misc.extract_energy[r_ptr.speed
                                                                        + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] / 2) * count;
                            }
                        }

                        /* Very rare monsters count less towards total monster power on the
                         * level. */
                        if (r_ptr.rarity > count)
                        {
                            hp  = hp * count / r_ptr.rarity;
                            dam = dam * count / r_ptr.rarity;

                            count = r_ptr.rarity;
                        }

                        tot_hp[j]  += hp;
                        tot_dam[j] += dam;

                        mon_count[j] += count / r_ptr.rarity;
                    }
                }

                /* Apply divisors now */
                for (int i = 0; i < Misc.z_info.r_max; i++)
                {
                    int new_power;

                    /* Point at the "info" */
                    Monster_Race r_ptr = races[i];
                    if (r_ptr == null)
                    {
                        continue;
                    }

                    /* Extract level */
                    byte lvl = r_ptr.level;

                    /* Paranoia */
                    if (tot_hp[lvl] != 0 && tot_dam[lvl] != 0)
                    {
                        /* Divide by average HP and av damage for all in-level monsters */
                        /* Note we have factored in the above 'adjustment factor' */
                        long av_hp  = tot_hp[lvl] * 10 / mon_count[lvl];
                        long av_dam = tot_dam[lvl] * 10 / mon_count[lvl];

                        /* Assign monster power */
                        r_ptr.power = power[i];

                        /* Justifiable paranoia - avoid divide by zero errors */
                        if (av_hp > 0)
                        {
                            power[i] = power[i] / av_hp;
                        }
                        if (av_dam > 0)
                        {
                            power[i] = power[i] / av_dam;
                        }

                        /* Assign monster scaled power */
                        r_ptr.scaled_power = power[i];

                        /* Never less than 1 */
                        if (r_ptr.power < 1)
                        {
                            r_ptr.power = 1;
                        }

                        /* Get power */
                        new_power = (int)r_ptr.power;

                        /* Compute rarity algorithmically */
                        int j;
                        for (j = 1; new_power > j; new_power -= j * j, j++)
                        {
                            ;
                        }

                        /* Set rarity */
                        if (Misc.arg_rebalance)
                        {
                            r_ptr.rarity = (byte)j;
                        }
                    }
                }
            }
            /* Determine total monster power */
            for (int i = 0; i < Misc.z_info.r_max; i++)
            {
                Monster_Race r = Misc.r_info[i];
                if (r == null)
                {
                    continue;
                }

                tot_mon_power += (int)r.scaled_power;
            }

            /*	msg("Tot mon power is %d", tot_mon_power); */

            if (dump)
            {
                /* dump the power details */
                throw new NotImplementedException();
                //path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "mon_power.txt");
                //mon_fp = file_open(buf, MODE_WRITE, FTYPE_TEXT);

                //file_putf(mon_fp, "ridx|level|rarity|d_char|name|pwr|scaled|melee|spell|hp\n");

                //for (i = 0; i < z_info.r_max; i++) {
                //    r_ptr = &r_info[i];

                //    /* Don't print anything for nonexistent monsters */
                //    if (!r_ptr.name) continue;

                //    file_putf(mon_fp, "%d|%d|%d|%c|%s|%d|%d|%d|%d|%d\n", r_ptr.ridx,
                //        r_ptr.level, r_ptr.rarity, r_ptr.d_char, r_ptr.name,
                //        r_ptr.power, r_ptr.scaled_power, r_ptr.melee_dam,
                //        r_ptr.spell_dam, r_ptr.hp);
                //}

                //file_close(mon_fp);
            }

            /* Free power array */
            //FREE(power);

            /* Success */
            return(0);
        }
Example #12
0
        static long max_dam(Monster_Race r_ptr)
        {
            int rlev, i;
            int melee_dam = 0, atk_dam = 0, spell_dam = 0;
            int dam = 1;

            /* Extract the monster level, force 1 for town monsters */
            rlev = ((r_ptr.level >= 1) ? r_ptr.level : 1);

            /* Assume single resist for the elemental attacks */
            spell_dam = Monster_Spell_Flag.best_spell_power(r_ptr, 1);

            /* Hack - Apply over 10 rounds */
            spell_dam *= 10;

            /* Scale for frequency and availability of mana / ammo */
            if(spell_dam != 0) {
                int freq = r_ptr.freq_spell;

                /* Hack -- always get 1 shot */
                if(freq < 10)
                    freq = 10;

                /* Adjust for frequency */
                spell_dam = spell_dam * freq / 100;
            }

            /* Check attacks */
            for(i = 0; i < 4; i++) {
                if (r_ptr.blow[i] == null) continue;
                /* Extract the attack infomation */
                Monster_Blow.RBE effect = r_ptr.blow[i].effect;
                Monster_Blow.RBM method = r_ptr.blow[i].method;
                int d_dice = r_ptr.blow[i].d_dice;
                int d_side = r_ptr.blow[i].d_side;

                /* Hack -- no more attacks */
                if(method == null)
                    continue;

                /* Assume maximum damage*/
                atk_dam = (int)blow_effect(effect, d_dice * d_side, r_ptr.level);

                /*stun definitely most dangerous*/
                if(method == Monster_Blow.RBM.PUNCH || method == Monster_Blow.RBM.KICK ||
                   method == Monster_Blow.RBM.BUTT || method == Monster_Blow.RBM.CRUSH) {
                    atk_dam *= 4;
                    atk_dam /= 3;
                } else if(method == Monster_Blow.RBM.CLAW || method == Monster_Blow.RBM.BITE) {
                    atk_dam *= 7;
                    atk_dam /= 5;
                }

                /* Normal melee attack */
                if(!r_ptr.flags.has(Monster_Flag.NEVER_BLOW.value)) {
                    /* Keep a running total */
                    melee_dam += atk_dam;
                }
            }

            /*
             * Apply damage over 10 rounds. We assume that the monster has to make contact first.
             * Hack - speed has more impact on melee as has to stay in contact with player.
             * Hack - this is except for pass wall and kill wall monsters which can always get to the player.
             * Hack - use different values for huge monsters as they strike out to range 2.
             */
            if(r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.KILL_WALL.value, Monster_Flag.PASS_WALL.value))
                melee_dam *= 10;
            else {
                melee_dam = melee_dam * 3 + melee_dam * Misc.extract_energy[r_ptr.speed + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] / 7;
            }

            /*
             * Scale based on attack accuracy. We make a massive number of assumptions here and just use monster level.
             */
            melee_dam = melee_dam * Math.Min(45 + rlev * 3, 95) / 100;

            /* Hack -- Monsters that multiply ignore the following reductions */
            if(!r_ptr.flags.has(Monster_Flag.MULTIPLY.value)) {
                /*Reduce damamge potential for monsters that move randomly */
                if(r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.RAND_25.value, Monster_Flag.RAND_50.value)) {
                    int reduce = 100;

                    if(r_ptr.flags.has(Monster_Flag.RAND_25.value))
                        reduce -= 25;
                    if(r_ptr.flags.has(Monster_Flag.RAND_50.value))
                        reduce -= 50;

                    /*even moving randomly one in 8 times will hit the player*/
                    reduce += (100 - reduce) / 8;

                    /* adjust the melee damage*/
                    melee_dam = (melee_dam * reduce) / 100;
                }

                /*monsters who can't move aren't nearly as much of a combat threat*/
                if(r_ptr.flags.has(Monster_Flag.NEVER_MOVE.value)) {
                    if(r_ptr.spell_flags.has(Monster_Spell_Flag.TELE_TO.value) ||
                        r_ptr.spell_flags.has(Monster_Spell_Flag.BLINK.value)) {
                        /* Scale for frequency */
                        melee_dam = melee_dam / 5 + 4 * melee_dam * r_ptr.freq_spell / 500;

                        /* Incorporate spell failure chance */
                        if(!r_ptr.flags.has(Monster_Flag.STUPID.value))
                            melee_dam = melee_dam / 5 + 4 * melee_dam * Math.Min(75 + (rlev + 3) / 4, 100) / 500;
                    } else if(r_ptr.flags.has(Monster_Flag.INVISIBLE.value))
                        melee_dam /= 3;
                    else
                        melee_dam /= 5;
                }
            }

            /* But keep at a minimum */
            if(melee_dam < 1)
                melee_dam = 1;

            /*
             * Combine spell and melee damage
             */
            dam = (spell_dam + melee_dam);

            r_ptr.highest_threat = (short)dam;
            r_ptr.spell_dam = spell_dam;	/*AMF:DEBUG*/
            r_ptr.melee_dam = melee_dam;	/*AMF:DEBUG*/

            /*
             * Adjust for speed.  Monster at speed 120 will do double damage,
             * monster at speed 100 will do half, etc.  Bonus for monsters who can haste self.
             */
            dam = (dam * Misc.extract_energy[r_ptr.speed + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)]) / 10;

            /*
             * Adjust threat for speed -- multipliers are more threatening.
             */
            if(r_ptr.flags.has(Monster_Flag.MULTIPLY.value))
                r_ptr.highest_threat = (short)((r_ptr.highest_threat * Misc.extract_energy[r_ptr.speed + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)]) / 5);

            /*
             * Adjust threat for friends.
             */
            if(r_ptr.flags.has(Monster_Flag.FRIENDS.value))
                r_ptr.highest_threat *= 2;
            else if(r_ptr.flags.has(Monster_Flag.FRIEND.value))
                r_ptr.highest_threat = (short)(r_ptr.highest_threat * 3 / 2);

            /*but deep in a minimum*/
            if(dam < 1)
                dam = 1;

            /* We're done */
            return (dam);
        }
Example #13
0
        static long hp_adjust(Monster_Race r_ptr)
        {
            long hp;
            int resists = 1;
            int hide_bonus = 0;

            /* Get the monster base hitpoints */
            hp = r_ptr.avg_hp;

            /* Never moves with no ranged attacks - high hit points count for less */
            if (r_ptr.flags.has(Monster_Flag.NEVER_MOVE.value) && !(r_ptr.freq_innate != 0 || r_ptr.freq_spell != 0))
            {
                hp /= 2;
                if (hp < 1) hp = 1;
            }

            /* Just assume healers have more staying power */
            if (r_ptr.spell_flags.has(Monster_Spell_Flag.HEAL.value)) hp = (hp * 6) / 5;

            /* Miscellaneous improvements */
            if (r_ptr.flags.has(Monster_Flag.REGENERATE.value)) {hp *= 10; hp /= 9;}
            if (r_ptr.flags.has(Monster_Flag.PASS_WALL.value)) {hp *= 3; hp /= 2;}

            /* Calculate hide bonus */
            if (r_ptr.flags.has(Monster_Flag.EMPTY_MIND.value)) hide_bonus += 2;
            else
            {
                if (r_ptr.flags.has(Monster_Flag.COLD_BLOOD.value)) hide_bonus += 1;
                if (r_ptr.flags.has(Monster_Flag.WEIRD_MIND.value)) hide_bonus += 1;
            }

            /* Invisibility */
            if (r_ptr.flags.has(Monster_Flag.INVISIBLE.value))
            {
                hp = (hp * (r_ptr.level + hide_bonus + 1)) / Math.Max(1, (int)r_ptr.level);
            }

            /* Monsters that can teleport are a hassle, and can easily run away */
            if (r_ptr.spell_flags.test(Monster_Spell_Flag.SIZE, Monster_Spell_Flag.TPORT.value, Monster_Spell_Flag.TELE_AWAY.value,
                Monster_Spell_Flag.TELE_LEVEL.value))
                hp = (hp * 6) / 5;

            /*
             * Monsters that multiply are tougher to kill
             */
            if (r_ptr.flags.has(Monster_Flag.MULTIPLY.value)) hp *= 2;

            /* Monsters with resistances are harder to kill.
               Therefore effective slays / brands against them are worth more. */
            if (r_ptr.flags.has(Monster_Flag.IM_ACID.value)) resists += 2;
            if (r_ptr.flags.has(Monster_Flag.IM_FIRE.value)) resists += 2;
            if (r_ptr.flags.has(Monster_Flag.IM_COLD.value)) resists += 2;
            if (r_ptr.flags.has(Monster_Flag.IM_ELEC.value)) resists += 2;
            if (r_ptr.flags.has(Monster_Flag.IM_POIS.value)) resists += 2;

            /* Bonus for multiple basic resists and weapon resists */
            if (resists >= 12) resists *= 6;
            else if (resists >= 10) resists *= 4;
            else if (resists >= 8) resists *= 3;
            else if (resists >= 6) resists *= 2;

            /* If quite resistant, reduce resists by defense holes */
            if (resists >= 6)
            {
                if (r_ptr.flags.has(Monster_Flag.HURT_ROCK.value)) resists -= 1;
                if (r_ptr.flags.has(Monster_Flag.HURT_LIGHT.value)) resists -= 1;
                if (!r_ptr.flags.has(Monster_Flag.NO_SLEEP.value)) resists -= 3;
                if (!r_ptr.flags.has(Monster_Flag.NO_FEAR.value)) resists -= 2;
                if (!r_ptr.flags.has(Monster_Flag.NO_CONF.value)) resists -= 2;
                if (!r_ptr.flags.has(Monster_Flag.NO_STUN.value)) resists -= 1;

                if (resists < 5) resists = 5;
            }

            /* If quite resistant, bonus for high resists */
            if (resists >= 3)
            {
                if (r_ptr.flags.has(Monster_Flag.IM_WATER.value)) resists += 1;
                if (r_ptr.flags.has(Monster_Flag.RES_NETH.value)) resists += 1;
                if (r_ptr.flags.has(Monster_Flag.RES_NEXUS.value)) resists += 1;
                if (r_ptr.flags.has(Monster_Flag.RES_DISE.value)) resists += 1;
            }

            /* Scale resists */
            resists = resists * 25;

            /* Monster resistances */
            if (resists < (r_ptr.ac + resists) / 3)
            {
                hp += (hp * resists) / (150 + r_ptr.level);
            }
            else
            {
                hp += (hp * (r_ptr.ac + resists) / 3) / (150 + r_ptr.level);
            }

            /*boundry control*/
            if (hp < 1) hp = 1;

            return (hp);
        }
Example #14
0
        public static int r_power(Monster_Race[] races)
        {
            //God damn it C...
            /*
            ang_file *mon_fp;
            char buf[1024];*/
            bool dump = false;

            /* Allocate space for power */
            long[] power = new long[Misc.z_info.r_max];
            long[] tot_hp = new long[Misc.MAX_DEPTH];
            long[] tot_dam = new long[Misc.MAX_DEPTH];
            long[] mon_count = new long[Misc.MAX_DEPTH];

            for(int iteration = 0; iteration < 3; iteration++) {

                /* Reset the sum of all monster power values */
                tot_mon_power = 0;

                /* Make sure all arrays start at zero */
                for(int i = 0; i < Misc.MAX_DEPTH; i++) {
                    tot_hp[i] = 0;
                    tot_dam[i] = 0;
                    mon_count[i] = 0;
                }

                /* Go through r_info and evaluate power ratings & flows. */
                for(int i = 0; i < Misc.z_info.r_max; i++) {

                    /* Point at the "info" */
                    Monster_Race r_ptr = races[i];
                    if(r_ptr == null)
                        continue;

                    /* Set the current level */
                    byte lvl = r_ptr.level;

                    /* Maximum damage this monster can do in 10 game turns */
                    long dam = max_dam(r_ptr);

                    /* Adjust hit points based on resistances */
                    long hp = hp_adjust(r_ptr);

                    /* Hack -- set exp */
                    if(lvl == 0)
                        r_ptr.mexp = 0;
                    else {
                        /* Compute depths of non-unique monsters */
                        if(r_ptr.flags.has(Monster_Flag.UNIQUE.value)) {
                            long mexp = (hp * dam) / 25;
                            long threat = r_ptr.highest_threat;

                            /* Compute level algorithmically */
                            int j;
                            for(j = 1; (mexp > j + 4) || (threat > j + 5);
                                mexp -= j * j, threat -= (j + 4), j++)
                                ;

                            /* Set level */
                            lvl = (byte)Math.Min((j > 250 ? 90 + (j - 250) / 20 : /* Level 90+ */
                                    (j > 130 ? 70 + (j - 130) / 6 :	/* Level 70+ */
                                    (j > 40 ? 40 + (j - 40) / 3 :	/* Level 40+ */
                                    j))), 99);

                            /* Set level */
                            if(Misc.arg_rebalance)
                                r_ptr.level = lvl;
                        }

                        if(Misc.arg_rebalance) {
                            /* Hack -- for Ungoliant */
                            if(hp > 10000)
                                r_ptr.mexp = (int)((hp / 25) * (dam / lvl));
                            else
                                r_ptr.mexp = (int)((hp * dam) / (lvl * 25));

                            /* Round to 2 significant figures */
                            if(r_ptr.mexp > 100) {
                                if(r_ptr.mexp < 1000) {
                                    r_ptr.mexp = (r_ptr.mexp + 5) / 10;
                                    r_ptr.mexp *= 10;
                                } else if(r_ptr.mexp < 10000) {
                                    r_ptr.mexp = (r_ptr.mexp + 50) / 100;
                                    r_ptr.mexp *= 100;
                                } else if(r_ptr.mexp < 100000) {
                                    r_ptr.mexp = (r_ptr.mexp + 500) / 1000;
                                    r_ptr.mexp *= 1000;
                                } else if(r_ptr.mexp < 1000000) {
                                    r_ptr.mexp = (r_ptr.mexp + 5000) / 10000;
                                    r_ptr.mexp *= 10000;
                                } else if(r_ptr.mexp < 10000000) {
                                    r_ptr.mexp = (r_ptr.mexp + 50000) / 100000;
                                    r_ptr.mexp *= 100000;
                                }
                            }
                        }
                    }

                    /* If we're rebalancing, this is a nop, if not, we restore the orig value */
                    lvl = r_ptr.level;
                    if((lvl != 0) && (r_ptr.mexp < 1L))
                        r_ptr.mexp = 1;

                    /*
                     * Hack - We have to use an adjustment factor to prevent overflow.
                     * Try to scale evenly across all levels instead of scaling by level.
                     */
                    hp /= 2;
                    if(hp < 1)
                        hp = 1;
                    r_ptr.hp = hp;		/*AMF:DEBUG*/

                    /* Define the power rating */
                    power[i] = hp * dam;

                    /* Adjust for group monsters.  Average in-level group size is 5 */
                    if(!r_ptr.flags.has(Monster_Flag.UNIQUE.value)) {
                        if(r_ptr.flags.has(Monster_Flag.FRIEND.value))
                            power[i] *= 2;
                        else if(r_ptr.flags.has(Monster_Flag.FRIENDS.value))
                            power[i] *= 5;
                    }

                    /* Adjust for escorts */
                    if(r_ptr.flags.has(Monster_Flag.ESCORTS.value))
                        power[i] *= 3;
                    if(r_ptr.flags.has(Monster_Flag.ESCORT.value) && !r_ptr.flags.has(Monster_Flag.ESCORTS.value))
                        power[i] *= 2;

                    /* Adjust for multiplying monsters. This is modified by the speed,
                     * as fast multipliers are much worse than slow ones. We also adjust for
                     * ability to bypass walls or doors.
                     */
                    if(r_ptr.flags.has(Monster_Flag.MULTIPLY.value)) {
                        if(r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.KILL_WALL.value, Monster_Flag.PASS_WALL.value))
                            power[i] = Math.Max(power[i], power[i] * Misc.extract_energy[r_ptr.speed
                                        + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)]);
                        else if(r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.OPEN_DOOR.value, Monster_Flag.BASH_DOOR.value))
                            power[i] = Math.Max(power[i], power[i] * Misc.extract_energy[r_ptr.speed
                                        + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] * 3 / 2);
                        else
                            power[i] = Math.Max(power[i], power[i] * Misc.extract_energy[r_ptr.speed
                                        + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] / 2);
                    }

                    /*
                     * Update the running totals - these will be used as divisors later
                     * Total HP / dam / count for everything up to the current level
                     */
                    for(int j = lvl; j < (lvl == 0 ? lvl + 1 : Misc.MAX_DEPTH); j++) {
                        int count = 10;

                        /* Uniques don't count towards monster power on the level. */
                        if(r_ptr.flags.has(Monster_Flag.UNIQUE.value))
                            continue;

                        /* Specifically placed monsters don't count towards monster power
                         * on the level. */
                        if(!(r_ptr.rarity != 0))
                            continue;

                        /* Hack -- provide adjustment factor to prevent overflow */
                        if((j == 90) && (r_ptr.level < 90)) {
                            hp /= 10;
                            dam /= 10;
                        }

                        if((j == 65) && (r_ptr.level < 65)) {
                            hp /= 10;
                            dam /= 10;
                        }

                        if((j == 40) && (r_ptr.level < 40)) {
                            hp /= 10;
                            dam /= 10;
                        }

                        /*
                         * Hack - if it's a group monster or multiplying monster, add several to the count
                         * so that the averages don't get thrown off
                         */

                        if(r_ptr.flags.has(Monster_Flag.FRIEND.value))
                            count = 20;
                        else if(r_ptr.flags.has(Monster_Flag.FRIENDS.value))
                            count = 50;

                        if(r_ptr.flags.has(Monster_Flag.MULTIPLY.value)) {
                            if(r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.KILL_WALL.value, Monster_Flag.PASS_WALL.value))
                                count = Math.Max(1, (int)Misc.extract_energy[r_ptr.speed
                                    + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)]) * count;
                            else if(r_ptr.flags.test(Monster_Flag.SIZE, Monster_Flag.OPEN_DOOR.value, Monster_Flag.BASH_DOOR.value))
                                count = Math.Max(1, Misc.extract_energy[r_ptr.speed
                                    + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] * 3 / 2) * count;
                            else
                                count = Math.Max(1, Misc.extract_energy[r_ptr.speed
                                    + (r_ptr.spell_flags.has(Monster_Spell_Flag.HASTE.value) ? 5 : 0)] / 2) * count;
                        }

                        /* Very rare monsters count less towards total monster power on the
                         * level. */
                        if(r_ptr.rarity > count) {
                            hp = hp * count / r_ptr.rarity;
                            dam = dam * count / r_ptr.rarity;

                            count = r_ptr.rarity;
                        }

                        tot_hp[j] += hp;
                        tot_dam[j] += dam;

                        mon_count[j] += count / r_ptr.rarity;
                    }

                }

                /* Apply divisors now */
                for(int i = 0; i < Misc.z_info.r_max; i++) {
                    int new_power;

                    /* Point at the "info" */
                    Monster_Race r_ptr = races[i];
                    if(r_ptr == null)
                        continue;

                    /* Extract level */
                    byte lvl = r_ptr.level;

                    /* Paranoia */
                    if(tot_hp[lvl] != 0 && tot_dam[lvl] != 0) {

                        /* Divide by average HP and av damage for all in-level monsters */
                        /* Note we have factored in the above 'adjustment factor' */
                        long av_hp = tot_hp[lvl] * 10 / mon_count[lvl];
                        long av_dam = tot_dam[lvl] * 10 / mon_count[lvl];

                        /* Assign monster power */
                        r_ptr.power = power[i];

                        /* Justifiable paranoia - avoid divide by zero errors */
                        if(av_hp > 0)
                            power[i] = power[i] / av_hp;
                        if(av_dam > 0)
                            power[i] = power[i] / av_dam;

                        /* Assign monster scaled power */
                        r_ptr.scaled_power = power[i];

                        /* Never less than 1 */
                        if(r_ptr.power < 1)
                            r_ptr.power = 1;

                        /* Get power */
                        new_power = (int)r_ptr.power;

                        /* Compute rarity algorithmically */
                        int j;
                        for(j = 1; new_power > j; new_power -= j * j, j++)
                            ;

                        /* Set rarity */
                        if(Misc.arg_rebalance)
                            r_ptr.rarity = (byte)j;
                    }
                }

            }
            /* Determine total monster power */
            for(int i = 0; i < Misc.z_info.r_max; i++) {
                Monster_Race r = Misc.r_info[i];
                if(r == null)
                    continue;

                tot_mon_power += (int)r.scaled_power;
            }

            /*	msg("Tot mon power is %d", tot_mon_power); */

            if(dump) {
                /* dump the power details */
                throw new NotImplementedException();
                //path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "mon_power.txt");
                //mon_fp = file_open(buf, MODE_WRITE, FTYPE_TEXT);

                //file_putf(mon_fp, "ridx|level|rarity|d_char|name|pwr|scaled|melee|spell|hp\n");

                //for (i = 0; i < z_info.r_max; i++) {
                //    r_ptr = &r_info[i];

                //    /* Don't print anything for nonexistent monsters */
                //    if (!r_ptr.name) continue;

                //    file_putf(mon_fp, "%d|%d|%d|%c|%s|%d|%d|%d|%d|%d\n", r_ptr.ridx,
                //        r_ptr.level, r_ptr.rarity, r_ptr.d_char, r_ptr.name,
                //        r_ptr.power, r_ptr.scaled_power, r_ptr.melee_dam,
                //        r_ptr.spell_dam, r_ptr.hp);
                //}

                //file_close(mon_fp);
            }

            /* Free power array */
            //FREE(power);

            /* Success */
            return 0;
        }
Example #15
0
        public static void wr_monster_memory()
        {
            int i;
            int r_idx;

            wr_u16b(Misc.z_info.r_max);
            for (r_idx = 0; r_idx < Misc.z_info.r_max; r_idx++) {
                Monster_Race r_ptr = Misc.r_info[r_idx];
                Monster_Lore l_ptr = Misc.l_list[r_idx];

                if (r_ptr == null) {
                    r_ptr = new Monster_Race();
                }

                if (l_ptr == null) {
                    l_ptr = new Monster_Lore();
                }

                /* Count sights/deaths/kills */
                wr_s16b(l_ptr.sights);
                wr_s16b(l_ptr.deaths);
                wr_s16b(l_ptr.pkills);
                wr_s16b(l_ptr.tkills);

                /* Count wakes and ignores */
                wr_byte(l_ptr.wake);
                wr_byte(l_ptr.ignore);

                /* Count drops */
                wr_byte(l_ptr.drop_gold);
                wr_byte(l_ptr.drop_item);

                /* Count spells */
                wr_byte(l_ptr.cast_innate);
                wr_byte(l_ptr.cast_spell);

                /* Count blows of each type */
                for (i = 0; i < Monster_Blow.MONSTER_BLOW_MAX; i++)
                    wr_byte(l_ptr.blows[i]);

                /* Memorize flags */
                for (i = 0; i < Monster_Flag.BYTES && i < Monster_Flag.SIZE; i++)
                    wr_byte(l_ptr.flags.data[i]);
                if (i < Monster_Flag.BYTES) Savefile.pad_bytes(Monster_Flag.BYTES - i);

                for (i = 0; i < Monster_Flag.BYTES && i < Monster_Spell_Flag.SIZE; i++)
                    wr_byte(l_ptr.spell_flags[i]);
                if (i < Monster_Flag.BYTES) Savefile.pad_bytes(Monster_Flag.BYTES - i);

                /* Monster limit per level */
                wr_byte(r_ptr.max_num);

                /* XXX */
                wr_byte(0);
                wr_byte(0);
                wr_byte(0);
            }
        }
Example #16
0
        /*
         * Returns a pointer to a statically allocatted string containing a formatted
         * message based on the given message code and the quantity flag.
         * The contents of the returned value will change with the next call
         * to this function
         */
        static string get_mon_msg_action(MON_MSG msg_code, bool do_plural, Monster_Race race)
        {
            //static char buf[200];
            string buf = "";
            string action = msg_repository[(int)msg_code];
            short n = 0;

            /* Regular text */
            byte flag = 0;

            Misc.assert(race.Base != null && race.Base.pain != null);

            if(race.Base != null && race.Base.pain != null) {
                switch(msg_code) {
                    case MON_MSG.MON_MSG_95:
                        action = race.Base.pain.Messages[0];
                        break;
                    case MON_MSG.MON_MSG_75:
                        action = race.Base.pain.Messages[1];
                        break;
                    case MON_MSG.MON_MSG_50:
                        action = race.Base.pain.Messages[2];
                        break;
                    case MON_MSG.MON_MSG_35:
                        action = race.Base.pain.Messages[3];
                        break;
                    case MON_MSG.MON_MSG_20:
                        action = race.Base.pain.Messages[4];
                        break;
                    case MON_MSG.MON_MSG_10:
                        action = race.Base.pain.Messages[5];
                        break;
                    case MON_MSG.MON_MSG_0:
                        action = race.Base.pain.Messages[6];
                        break;
                }
            }

            /* Put the message characters in the buffer */
            for(; action.Length > 0; action = action.Substring(1)) {
                /* Check available space */
                if(n >= (buf.Length))
                    break;

                /* Are we parsing a quantity modifier? */
                if(flag != 0) {
                    /* Check the presence of the modifier's terminator */
                    if(action[0] == ']') {
                        /* Go back to parsing regular text */
                        flag = 0;

                        /* Skip the mark */
                        continue;
                    }

                    /* Check if we have to parse the plural modifier */
                    if(action[0] == '|') {
                        /* Switch to plural modifier */
                        flag = PLURAL_MON;

                        /* Skip the mark */
                        continue;
                    }

                    /* Ignore the character if we need the other part */
                    if((flag == PLURAL_MON) != do_plural)
                        continue;
                }

                /* Do we need to parse a new quantity modifier? */
                else if(action[0] == '[') {
                    /* Switch to singular modifier */
                    flag = SINGULAR_MON;

                    /* Skip the mark */
                    continue;
                }

                /* Append the character to the buffer */
                buf += action[0];
                n++;
            }

            /* Terminate the buffer */
            //buf[n] = '\0';

            /* Done */
            return (buf);
        }
Example #17
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);
        }
Example #18
0
        /*
         * Returns a pointer to a statically allocatted string containing a formatted
         * message based on the given message code and the quantity flag.
         * The contents of the returned value will change with the next call
         * to this function
         */
        static string get_mon_msg_action(MON_MSG msg_code, bool do_plural, Monster_Race race)
        {
            //static char buf[200];
            string buf    = "";
            string action = msg_repository[(int)msg_code];
            short  n      = 0;

            /* Regular text */
            byte flag = 0;

            Misc.assert(race.Base != null && race.Base.pain != null);

            if (race.Base != null && race.Base.pain != null)
            {
                switch (msg_code)
                {
                case MON_MSG.MON_MSG_95:
                    action = race.Base.pain.Messages[0];
                    break;

                case MON_MSG.MON_MSG_75:
                    action = race.Base.pain.Messages[1];
                    break;

                case MON_MSG.MON_MSG_50:
                    action = race.Base.pain.Messages[2];
                    break;

                case MON_MSG.MON_MSG_35:
                    action = race.Base.pain.Messages[3];
                    break;

                case MON_MSG.MON_MSG_20:
                    action = race.Base.pain.Messages[4];
                    break;

                case MON_MSG.MON_MSG_10:
                    action = race.Base.pain.Messages[5];
                    break;

                case MON_MSG.MON_MSG_0:
                    action = race.Base.pain.Messages[6];
                    break;
                }
            }

            /* Put the message characters in the buffer */
            for (; action.Length > 0; action = action.Substring(1))
            {
                /* Check available space */
                if (n >= (buf.Length))
                {
                    break;
                }

                /* Are we parsing a quantity modifier? */
                if (flag != 0)
                {
                    /* Check the presence of the modifier's terminator */
                    if (action[0] == ']')
                    {
                        /* Go back to parsing regular text */
                        flag = 0;

                        /* Skip the mark */
                        continue;
                    }

                    /* Check if we have to parse the plural modifier */
                    if (action[0] == '|')
                    {
                        /* Switch to plural modifier */
                        flag = PLURAL_MON;

                        /* Skip the mark */
                        continue;
                    }

                    /* Ignore the character if we need the other part */
                    if ((flag == PLURAL_MON) != do_plural)
                    {
                        continue;
                    }
                }

                /* Do we need to parse a new quantity modifier? */
                else if (action[0] == '[')
                {
                    /* Switch to singular modifier */
                    flag = SINGULAR_MON;

                    /* Skip the mark */
                    continue;
                }

                /* Append the character to the buffer */
                buf += action[0];
                n++;
            }

            /* Terminate the buffer */
            //buf[n] = '\0';

            /* Done */
            return(buf);
        }