20 votes

An obvious bug in Dungeon Crawl: Stone Soup that players failed to recognize for two weeks, and what it demonstrates about "cognitive decoupling"

3 comments

  1. [3]
    teaearlgraycold
    Link
    Am I stupid? I don't see how the patch doubles damage done by the player. [PATCH] Fix a crash with cleaving + infusion vs spectral weapons. From e0bdd66d849c596fceac82094b8595117c4c4f9e Mon Sep 17...

    Am I stupid? I don't see how the patch doubles damage done by the player.

    [PATCH] Fix a crash with cleaving + infusion vs spectral weapons.
    From e0bdd66d849c596fceac82094b8595117c4c4f9e Mon Sep 17 00:00:00 2001
    From: Neil Moore <neil@s-z.org>
    Date: Fri, 6 Mar 2015 11:31:13 -0500
    Subject: [PATCH] Fix a crash with cleaving + infusion vs spectral weapons.
    
    If we cleaved from the SW's caster (killing it) into the SW, the call
    sequence melee_attack::handle_phase_hit() -> attack::calc_damage ->()
    attack::player_stab() -> alert_nearby_monsters() could would cause the
    SW to notice the dead caster and cease to exist.  But then we check the
    vanished SW's AC for infusion damage immediately afterwards, leading
    to a crash:
    http://dobrazupa.org/morgue/ihatethisgame/crash-ihatethisgame-20150302-235727.txt
    
    Instead, calculate the infusion damage first, before calling
    calc_damage.
    
    Also, for robustness, add an extra check to prevent vampires trying to
    drain already-reset monsters like these.  This check isn't currently
    necessary, because _player_vampire_draws_blood happens to think that
    reset monsters have no blood.
    ---
    crawl-ref/source/melee_attack.cc | 20 ++++++++++++++------
    1 file changed, 14 insertions(+), 6 deletions(-)
    
    diff --git a/crawl-ref/source/melee_attack.cc b/crawl-ref/source/melee_attack.cc
    index d0528b7280b..e370089659b 100644
    --- a/crawl-ref/source/melee_attack.cc
    +++ b/crawl-ref/source/melee_attack.cc
    @@ -412,6 +412,7 @@ bool melee_attack::handle_phase_hit()
            }
        }
    
    +    damage_done = 0;
        // Slimify does no damage and serves as an on-hit effect, handle it
        if (attacker->is_player() && you.duration[DUR_SLIMIFY]
            && mon_can_be_slimified(defender->as_monster())
    @@ -419,17 +420,12 @@ bool melee_attack::handle_phase_hit()
        {
            // Bail out after sliming so we don't get aux unarmed and
            // attack a fellow slime.
    -        damage_done = 0;
            slimify_monster(defender->as_monster());
            you.duration[DUR_SLIMIFY] = 0;
    
            return false;
        }
    
    -    // This does more than just calculate the damage, it also sets up
    -    // messages, etc.
    -    damage_done = calc_damage();
    -
        if (attacker->is_player() && you.duration[DUR_INFUSION])
        {
            if (enough_mp(1, true, false))
    @@ -443,12 +439,18 @@ bool melee_attack::handle_phase_hit()
    
                if (hurt > 0)
                {
    -                damage_done += hurt;
    +                damage_done = hurt;
                    dec_mp(1);
                }
            }
        }
    
    +    // This does more than just calculate the damage, it also sets up
    +    // messages, etc. It also wakes nearby creatures on a failed stab,
    +    // meaning it could have made the attacked creature vanish. That
    +    // will be checked early in player_monattack_hit_effects
    +    damage_done += calc_damage();
    +
        bool stop_hit = false;
        // Check if some hit-effect killed the monster.
        if (attacker->is_player())
    @@ -1879,6 +1881,12 @@ bool melee_attack::player_monattk_hit_effects()
    {
        player_weapon_upsets_god();
    
    +    // Don't even check vampire bloodletting if the monster has already
    +    // been reset (for example, a spectral weapon who noticed in
    +    // player_stab_check that it shouldn't exist anymore).
    +    if (defender->type == MONS_NO_MONSTER)
    +        return false;
    +
        // Thirsty vampires will try to use a stabbing situation to draw blood.
        if (you.species == SP_VAMPIRE && you.hunger_state < HS_SATIATED
            && damage_done > 0 && stab_attempt && stab_bonus > 0
    
    2 votes
    1. [2]
      Deimos
      Link Parent
      This is the fixed commit, so maybe it's a better one to look at: https://github.com/crawl/crawl/commit/90bd1c500bff56e71350d45dbea52bac3bedbd97 The comment on it says: So it sounds like re-using a...

      This is the fixed commit, so maybe it's a better one to look at: https://github.com/crawl/crawl/commit/90bd1c500bff56e71350d45dbea52bac3bedbd97

      The comment on it says:

      This correctly applies the fix in e0bdd66 by using a local variable instead of the damage_done attribute of the attack class.

      So it sounds like re-using a class/object attribute caused it to be added to twice, ending up with double damage.

      2 votes
      1. teaearlgraycold
        Link Parent
        Oh. Turns out the problem is with C++ readability. I had no idea that was a class attribute.

        Oh. Turns out the problem is with C++ readability. I had no idea that was a class attribute.

        3 votes