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)); }