Example #1
0
        /*
         * Calculate the blows a player would get.
         *
         * \param o_ptr is the object for which we are calculating blows
         * \param state is the player state for which we are calculating blows
         * \param extra_blows is the number of +blows available from this object and
         * this state
         *
         * N.B. state.num_blows is now 100x the number of blows.
         */
        public int calc_blows(Object.Object obj, Player_State state, int extra_blows)
        {
            int blows;
            int str_index, dex_index;
            int div;
            int blow_energy;

            if(obj == null)
                return 0;

            /* Enforce a minimum "weight" (tenth pounds) */
            div = ((obj.weight < Class.min_weight) ? (int)Class.min_weight :
                obj.weight);

            /* Get the strength vs weight */
            str_index = adj_str_blow[state.stat_ind[(int)Stat.Str]] *
                    Class.att_multiply / div;

            /* Maximal value */
            if (str_index > 11) str_index = 11;

            /* Index by dexterity */
            dex_index = Math.Min((int)adj_dex_blow[state.stat_ind[(int)Stat.Dex]], 11);

            /* Use the blows table to get energy per blow */
            blow_energy = blows_table[str_index, dex_index];

            blows = Math.Min((10000 / blow_energy), (100 * Class.max_attacks));

            /* Require at least one blow */
            return Math.Max(blows + (100 * extra_blows), 100);
        }
Example #2
0
        public Player_State(Player_State state)
        {
            speed = state.speed;

            num_blows = state.num_blows;
            num_shots = state.num_shots;

            ammo_mult = state.ammo_mult;
            ammo_tval = state.ammo_tval;

            state.stat_add.CopyTo(stat_add, 0);
            state.stat_ind.CopyTo(stat_ind, 0);
            state.stat_use.CopyTo(stat_use, 0);
            state.stat_top.CopyTo(stat_top, 0);

            dis_ac = state.dis_ac;
            ac = state.ac;

            dis_to_a = state.dis_to_a;
            to_a = state.to_a;

            to_h = state.to_h;
            dis_to_h = state.dis_to_h;

            to_d = state.to_d;
            dis_to_d = state.dis_to_d;

            see_infra = state.see_infra;

            state.skills.CopyTo(skills, 0);

            noise = state.noise;

            heavy_wield = state.heavy_wield;	/* Heavy weapon */
            heavy_shoot = state.heavy_shoot;	/* Heavy shooter */
            icky_wield = state.icky_wield;	/* Icky weapon shooter */

            flags.copy(state.flags);
        }
Example #3
0
        public Player_State(Player_State state)
        {
            speed = state.speed;

            num_blows = state.num_blows;
            num_shots = state.num_shots;

            ammo_mult = state.ammo_mult;
            ammo_tval = state.ammo_tval;

            state.stat_add.CopyTo(stat_add, 0);
            state.stat_ind.CopyTo(stat_ind, 0);
            state.stat_use.CopyTo(stat_use, 0);
            state.stat_top.CopyTo(stat_top, 0);

            dis_ac = state.dis_ac;
            ac     = state.ac;

            dis_to_a = state.dis_to_a;
            to_a     = state.to_a;

            to_h     = state.to_h;
            dis_to_h = state.dis_to_h;

            to_d     = state.to_d;
            dis_to_d = state.dis_to_d;

            see_infra = state.see_infra;

            state.skills.CopyTo(skills, 0);

            noise = state.noise;

            heavy_wield = state.heavy_wield;            /* Heavy weapon */
            heavy_shoot = state.heavy_shoot;            /* Heavy shooter */
            icky_wield  = state.icky_wield;             /* Icky weapon shooter */

            flags.copy(state.flags);
        }
