mtype &MonsterGenerator::get_mtype( const mtype_id& id )
{
    // first do the look-up as it is most likely to succeed
    const auto iter = mon_templates.find( id );
    if( iter != mon_templates.end() ) {
        return *iter->second;
    }

    // second most likely are outdated ids from old saves, this compares against strings, not
    // mtype_ids because the old ids are not valid ids at all.
    if( id.str() == "mon_zombie_fast" ) {
        return get_mtype( mon_zombie_dog );
    }
    if( id.str() == "mon_fungaloid_dormant" ) {
        return get_mtype( mon_fungaloid );
    }

    // this is most unlikely and therefor checked last.
    debugmsg( "Could not find monster with type %s", id.c_str() );
    return *mon_templates[mtype_id::NULL_ID];
}
void activity_handlers::pulp_do_turn( player_activity *act, player *p )
{
    const tripoint &pos = act->placement;
    static const int full_pulp_threshold = 4;
    const int move_cost = int(p->weapon.is_null() ? 80 : p->weapon.attack_time() * 0.8);

    // numbers logic: a str 8 character with a butcher knife (4 bash, 18 cut)
    // should have at least a 50% chance of damaging an intact zombie corpse (75 volume).
    // a str 8 character with a baseball bat (28 bash, 0 cut) should have around a 25% chance.

    int cut_power = p->weapon.type->melee_cut;
    // stabbing weapons are a lot less effective at pulping
    if( p->weapon.has_flag("STAB") || p->weapon.has_flag("SPEAR") ) {
        cut_power /= 2;
    }
    double pulp_power = sqrt((double)(p->str_cur + p->weapon.type->melee_dam)) *
        std::min(1.0, sqrt((double)(cut_power + 1)));
    pulp_power = std::min(pulp_power, (double)p->str_cur);
    pulp_power *= 20; // constant multiplier to get the chance right
    int moves = 0;
    int &num_corpses = act->index; // use this to collect how many corpse are pulped
    auto corpse_pile = g->m.i_at(pos);
    for( auto corpse = corpse_pile.begin(); corpse != corpse_pile.end(); ++corpse ) {
        if( !(corpse->is_corpse() && corpse->damage < full_pulp_threshold) ) {
            continue; // no corpse or already pulped
        }
        int damage = pulp_power / corpse->volume();
        //Determine corpse's blood type.
        field_id type_blood = corpse->get_mtype()->bloodType();
        do {
            moves += move_cost;
            const int mod_sta = ( (p->weapon.weight() / 100 ) + 20) * -1;
            p->mod_stat("stamina", mod_sta);
            // Increase damage as we keep smashing,
            // to insure that we eventually smash the target.
            if( x_in_y(pulp_power, corpse->volume())  ) {
                corpse->damage++;
                p->handle_melee_wear();
            }
            // Splatter some blood around
            tripoint tmp = pos;
            if( type_blood != fd_null ) {
                for( tmp.x = pos.x - 1; tmp.x <= pos.x + 1; tmp.x++ ) {
                    for( tmp.y = pos.y - 1; tmp.y <= pos.y + 1; tmp.y++ ) {
                        if( !one_in(damage + 1) && type_blood != fd_null ) {
                            g->m.add_field( tmp, type_blood, 1, 0 );
                        }
                    }
                }
            }
            if( corpse->damage >= full_pulp_threshold ) {
                corpse->damage = full_pulp_threshold;
                corpse->active = false;
                num_corpses++;
            }
            if( moves >= p->moves ) {
                // enough for this turn;
                p->moves -= moves;
                return;
            }
        } while( corpse->damage < full_pulp_threshold );
    }
    // If we reach this, all corpses have been pulped, finish the activity
    act->moves_left = 0;
    // TODO: Factor in how long it took to do the smashing.
    add_msg(ngettext("The corpse is thoroughly pulped.",
                     "The corpses are thoroughly pulped.", num_corpses));
}