Example #4
0
        /*
         * Calculate the players current "state", taking into account
         * not only race/class intrinsics, but also objects being worn
         * and temporary spell effects.
         *
         * See also calc_mana() and calc_hitpoints().
         *
         * Take note of the new "speed code", in particular, a very strong
         * player will start slowing down as soon as he reaches 150 pounds,
         * but not until he reaches 450 pounds will he be half as fast as
         * a normal kobold.  This both hurts and helps the player, hurts
         * because in the old days a player could just avoid 300 pounds,
         * and helps because now carrying 300 pounds is not very painful.
         *
         * The "weapon" and "bow" do *not* add to the bonuses to hit or to
         * damage, since that would affect non-combat things.  These values
         * are actually added in later, at the appropriate place.
         *
         * If id_only is true, calc_bonuses() will only use the known
         * information of objects; thus it returns what the player _knows_
         * the character state to be.
         */
        void calc_bonuses(Object.Object[] inventory, ref Player_State state, bool id_only)
        {
            Player p_ptr = Player.instance;
            int i, j, hold;

            int extra_blows = 0;
            int extra_shots = 0;
            int extra_might = 0;

            Object.Object o_ptr;

            Bitflag f = new Bitflag(Object_Flag.SIZE);
            Bitflag collect_f = new Bitflag(Object_Flag.SIZE);

            /*** Reset ***/
            state = new Player_State();
            //memset(state, 0, sizeof *state);

            /* Set various defaults */
            state.speed = 110;
            state.num_blows = 100;

            /*** Extract race/class info ***/

            /* Base infravision (purely racial) */
            if(p_ptr.Race == null)
                return;
            state.see_infra = p_ptr.Race.infra;

            /* Base skills */
            for (i = 0; i < (int)Skill.MAX; i++)
                state.skills[i] = (short)(p_ptr.Race.r_skills[i] + p_ptr.Class.c_skills[i]);

            /*** Analyze player ***/

            /* Extract the player flags */
            Player.player_flags(ref collect_f);

            /*** Analyze equipment ***/

            /* Scan the equipment */
            for (i = Misc.INVEN_WIELD; i < Misc.INVEN_TOTAL; i++)
            {
                o_ptr = inventory[i];

                /* Skip non-objects */
                if (o_ptr ==  null || o_ptr.kind == null) continue;

                /* Extract the item flags */
                if (id_only)
                    o_ptr.object_flags_known(ref f);
                else
                    o_ptr.object_flags(ref f);

                collect_f.union(f);

                /* Affect stats */
                if (f.has(Object_Flag.STR.value)) state.stat_add[(int)Stat.Str] +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.STR.value)];
                if (f.has(Object_Flag.INT.value)) state.stat_add[(int)Stat.Int] +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.INT.value)];
                if (f.has(Object_Flag.WIS.value)) state.stat_add[(int)Stat.Wis] +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.WIS.value)];
                if (f.has(Object_Flag.DEX.value)) state.stat_add[(int)Stat.Dex] +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.DEX.value)];
                if (f.has(Object_Flag.CON.value)) state.stat_add[(int)Stat.Con] +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.CON.value)];
                if (f.has(Object_Flag.CHR.value)) state.stat_add[(int)Stat.Chr] +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.CHR.value)];

                /* Affect stealth */
                if (f.has(Object_Flag.STEALTH.value)) state.skills[(int)Skill.STEALTH] +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.STEALTH.value)];

                /* Affect searching ability (factor of five) */
                if (f.has(Object_Flag.SEARCH.value)) state.skills[(int)Skill.SEARCH] +=
                    (short)(o_ptr.pval[o_ptr.which_pval(Object_Flag.SEARCH.value)] * 5);

                /* Affect searching frequency (factor of five) */
                if (f.has(Object_Flag.SEARCH.value)) state.skills[(int)Skill.SEARCH_FREQUENCY] +=
                    (short)(o_ptr.pval[o_ptr.which_pval(Object_Flag.SEARCH.value)] * 5);

                /* Affect infravision */
                if (f.has(Object_Flag.INFRA.value)) state.see_infra +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.INFRA.value)];

                /* Affect digging (factor of 20) */
                if (f.has(Object_Flag.TUNNEL.value)) state.skills[(int)Skill.DIGGING] +=
                    (short)(o_ptr.pval[o_ptr.which_pval(Object_Flag.TUNNEL.value)] * 20);

                /* Affect speed */
                if (f.has(Object_Flag.SPEED.value)) state.speed +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.SPEED.value)];

                /* Affect blows */
                if (f.has(Object_Flag.BLOWS.value)) extra_blows +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.BLOWS.value)];

                /* Affect shots */
                if (f.has(Object_Flag.SHOTS.value)) extra_shots +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.SHOTS.value)];

                /* Affect Might */
                if (f.has(Object_Flag.MIGHT.value)) extra_might +=
                    o_ptr.pval[o_ptr.which_pval(Object_Flag.MIGHT.value)];

                /* Modify the base armor class */
                state.ac += o_ptr.ac;

                /* The base armor class is always known */
                state.dis_ac += o_ptr.ac;

                /* Apply the bonuses to armor class */
                if (!id_only || o_ptr.is_known())
                    state.to_a += o_ptr.to_a;

                /* Apply the mental bonuses to armor class, if known */
                if (o_ptr.defence_plusses_are_visible())
                    state.dis_to_a += o_ptr.to_a;

                /* Hack -- do not apply "weapon" bonuses */
                if (i == Misc.INVEN_WIELD) continue;

                /* Hack -- do not apply "bow" bonuses */
                if (i == Misc.INVEN_BOW) continue;

                /* Apply the bonuses to hit/damage */
                if (!id_only || o_ptr.is_known())
                {
                    state.to_h += o_ptr.to_h;
                    state.to_d += o_ptr.to_d;
                }

                /* Apply the mental bonuses tp hit/damage, if known */
                if (o_ptr.attack_plusses_are_visible())
                {
                    state.dis_to_h += o_ptr.to_h;
                    state.dis_to_d += o_ptr.to_d;
                }
            }

            /*** Update all flags ***/

            for (i = 0; i < Object_Flag.MAX.value; i++)
                if (collect_f.has(i))
                    state.flags.on(i);

            /*** Handle stats ***/

            /* Calculate stats */
            for (i = 0; i < (int)Stat.Max; i++)
            {
                int add, top, use, ind;

                /* Extract modifier */
                add = state.stat_add[i];

                /* Maximize mode */
                if (Option.birth_maximize.value)
                {
                    /* Modify the stats for race/class */
                    add += (p_ptr.Race.r_adj[i] + p_ptr.Class.c_adj[i]);
                }

                /* Extract the new "stat_top" value for the stat */
                top = Birther.modify_stat_value(p_ptr.stat_max[i], add);

                /* Save the new value */
                state.stat_top[i] = (short)top;

                /* Extract the new "stat_use" value for the stat */
                use = Birther.modify_stat_value(p_ptr.stat_cur[i], add);

                /* Save the new value */
                state.stat_use[i] = (short)use;

                /* Values: n/a */
                if (use <= 3) ind = 0;

                /* Values: 3, 4, ..., 18 */
                else if (use <= 18) ind = (use - 3);

                /* Ranges: 18/00-18/09, ..., 18/210-18/219 */
                else if (use <= 18+219) ind = (15 + (use - 18) / 10);

                /* Range: 18/220+ */
                else ind = (37);

                Misc.assert((0 <= ind) && (ind < Misc.STAT_RANGE));

                /* Save the new index */
                state.stat_ind[i] = (short)ind;
            }

            /*** Temporary flags ***/

            /* Apply temporary "stun" */
            if (p_ptr.timed[(int)Timed_Effect.STUN] > 50)
            {
                state.to_h -= 20;
                state.dis_to_h -= 20;
                state.to_d -= 20;
                state.dis_to_d -= 20;
                state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 8 / 10);
            }
            else if (p_ptr.timed[(int)Timed_Effect.STUN] != 0)
            {
                state.to_h -= 5;
                state.dis_to_h -= 5;
                state.to_d -= 5;
                state.dis_to_d -= 5;
                state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 9 / 10);
            }

            /* Invulnerability */
            if (p_ptr.timed[(int)Timed_Effect.INVULN] != 0)
            {
                state.to_a += 100;
                state.dis_to_a += 100;
            }

            /* Temporary blessing */
            if (p_ptr.timed[(int)Timed_Effect.BLESSED] != 0)
            {
                state.to_a += 5;
                state.dis_to_a += 5;
                state.to_h += 10;
                state.dis_to_h += 10;
                state.skills[(int)Skill.DEVICE] = (short) (state.skills[(int)Skill.DEVICE] * 105 / 100);
            }

            /* Temporary shield */
            if (p_ptr.timed[(int)Timed_Effect.SHIELD] != 0)
            {
                state.to_a += 50;
                state.dis_to_a += 50;
            }

            /* Temporary stoneskin */
            if (p_ptr.timed[(int)Timed_Effect.STONESKIN] != 0)
            {
                state.to_a += 40;
                state.dis_to_a += 40;
                state.speed -= 5;
            }

            /* Temporary "Hero" */
            if (p_ptr.timed[(int)Timed_Effect.HERO] != 0)
            {
                state.to_h += 12;
                state.dis_to_h += 12;
                state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 105 / 100);
            }

            /* Temporary "Berserk" */
            if (p_ptr.timed[(int)Timed_Effect.SHERO] != 0)
            {
                state.to_h += 24;
                state.dis_to_h += 24;
                state.to_a -= 10;
                state.dis_to_a -= 10;
                state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 9 / 10);
            }

            /* Temporary "fast" */
            if (p_ptr.timed[(int)Timed_Effect.FAST] != 0 || p_ptr.timed[(int)Timed_Effect.SPRINT] != 0)
                state.speed += 10;

            /* Temporary "slow" */
            if (p_ptr.timed[(int)Timed_Effect.SLOW] != 0)
                state.speed -= 10;

            /* Temporary infravision boost */
            if (p_ptr.timed[(int)Timed_Effect.SINFRA] != 0)
                state.see_infra += 5;

            /* Terror - this is necessary because TMD_AFRAID already occupies the
             * of_ptr.timed slot for Object_Flag.AFRAID */
            if (p_ptr.timed[(int)Timed_Effect.TERROR] > p_ptr.timed[(int)Timed_Effect.AFRAID])
                p_ptr.timed[(int)Timed_Effect.AFRAID] = p_ptr.timed[(int)Timed_Effect.TERROR];

            if (p_ptr.timed[(int)Timed_Effect.TERROR] != 0)
                state.speed += 5;

            /* Fear can come from item flags too */
            if (p_ptr.check_state(Object_Flag.AFRAID, p_ptr.state.flags))
            {
                state.to_h -= 20;
                state.dis_to_h -= 20;
                state.to_a += 8;
                state.dis_to_a += 8;
                state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 95 / 100);
            }

            /* Confusion */
            if (p_ptr.timed[(int)Timed_Effect.CONFUSED] != 0)
                state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 75 / 100);

            /* Amnesia */
            if (p_ptr.timed[(int)Timed_Effect.AMNESIA] != 0)
                state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 8 / 10);

            /* Poison */
            if (p_ptr.timed[(int)Timed_Effect.POISONED] != 0)
                state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 95 / 100);

            /* Hallucination */
            if (p_ptr.timed[(int)Timed_Effect.IMAGE] != 0)
                state.skills[(int)Skill.DEVICE] = (short)(state.skills[(int)Skill.DEVICE] * 8 / 10);

            /*** Analyze weight ***/

            /* Extract the current weight (in tenth pounds) */
            j = p_ptr.total_weight;

            /* Extract the "weight limit" (in tenth pounds) */
            i = state.weight_limit();

            /* Apply "encumbrance" from weight */
            if (j > i / 2) state.speed -= (short)((j - (i / 2)) / (i / 10));

            /* Bloating slows the player down (a little) */
            if (p_ptr.food >= Misc.PY_FOOD_MAX) state.speed -= 10;

            /* Searching slows the player down */
            if (p_ptr.searching != 0) state.speed -= 10;

            /* Sanity check on extreme speeds */
            if (state.speed < 0) state.speed = 0;
            if (state.speed > 199) state.speed = 199;

            /*** Apply modifier bonuses ***/

            /* Actual Modifier Bonuses (Un-inflate stat bonuses) */
            state.to_a += (short)((int)(adj_dex_ta[state.stat_ind[(int)Stat.Dex]]) - 128);
            state.to_d += (short)((int)(adj_str_td[state.stat_ind[(int)Stat.Str]]) - 128);
            state.to_h += (short)((int)(adj_dex_th[state.stat_ind[(int)Stat.Dex]]) - 128);
            state.to_h += (short)((int)(adj_str_th[state.stat_ind[(int)Stat.Str]]) - 128);

            /* Displayed Modifier Bonuses (Un-inflate stat bonuses) */
            state.dis_to_a += (short)((int)(adj_dex_ta[state.stat_ind[(int)Stat.Dex]]) - 128);
            state.dis_to_d += (short)((int)(adj_str_td[state.stat_ind[(int)Stat.Str]]) - 128);
            state.dis_to_h += (short)((int)(adj_dex_th[state.stat_ind[(int)Stat.Dex]]) - 128);
            state.dis_to_h += (short)((int)(adj_str_th[state.stat_ind[(int)Stat.Str]]) - 128);

            /*** Modify skills ***/

            /* Affect Skill -- stealth (bonus one) */
            state.skills[(int)Skill.STEALTH] += 1;

            /* Affect Skill -- disarming (DEX and INT) */
            state.skills[(int)Skill.DISARM] += adj_dex_dis[state.stat_ind[(int)Stat.Dex]];
            state.skills[(int)Skill.DISARM] += adj_int_dis[state.stat_ind[(int)Stat.Int]];

            /* Affect Skill -- magic devices (INT) */
            state.skills[(int)Skill.DEVICE] += adj_int_dev[state.stat_ind[(int)Stat.Int]];

            /* Affect Skill -- saving throw (WIS) */
            state.skills[(int)Skill.SAVE] += adj_wis_sav[state.stat_ind[(int)Stat.Wis]];

            /* Affect Skill -- digging (STR) */
            state.skills[(int)Skill.DIGGING] += adj_str_dig[state.stat_ind[(int)Stat.Str]];

            /* Affect Skills (Level, by Class) */
            for (i = 0; i < (int)Skill.MAX; i++)
                state.skills[i] += (short)(p_ptr.Class.x_skills[i] * p_ptr.lev / 10);

            /* Limit Skill -- digging from 1 up */
            if (state.skills[(int)Skill.DIGGING] < 1) state.skills[(int)Skill.DIGGING] = 1;

            /* Limit Skill -- stealth from 0 to 30 */
            if (state.skills[(int)Skill.STEALTH] > 30) state.skills[(int)Skill.STEALTH] = 30;
            if (state.skills[(int)Skill.STEALTH] < 0) state.skills[(int)Skill.STEALTH] = 0;

            /* Apply Skill -- Extract noise from stealth */
            state.noise = (uint)(1L << (30 - state.skills[(int)Skill.STEALTH]));

            /* Obtain the "hold" value */
            hold = adj_str_hold[state.stat_ind[(int)Stat.Str]];

            /*** Analyze current bow ***/

            /* Examine the "current bow" */
            o_ptr = inventory[Misc.INVEN_BOW];

            /* Assume not heavy */
            state.heavy_shoot = false;

            /* It is hard to hold a heavy bow */
            if (hold < o_ptr.weight / 10)
            {
                /* Hard to wield a heavy bow */
                state.to_h += (short)(2 * (hold - o_ptr.weight / 10));
                state.dis_to_h += (short)(2 * (hold - o_ptr.weight / 10));

                /* Heavy Bow */
                state.heavy_shoot = true;
            }

            /* Analyze launcher */
            if (o_ptr.kind != null)
            {
                /* Get to shoot */
                state.num_shots = 1;

                /* Analyze the launcher */
                switch (o_ptr.sval)
                {
                    /* Sling and ammo */
                    case SVal.SV_SLING:
                    {
                        state.ammo_tval = TVal.TV_SHOT;
                        state.ammo_mult = 2;
                        break;
                    }

                    /* Short Bow and Arrow */
                    case SVal.SV_SHORT_BOW:
                    {
                        state.ammo_tval = TVal.TV_ARROW;
                        state.ammo_mult = 2;
                        break;
                    }

                    /* Long Bow and Arrow */
                    case SVal.SV_LONG_BOW:
                    {
                        state.ammo_tval = TVal.TV_ARROW;
                        state.ammo_mult = 3;
                        break;
                    }

                    /* Light Crossbow and Bolt */
                    case SVal.SV_LIGHT_XBOW:
                    {
                        state.ammo_tval = TVal.TV_BOLT;
                        state.ammo_mult = 3;
                        break;
                    }

                    /* Heavy Crossbow and Bolt */
                    case SVal.SV_HEAVY_XBOW:
                    {
                        state.ammo_tval = TVal.TV_BOLT;
                        state.ammo_mult = 4;
                        break;
                    }
                }

                /* Apply special flags */
                if (o_ptr.kind != null && !state.heavy_shoot)
                {
                    /* Extra shots */
                    state.num_shots += (short)extra_shots;

                    /* Extra might */
                    state.ammo_mult += (byte)extra_might;

                    /* Hack -- Rangers love Bows */
                    if (player_has(Misc.PF.EXTRA_SHOT.value) && (state.ammo_tval == TVal.TV_ARROW))
                    {
                        /* Extra shot at level 20 */
                        if (p_ptr.lev >= 20) state.num_shots++;

                        /* Extra shot at level 40 */
                        if (p_ptr.lev >= 40) state.num_shots++;
                    }
                }

                /* Require at least one shot */
                if (state.num_shots < 1) state.num_shots = 1;
            }

            /*** Analyze weapon ***/

            /* Examine the "current weapon" */
            o_ptr = inventory[Misc.INVEN_WIELD];

            /* Assume not heavy */
            state.heavy_wield = false;

            /* It is hard to hold a heavy weapon */
            if (hold < o_ptr.weight / 10)
            {
                /* Hard to wield a heavy weapon */
                state.to_h += (short)(2 * (hold - o_ptr.weight / 10));
                state.dis_to_h += (short)(2 * (hold - o_ptr.weight / 10));

                /* Heavy weapon */
                state.heavy_wield = true;
            }

            /* Non-object means barehanded attacks */
            if (o_ptr.kind == null)
                Misc.assert(o_ptr.weight == 0);

            /* Normal weapons */
            if (!state.heavy_wield)
            {
                /* Calculate number of blows */
                state.num_blows = (short)calc_blows(o_ptr, state, extra_blows);

                /* Boost digging skill by weapon weight */
                state.skills[(int)Skill.DIGGING] += (short)(o_ptr.weight / 10);
            }

            /* Assume okay */
            state.icky_wield = false;

            /* Priest weapon penalty for non-blessed edged weapons */
            if (player_has(Misc.PF.BLESS_WEAPON.value) && !p_ptr.check_state(Object_Flag.BLESSED, p_ptr.state.flags) &&
                ((o_ptr.tval == TVal.TV_SWORD) || (o_ptr.tval == TVal.TV_POLEARM)))
            {
                /* Reduce the real bonuses */
                state.to_h -= 2;
                state.to_d -= 2;

                /* Reduce the mental bonuses */
                state.dis_to_h -= 2;
                state.dis_to_d -= 2;

                /* Icky weapon */
                state.icky_wield = true;
            }

            return;
        }
Example #5
0
        /*
         * Calculate bonuses, and print various things on changes.
         */
        void update_bonuses()
        {
            int i;

            if(state == null) {
                state = new Player_State();
            }
            Player_State old = new Player_State(state);

            /*** Calculate bonuses ***/

            calc_bonuses(inventory, ref state, false);

            /*** Notice changes ***/

            /* Analyze stats */
            for (i = 0; i < (int)Stat.Max; i++)
            {
                /* Notice changes */
                if (state.stat_top[i] != old.stat_top[i])
                {
                    /* Redisplay the stats later */
                    redraw |= (Misc.PR_STATS);
                }

                /* Notice changes */
                if (state.stat_use[i] != old.stat_use[i])
                {
                    /* Redisplay the stats later */
                    redraw |= (Misc.PR_STATS);
                }

                /* Notice changes */
                if (state.stat_ind[i] != old.stat_ind[i])
                {
                    /* Change in CON affects Hitpoints */
                    if (i == (int)Stat.Con)
                    {
                        update |= (Misc.PU_HP);
                    }

                    /* Change in INT may affect Mana/Spells */
                    else if (i == (int)Stat.Int)
                    {
                        if (Class.spell_stat == (int)Stat.Int)
                        {
                            update |= (Misc.PU_MANA | Misc.PU_SPELLS);
                        }
                    }

                    /* Change in WIS may affect Mana/Spells */
                    else if (i == (int)Stat.Wis)
                    {
                        if (Class.spell_stat == (int)Stat.Wis)
                        {
                            update |= (Misc.PU_MANA | Misc.PU_SPELLS);
                        }
                    }
                }
            }

            /* Hack -- Telepathy Change */
            if (state.flags.has(Object_Flag.TELEPATHY.value) != old.flags.has(Object_Flag.TELEPATHY.value))
            {
                /* Update monster visibility */
                update |= (Misc.PU_MONSTERS);
            }

            /* Hack -- See Invis Change */
            if (state.flags.has(Object_Flag.SEE_INVIS.value) != old.flags.has(Object_Flag.SEE_INVIS.value))
            {
                /* Update monster visibility */
                update |= (Misc.PU_MONSTERS);
            }

            /* Redraw speed (if needed) */
            if (state.speed != old.speed)
            {
                /* Redraw speed */
                redraw |= (Misc.PR_SPEED);
            }

            /* Redraw armor (if needed) */
            if ((state.dis_ac != old.dis_ac) || (state.dis_to_a != old.dis_to_a))
            {
                /* Redraw */
                redraw |= (Misc.PR_ARMOR);
            }

            /* Hack -- handle "xtra" mode */
            if (Misc.character_xtra != 0) return;

            /* Take note when "heavy bow" changes */
            if (old.heavy_shoot != state.heavy_shoot)
            {
                /* Message */
                if (state.heavy_shoot)
                    Utilities.msg("You have trouble wielding such a heavy bow.");
                else if (inventory[Misc.INVEN_BOW].kind != null)
                    Utilities.msg("You have no trouble wielding your bow.");
                else
                    Utilities.msg("You feel relieved to put down your heavy bow.");
            }

            /* Take note when "heavy weapon" changes */
            if (old.heavy_wield != state.heavy_wield)
            {
                /* Message */
                if (state.heavy_wield)
                    Utilities.msg("You have trouble wielding such a heavy weapon.");
                else if (inventory[Misc.INVEN_WIELD].kind != null)
                    Utilities.msg("You have no trouble wielding your weapon.");
                else
                    Utilities.msg("You feel relieved to put down your heavy weapon.");
            }

            /* Take note when "illegal weapon" changes */
            if (old.icky_wield != state.icky_wield)
            {
                /* Message */
                if (state.icky_wield)
                    Utilities.msg("You do not feel comfortable with your weapon.");
                else if (inventory[Misc.INVEN_WIELD].kind != null)
                    Utilities.msg("You feel comfortable with your weapon.");
                else
                    Utilities.msg("You feel more comfortable after removing your weapon.");
            }
        }