예제 #1
0
int player::get_acquirable_energy( const item &it, rechargeable_cbm cbm ) const
{
    switch( cbm ) {
        case rechargeable_cbm::none:
            break;

        case rechargeable_cbm::battery:
            return std::min<long>( it.charges, std::numeric_limits<int>::max() );

        case rechargeable_cbm::reactor:
            if( it.charges > 0 ) {
                const auto iter = plut_charges.find( it.typeId() );
                return iter != plut_charges.end() ? it.charges * iter->second : 0;
            }

            break;

        case rechargeable_cbm::furnace: {
            int amount = ( it.volume() / 250_ml + it.weight() / 1_gram ) / 9;

            // @todo JSONize.
            if( it.made_of( material_id( "leather" ) ) ) {
                amount /= 4;
            }
            if( it.made_of( material_id( "wood" ) ) ) {
                amount /= 2;
            }

            return amount;
        }
    }

    return 0;
}
예제 #2
0
itype_id mtype::get_meat_itype() const
{
    if( has_flag( MF_POISON ) ) {
        if( made_of( material_id( "flesh" ) ) || made_of( material_id( "hflesh" ) ) ) {
            return "meat_tainted";
        } else if( made_of( material_id( "iflesh" ) ) ) {
            //In the future, insects could drop insect flesh rather than plain ol' meat.
            return "meat_tainted";
        } else if( made_of( material_id( "veggy" ) ) ) {
            return "veggy_tainted";
        } else if( made_of( material_id( "bone" ) ) ) {
            return "bone_tainted";
        }
    } else {
        if( made_of( material_id( "flesh" ) ) || made_of( material_id( "hflesh" ) ) ) {
            if( has_flag( MF_HUMAN ) ) {
                return "human_flesh";
            } else if( has_flag( MF_AQUATIC ) ) {
                return "fish";
            } else {
                return "meat";
            }
        } else if( made_of( material_id( "iflesh" ) ) ) {
            //In the future, insects could drop insect flesh rather than plain ol' meat.
            return "meat";
        } else if( made_of( material_id( "veggy" ) ) ) {
            return "veggy";
        } else if( made_of( material_id( "bone" ) ) ) {
            return "bone";
        }
    }
    return "null";
}
예제 #3
0
void mdeath::normal(monster *z)
{
    if ((g->u.sees(*z)) && (!z->no_corpse_quiet)) {
        add_msg(m_good, _("The %s dies!"),
                z->name().c_str()); //Currently it is possible to get multiple messages that a monster died.
    }
    if ( z->type->in_species( ZOMBIE )) {
            sfx::play_variant_sound( "mon_death", "zombie_death", sfx::get_heard_volume(z->pos()));
        }
    m_size monSize = z->type->size;
    bool leaveCorpse = !z->no_corpse_quiet;

    // leave some blood if we have to
    field_id type_blood = z->bloodType();
    if (type_blood != fd_null) {
        g->m.add_field( z->pos(), type_blood, 1, 0 );
    }

    int maxHP = z->get_hp_max();
    if (!maxHP) {
        maxHP = 1;
    }

    float overflowDamage = std::max( -z->get_hp(), 0 );
    float corpseDamage = 5 * (overflowDamage / (maxHP * 2));

    if (leaveCorpse) {
        int gibAmount = int(floor(corpseDamage)) - 1;
        // allow one extra gib per 5 HP
        int gibLimit = 1 + (maxHP / 5.0);
        if (gibAmount > gibLimit) {
            gibAmount = gibLimit;
        }
        bool pulverized = (corpseDamage > 5 && overflowDamage > 150);
        if (!pulverized) {
            make_mon_corpse(z, int(floor(corpseDamage)));
        } else if (monSize >= MS_MEDIUM) {
            gibAmount += rng(1, 6);
            sfx::play_variant_sound( "mon_death", "zombie_gibbed", sfx::get_heard_volume(z->pos()));
        }
        // Limit chunking to flesh, veggy and insect creatures until other kinds are supported.
        bool leaveGibs = (z->made_of( material_id( "flesh" ) ) || z->made_of( material_id( "hflesh" ) ) || z->made_of( material_id( "veggy" ) ) ||
                          z->made_of( material_id( "iflesh" ) ));
        if (leaveGibs) {
            make_gibs( z, gibAmount );
        }
    }
}
예제 #4
0
/**
 * @brief Constructor sets the ID and unique ID for the Material.
 * @param id the user-specified optional Material ID
 * @param name the user-specified optional Material name
 */
Material::Material(int id, const char* name) {

  /* If the user did not define an optional ID, create one */
  if (id == 0)
    _id = material_id();

  /* Use the user-defined ID */
  else
    _id = id;

  _name = NULL;
  setName(name);

  _volume = 0.;
  _num_instances = 0;

  /* Initialize a dummy number groups */
  _num_groups = -1;

  _sigma_t = NULL;
  _sigma_s = NULL;
  _sigma_f = NULL;
  _nu_sigma_f = NULL;
  _chi = NULL;
  _fiss_matrix = NULL;

  _fissionable = false;

  _data_aligned = false;

  return;
}
예제 #5
0
mtype::mtype()
{
    id = mtype_id::NULL_ID();
    name = "human";
    name_plural = "humans";
    description = "";
    sym = " ";
    color = c_white;
    size = MS_MEDIUM;
    mat = { material_id( "flesh" ) };
    phase = SOLID;
    def_chance = 0;
    upgrades = false;
    half_life = -1;
    upgrade_into = mtype_id::NULL_ID();
    upgrade_group = mongroup_id::NULL_ID();
    burn_into = mtype_id::NULL_ID();
    dies.push_back( &mdeath::normal );
    sp_defense = nullptr;
    harvest = harvest_id::NULL_ID();
    luminance = 0;
    bash_skill = 0;
    flags.insert( MF_HUMAN );
    flags.insert( MF_BONES );
    flags.insert( MF_LEATHER );
}
예제 #6
0
// load a material object from incoming JSON
void material_type::load_material( JsonObject &jsobj )
{
    material_type mat;

    mat._ident = material_id( jsobj.get_string( "ident" ) );
    mat._name = _( jsobj.get_string( "name" ).c_str() );
    mat._salvage_id = jsobj.get_string( "salvage_id", "null" );
    mat._salvage_multiplier = jsobj.get_float( "salvage_multiplier", 1.0 );
    mat._bash_resist = jsobj.get_int( "bash_resist" );
    mat._cut_resist = jsobj.get_int( "cut_resist" );
    mat._bash_dmg_verb = _( jsobj.get_string( "bash_dmg_verb" ).c_str() );
    mat._cut_dmg_verb = _( jsobj.get_string( "cut_dmg_verb" ).c_str() );
    mat._acid_resist = jsobj.get_int( "acid_resist" );
    mat._elec_resist = jsobj.get_int( "elec_resist" );
    mat._fire_resist = jsobj.get_int( "fire_resist" );
    mat._chip_resist = jsobj.get_int( "chip_resist" );
    mat._density = jsobj.get_int( "density" );

    JsonArray jsarr = jsobj.get_array( "dmg_adj" );
    mat._dmg_adj[0] = _( jsarr.next_string().c_str() );
    mat._dmg_adj[1] = _( jsarr.next_string().c_str() );
    mat._dmg_adj[2] = _( jsarr.next_string().c_str() );
    mat._dmg_adj[3] = _( jsarr.next_string().c_str() );

    _all_materials[mat._ident] = mat;
    DebugLog( D_INFO, DC_ALL ) << "Loaded material: " << mat._name;
}
예제 #7
0
/**
 * @brief Constructor sets the ID and unique ID for the Material.
 * @param id the user-specified optional Material ID
 * @param name the user-specified optional Material name
 */
Material::Material(int id, const char* name) {

  /* If the user did not define an optional ID, create one */
  if (id == 0)
    _id = material_id();

  /* Use the user-defined ID */
  else
    _id = id;

  _name = NULL;
  setName(name);

  _sigma_t = NULL;
  _sigma_a = NULL;
  _sigma_s = NULL;
  _sigma_f = NULL;
  _nu_sigma_f = NULL;
  _chi = NULL;
  _dif_coef = NULL;
  _dif_hat = NULL;
  _dif_tilde = NULL;
  _buckling = NULL;

  _fissionable = false;

  _data_aligned = false;

  return;
}
예제 #8
0
field_id mtype::gibType() const
{
    if( has_flag( MF_LARVA ) || in_species( MOLLUSK ) ) {
        return fd_gibs_invertebrate;
    }
    if( made_of( material_id( "veggy" ) ) ) {
        return fd_gibs_veggy;
    }
    if( made_of( material_id( "iflesh" ) ) ) {
        return fd_gibs_insect;
    }
    if( made_of( material_id( "flesh" ) ) ) {
        return fd_gibs_flesh;
    }
    // There are other materials not listed here like steel, protoplasmic, powder, null, stone, bone
    return fd_null;
}
예제 #9
0
void sfx::do_projectile_hit( const Creature &target ) {
    const int heard_volume = sfx::get_heard_volume( target.pos() );
    const int angle = get_heard_angle( target.pos() );
    if( target.is_monster() ) {
        const monster &mon = dynamic_cast<const monster &>( target );
        static std::set<material_id> const fleshy = {
            material_id( "flesh" ),
            material_id( "hflesh" ),
            material_id( "iflesh" ),
            material_id( "veggy" ),
            material_id( "bone" ),
        };
        const bool is_fleshy = std::any_of( fleshy.begin(), fleshy.end(), [&mon]( const material_id &m ) {
            return mon.made_of( m );
        } );

        if( is_fleshy ) {
            play_variant_sound( "bullet_hit", "hit_flesh", heard_volume, angle, 0.8, 1.2 );
            return;
        } else if( mon.made_of( material_id( "stone" ) ) ) {
            play_variant_sound( "bullet_hit", "hit_wall", heard_volume, angle, 0.8, 1.2 );
            return;
        } else if( mon.made_of( material_id( "steel" ) ) ) {
            play_variant_sound( "bullet_hit", "hit_metal", heard_volume, angle, 0.8, 1.2 );
            return;
        } else {
            play_variant_sound( "bullet_hit", "hit_flesh", heard_volume, angle, 0.8, 1.2 );
            return;
        }
    }
    play_variant_sound( "bullet_hit", "hit_flesh", heard_volume, angle, 0.8, 1.2 );
}
예제 #10
0
void inventory::rust_iron_items()
{
    for( auto &elem : items ) {
        for( auto &elem_stack_iter : elem ) {
            if( elem_stack_iter.made_of( material_id( "iron" ) ) &&
                !elem_stack_iter.has_flag( "WATERPROOF_GUN" ) &&
                !elem_stack_iter.has_flag( "WATERPROOF" ) && elem_stack_iter.damage() < elem_stack_iter.max_damage() &&
                one_in( 500 ) ) {
                elem_stack_iter.inc_damage( DT_ACID ); // rusting never completely destroys an item
            }
        }
    }
}
예제 #11
0
void inventory::rust_iron_items()
{
    for( auto &elem : items ) {
        for( auto &elem_stack_iter : elem ) {
            if( elem_stack_iter.made_of( material_id( "iron" ) ) &&
                !elem_stack_iter.has_flag( "WATERPROOF_GUN" ) &&
                !elem_stack_iter.has_flag( "WATERPROOF" ) && elem_stack_iter.damage < 5 &&
                one_in( 500 ) ) {
                elem_stack_iter.damage++;
            }
        }
    }
}
예제 #12
0
field_id mtype::bloodType() const
{
    if( has_flag( MF_ACID_BLOOD ) )
        //A monster that has the death effect "ACID" does not need to have acid blood.
    {
        return fd_acid;
    }
    if( has_flag( MF_BILE_BLOOD ) ) {
        return fd_bile;
    }
    if( has_flag( MF_LARVA ) || has_flag( MF_ARTHROPOD_BLOOD ) ) {
        return fd_blood_invertebrate;
    }
    if( made_of( material_id( "veggy" ) ) ) {
        return fd_blood_veggy;
    }
    if( made_of( material_id( "iflesh" ) ) ) {
        return fd_blood_insect;
    }
    if( has_flag( MF_WARM ) && made_of( material_id( "flesh" ) ) ) {
        return fd_blood;
    }
    return fd_null;
}
예제 #13
0
material_type::material_type()
{
    _ident = material_id( "null" );
    _name = "null";
    _salvage_id = "null";
    _salvage_multiplier = 1.0;
    _bash_resist = 0;
    _cut_resist = 0;
    _bash_dmg_verb = _( "damages" );
    _cut_dmg_verb = _( "damages" );
    _dmg_adj[0] = _( "lightly damaged" );
    _dmg_adj[1] = _( "damaged" );
    _dmg_adj[2] = _( "very damaged" );
    _dmg_adj[3] = _( "thoroughly damaged" );
    _acid_resist = 0;
    _elec_resist = 0;
    _fire_resist = 0;
    _chip_resist = 0;
    _density = 1;
}
void LLMaterialMgr::onGetResponse(bool success, const LLSD& content, const LLUUID& region_id)
{
	if (!success)
	{
		// *TODO: is there any kind of error handling we can do here?
		LL_WARNS("Materials")<< "failed"<<LL_ENDL;
		return;
	}

	llassert(content.isMap());
	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());

	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
	std::istringstream content_stream(content_string);

	LLSD response_data;
	if (!unzip_llsd(response_data, content_stream, content_binary.size()))
	{
		LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL;
		return;
	}

	llassert(response_data.isArray());
	LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL;
	for (LLSD::array_const_iterator itMaterial = response_data.beginArray(); itMaterial != response_data.endArray(); ++itMaterial)
	{
		const LLSD& material_data = *itMaterial;
		llassert(material_data.isMap());

		llassert(material_data.has(MATERIALS_CAP_OBJECT_ID_FIELD));
		llassert(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].isBinary());
		LLMaterialID material_id(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].asBinary());

		llassert(material_data.has(MATERIALS_CAP_MATERIAL_FIELD));
		llassert(material_data[MATERIALS_CAP_MATERIAL_FIELD].isMap());
			
		setMaterial(region_id, material_id, material_data[MATERIALS_CAP_MATERIAL_FIELD]);
	}
}
예제 #15
0
mtype::mtype()
{
    id = mtype_id::NULL_ID();
    name = "human";
    name_plural = "humans";
    sym = " ";
    color = c_white;
    size = MS_MEDIUM;
    volume = 62499_ml;
    weight = 81499_gram;
    mat = { material_id( "flesh" ) };
    phase = SOLID;
    def_chance = 0;
    upgrades = false;
    half_life = -1;
    age_grow = -1;
    upgrade_into = mtype_id::NULL_ID();
    upgrade_group = mongroup_id::NULL_ID();

    reproduces = false;
    baby_timer = -1;
    baby_count = -1;
    baby_monster = mtype_id::NULL_ID();
    baby_egg = "null";

    biosignatures = false;
    biosig_timer = -1;
    biosig_item = "null";

    burn_into = mtype_id::NULL_ID();
    dies.push_back( &mdeath::normal );
    sp_defense = nullptr;
    harvest = harvest_id::NULL_ID();
    luminance = 0;
    bash_skill = 0;

    flags
    .set( MF_HUMAN )
    .set( MF_BONES )
    .set( MF_LEATHER );
}
예제 #16
0
void inventory::rust_iron_items()
{
    for( auto &elem : items ) {
        for( auto &elem_stack_iter : elem ) {
            if( elem_stack_iter.made_of( material_id( "iron" ) ) &&
                !elem_stack_iter.has_flag( "WATERPROOF_GUN" ) &&
                !elem_stack_iter.has_flag( "WATERPROOF" ) &&
                elem_stack_iter.damage() < elem_stack_iter.max_damage() / 2 &&
                //Passivation layer prevents further rusting
                one_in( 500 ) &&
                //Scale with volume, bigger = slower (see #24204)
                one_in( static_cast<int>( 14 * std::cbrt( 0.5 * std::max( 0.05,
                                          static_cast<double>( elem_stack_iter.base_volume().value() ) / 250 ) ) ) ) &&
                //                       ^season length   ^14/5*0.75/3.14 (from volume of sphere)
                g->m.water_from( g->u.pos() ).typeId() ==
                "salt_water" ) { //Freshwater without oxygen rusts slower than air
                elem_stack_iter.inc_damage( DT_ACID ); // rusting never completely destroys an item
                add_msg( m_bad, _( "Your %s is damaged by rust." ), elem_stack_iter.tname() );
            }
        }
    }
}
예제 #17
0
/**
 * @brief Create a duplicate of the Material.
 * @return a pointer to the clone
 */
Material* Material::clone() {

  Material* clone = new Material(material_id(), _name);

  /* Set the number of groups if this Material's groups have been set */
  if (_num_groups > 0)
    clone->setNumEnergyGroups(_num_groups);

  for (int i=0; i < _num_groups; i++) {
    clone->setSigmaTByGroup((double)_sigma_t[i], i+1);
    clone->setSigmaFByGroup((double)_sigma_f[i], i+1);
    clone->setNuSigmaFByGroup((double)_nu_sigma_f[i], i+1);
    clone->setChiByGroup((double)_chi[i], i+1);

    for (int j=0; j < _num_groups; j++)
      clone->setSigmaSByGroup((double)getSigmaSByGroup(i+1,j+1), i+1, j+1);
  }

  if (_fiss_matrix != NULL)
    clone->buildFissionMatrix();

  return clone;
}
예제 #18
0
void mdeath::splatter( monster &z )
{
    // Limit chunking to flesh, veggy and insect creatures until other kinds are supported.
    const std::vector<material_id> gib_mats = {{
            material_id( "flesh" ), material_id( "hflesh" ),
            material_id( "veggy" ), material_id( "iflesh" ),
            material_id( "bone" )
        }
    };
    const bool gibbable = !z.type->has_flag( MF_NOGIB ) &&
    std::any_of( gib_mats.begin(), gib_mats.end(), [&z]( const material_id & gm ) {
        return z.made_of( gm );
    } );

    const int max_hp = std::max( z.get_hp_max(), 1 );
    const float overflow_damage = std::max( -z.get_hp(), 0 );
    const float corpse_damage = 2.5 * overflow_damage / max_hp;
    bool pulverized = corpse_damage > 5 && overflow_damage > z.get_hp_max();
    // make sure that full splatter happens when this is a set death function, not part of normal
    for( const auto &deathfunction : z.type->dies ) {
        if( deathfunction == mdeath::splatter ) {
            pulverized = true;
        }
    }

    const field_id type_blood = z.bloodType();
    const field_id type_gib = z.gibType();

    if( gibbable ) {
        const auto area = g->m.points_in_radius( z.pos(), 1 );
        int number_of_gibs = std::min( std::floor( corpse_damage ) - 1, 1 + max_hp / 5.0f );

        if( pulverized && z.type->size >= MS_MEDIUM ) {
            number_of_gibs += rng( 1, 6 );
            sfx::play_variant_sound( "mon_death", "zombie_gibbed", sfx::get_heard_volume( z.pos() ) );
        }

        for( int i = 0; i < number_of_gibs; ++i ) {
            g->m.add_splatter( type_gib, random_entry( area ), rng( 1, i + 1 ) );
            g->m.add_splatter( type_blood, random_entry( area ) );
        }
    }

    int num_chunks = rng( 0, z.type->get_meat_chunks_count() / 4 );
    num_chunks = std::min( num_chunks, 10 );

    if( pulverized && gibbable ) {
        const itype_id meat = z.type->get_meat_itype();
        const item chunk( meat );
        for( int i = 0; i < num_chunks; i++ ) {
            bool drop_chunks = true;
            tripoint tarp( z.pos() + point( rng( -3, 3 ), rng( -3, 3 ) ) );
            const auto traj = line_to( z.pos(), tarp );

            for( size_t j = 0; j < traj.size(); j++ ) {
                tarp = traj[j];
                if( one_in( 2 ) && type_blood != fd_null ) {
                    g->m.add_splatter( type_blood, tarp );
                } else {
                    g->m.add_splatter( type_gib, tarp, rng( 1, j + 1 ) );
                }
                if( g->m.impassable( tarp ) ) {
                    g->m.bash( tarp, 3 );
                    if( g->m.impassable( tarp ) ) {
                        // Target is obstacle, not destroyed by bashing,
                        // stop trajectory in front of it, if this is the first
                        // point (e.g. wall adjacent to monster), don't drop anything on it
                        if( j > 0 ) {
                            tarp = traj[j - 1];
                        } else {
                            drop_chunks = false;
                        }
                        break;
                    }
                }
            }

            if( drop_chunks ) {
                g->m.add_item_or_charges( tarp, chunk );
            }
        }
    }
}
예제 #19
0
void mutation_branch::load( JsonObject &jo, const std::string & )
{
    mandatory( jo, was_loaded, "id", id );
    mandatory( jo, was_loaded, "name", raw_name, translated_string_reader );
    mandatory( jo, was_loaded, "description", raw_desc, translated_string_reader );
    mandatory( jo, was_loaded, "points", points );

    optional( jo, was_loaded, "visibility", visibility, 0 );
    optional( jo, was_loaded, "ugliness", ugliness, 0 );
    optional( jo, was_loaded, "starting_trait", startingtrait, false );
    optional( jo, was_loaded, "mixed_effect", mixed_effect, false );
    optional( jo, was_loaded, "active", activated, false );
    optional( jo, was_loaded, "starts_active", starts_active, false );
    optional( jo, was_loaded, "destroys_gear", destroys_gear, false );
    optional( jo, was_loaded, "allow_soft_gear", allow_soft_gear, false );
    optional( jo, was_loaded, "cost", cost, 0 );
    optional( jo, was_loaded, "time", cooldown, 0 );
    optional( jo, was_loaded, "hunger", hunger, false );
    optional( jo, was_loaded, "thirst", thirst, false );
    optional( jo, was_loaded, "fatigue", fatigue, false );
    optional( jo, was_loaded, "valid", valid, true );
    optional( jo, was_loaded, "purifiable", purifiable, true );

    if( jo.has_object( "spawn_item" ) ) {
        auto si = jo.get_object( "spawn_item" );
        optional( si, was_loaded, "type", spawn_item );
        optional( si, was_loaded, "message", raw_spawn_item_message );
    }
    if( jo.has_object( "ranged_mutation" ) ) {
        auto si = jo.get_object( "ranged_mutation" );
        optional( si, was_loaded, "type", ranged_mutation );
        optional( si, was_loaded, "message", raw_ranged_mutation_message );
    }
    optional( jo, was_loaded, "initial_ma_styles", initial_ma_styles );

    if( jo.has_array( "bodytemp_modifiers" ) ) {
        auto bodytemp_array = jo.get_array( "bodytemp_modifiers" );
        bodytemp_min = bodytemp_array.get_int( 0 );
        bodytemp_max = bodytemp_array.get_int( 1 );
    }

    optional( jo, was_loaded, "bodytemp_sleep", bodytemp_sleep, 0 );
    optional( jo, was_loaded, "threshold", threshold, false );
    optional( jo, was_loaded, "profession", profession, false );
    optional( jo, was_loaded, "debug", debug, false );
    optional( jo, was_loaded, "player_display", player_display, true );

    JsonArray vr = jo.get_array( "vitamin_rates" );

    while( vr.has_more() ) {
        auto pair = vr.next_array();
        vitamin_rates.emplace( vitamin_id( pair.get_string( 0 ) ),
                               time_duration::from_turns( pair.get_int( 1 ) ) );
    }

    auto vam = jo.get_array( "vitamins_absorb_multi" );
    while( vam.has_more() ) {
        auto pair = vam.next_array();
        std::map<vitamin_id, double> vit;
        auto vit_array = pair.get_array( 1 );
        // fill the inner map with vitamins
        while( vit_array.has_more() ) {
            auto vitamins = vit_array.next_array();
            vit.emplace( vitamin_id( vitamins.get_string( 0 ) ), vitamins.get_float( 1 ) );
        }
        // assign the inner vitamin map to the material_id key
        vitamin_absorb_multi.emplace( material_id( pair.get_string( 0 ) ), vit );
    }

    optional( jo, was_loaded, "healing_awake", healing_awake, 0.0f );
    optional( jo, was_loaded, "healing_resting", healing_resting, 0.0f );
    optional( jo, was_loaded, "hp_modifier", hp_modifier, 0.0f );
    optional( jo, was_loaded, "hp_modifier_secondary", hp_modifier_secondary, 0.0f );
    optional( jo, was_loaded, "hp_adjustment", hp_adjustment, 0.0f );
    optional( jo, was_loaded, "stealth_modifier", stealth_modifier, 0.0f );
    optional( jo, was_loaded, "str_modifier", str_modifier, 0.0f );
    optional( jo, was_loaded, "dodge_modifier", dodge_modifier, 0.0f );
    optional( jo, was_loaded, "speed_modifier", speed_modifier, 1.0f );
    optional( jo, was_loaded, "movecost_modifier", movecost_modifier, 1.0f );
    optional( jo, was_loaded, "movecost_flatground_modifier", movecost_flatground_modifier, 1.0f );
    optional( jo, was_loaded, "movecost_obstacle_modifier", movecost_obstacle_modifier, 1.0f );
    optional( jo, was_loaded, "attackcost_modifier", attackcost_modifier, 1.0f );
    optional( jo, was_loaded, "max_stamina_modifier", max_stamina_modifier, 1.0f );
    optional( jo, was_loaded, "weight_capacity_modifier", weight_capacity_modifier, 1.0f );
    optional( jo, was_loaded, "hearing_modifier", hearing_modifier, 1.0f );
    optional( jo, was_loaded, "noise_modifier", noise_modifier, 1.0f );
    optional( jo, was_loaded, "metabolism_modifier", metabolism_modifier, 0.0f );
    optional( jo, was_loaded, "thirst_modifier", thirst_modifier, 0.0f );
    optional( jo, was_loaded, "fatigue_modifier", fatigue_modifier, 0.0f );
    optional( jo, was_loaded, "fatigue_regen_modifier", fatigue_regen_modifier, 0.0f );
    optional( jo, was_loaded, "stamina_regen_modifier", stamina_regen_modifier, 0.0f );
    optional( jo, was_loaded, "overmap_sight", overmap_sight, 0.0f );
    optional( jo, was_loaded, "overmap_multiplier", overmap_multiplier, 1.0f );

    if( jo.has_object( "social_modifiers" ) ) {
        JsonObject sm = jo.get_object( "social_modifiers" );
        social_mods = load_mutation_social_mods( sm );
    }

    load_mutation_mods( jo, "passive_mods", mods );
    /* Not currently supported due to inability to save active mutation state
    load_mutation_mods(jsobj, "active_mods", new_mut.mods); */

    optional( jo, was_loaded, "prereqs", prereqs );
    optional( jo, was_loaded, "prereqs2", prereqs2 );
    optional( jo, was_loaded, "threshreq", threshreq );
    optional( jo, was_loaded, "cancels", cancels );
    optional( jo, was_loaded, "changes_to", replacements );
    optional( jo, was_loaded, "leads_to", additions );
    optional( jo, was_loaded, "flags", flags );
    optional( jo, was_loaded, "types", types );

    auto jsarr = jo.get_array( "category" );
    while( jsarr.has_more() ) {
        std::string s = jsarr.next_string();
        category.push_back( s );
        mutations_category[s].push_back( trait_id( id ) );
    }

    jsarr = jo.get_array( "wet_protection" );
    while( jsarr.has_more() ) {
        JsonObject jo = jsarr.next_object();
        std::string part_id = jo.get_string( "part" );
        int ignored = jo.get_int( "ignored", 0 );
        int neutral = jo.get_int( "neutral", 0 );
        int good = jo.get_int( "good", 0 );
        tripoint protect = tripoint( ignored, neutral, good );
        protection[get_body_part_token( part_id )] = protect;
    }

    jsarr = jo.get_array( "encumbrance_always" );
    while( jsarr.has_more() ) {
        JsonArray jo = jsarr.next_array();
        std::string part_id = jo.next_string();
        int enc = jo.next_int();
        encumbrance_always[get_body_part_token( part_id )] = enc;
    }

    jsarr = jo.get_array( "encumbrance_covered" );
    while( jsarr.has_more() ) {
        JsonArray jo = jsarr.next_array();
        std::string part_id = jo.next_string();
        int enc = jo.next_int();
        encumbrance_covered[get_body_part_token( part_id )] = enc;
    }

    jsarr = jo.get_array( "restricts_gear" );
    while( jsarr.has_more() ) {
        restricts_gear.insert( get_body_part_token( jsarr.next_string() ) );
    }

    jsarr = jo.get_array( "armor" );
    while( jsarr.has_more() ) {
        JsonObject jo = jsarr.next_object();
        auto parts = jo.get_tags( "parts" );
        std::set<body_part> bps;
        for( const std::string &part_string : parts ) {
            if( part_string == "ALL" ) {
                // Shorthand, since many mutations protect whole body
                bps.insert( all_body_parts.begin(), all_body_parts.end() );
            } else {
                bps.insert( get_body_part_token( part_string ) );
            }
        }

        resistances res = load_resistances_instance( jo );

        for( body_part bp : bps ) {
            armor[ bp ] = res;
        }
    }

    if( jo.has_array( "attacks" ) ) {
        jsarr = jo.get_array( "attacks" );
        while( jsarr.has_more() ) {
            JsonObject jo = jsarr.next_object();
            attacks_granted.emplace_back( load_mutation_attack( jo ) );
        }
    } else if( jo.has_object( "attacks" ) ) {
        JsonObject attack = jo.get_object( "attacks" );
        attacks_granted.emplace_back( load_mutation_attack( attack ) );
    }
}
예제 #20
0
void mdeath::normal( monster &z )
{
    if( z.no_corpse_quiet ) {
        return;
    }

    if( z.type->in_species( ZOMBIE ) ) {
        sfx::play_variant_sound( "mon_death", "zombie_death", sfx::get_heard_volume( z.pos() ) );
    }

    if( g->u.sees( z ) ) {
        //Currently it is possible to get multiple messages that a monster died.
        add_msg( m_good, _( "The %s dies!" ), z.name().c_str() );
    }

    const int max_hp = std::max( z.get_hp_max(), 1 );
    const float overflow_damage = std::max( -z.get_hp(), 0 );
    const float corpse_damage = 2.5 * overflow_damage / max_hp;
    const bool pulverized = corpse_damage > 5 && overflow_damage > z.get_hp_max();

    z.bleed(); // leave some blood if we have to

    if( !pulverized ) {
        make_mon_corpse( z, int( std::floor( corpse_damage ) ) );
    }

    // Limit chunking to flesh, veggy and insect creatures until other kinds are supported.
    const std::vector<material_id> gib_mats = {{
        material_id( "flesh" ), material_id( "hflesh" ),
        material_id( "veggy" ), material_id( "iflesh" ),
        material_id( "bone" )
    }};
    const bool gibbable = !z.type->has_flag( MF_NOGIB ) &&
        std::any_of( gib_mats.begin(), gib_mats.end(), [&z]( const material_id &gm ) {
            return z.made_of( gm );
        } );

    const field_id type_blood = z.bloodType();
    const field_id type_gib = z.gibType();

    if( gibbable ) {
        const auto area = g->m.points_in_radius( z.pos(), 1 );
        int number_of_gibs = std::min( std::floor( corpse_damage ) - 1, 1 + max_hp / 5.0f );

        if( pulverized && z.type->size >= MS_MEDIUM ) {
            number_of_gibs += rng( 1, 6 );
            sfx::play_variant_sound( "mon_death", "zombie_gibbed", sfx::get_heard_volume( z.pos() ) );
        }

        for( int i = 0; i < number_of_gibs; ++i ) {
            g->m.add_splatter( type_gib, random_entry( area ), rng( 1, i + 1 ) );
            g->m.add_splatter( type_blood, random_entry( area ) );
        }
    }

    const int num_chunks = z.type->get_meat_chunks_count();

    if( pulverized && gibbable ) {
        const itype_id meat = z.type->get_meat_itype();
        const item chunk( meat );
        for( int i = 0; i < num_chunks; i++ ) {
            tripoint tarp( z.pos() + point( rng( -3, 3 ), rng( -3, 3 ) ) );
            const auto traj = line_to( z.pos(), tarp );

            for( size_t j = 0; j < traj.size(); j++ ) {
                tarp = traj[j];
                if( one_in( 2 ) && type_blood != fd_null ) {
                    g->m.add_splatter( type_blood, tarp );
                } else {
                    g->m.add_splatter( type_gib, tarp, rng( 1, j + 1 ) );
                }
                if( g->m.impassable( tarp ) ) {
                    g->m.bash( tarp, 3 );
                    if( g->m.impassable( tarp ) ) {
                        // Target is obstacle, not destroyed by bashing,
                        // stop trajectory in front of it, if this is the first
                        // point (e.g. wall adjacent to monster) , make it invalid.
                        if( j > 0 ) {
                            tarp = traj[j - 1];
                        } else {
                            tarp = tripoint_min;
                        }
                        break;
                    }
                }
            }

            if( tarp != tripoint_min ) {
                g->m.add_item_or_charges( tarp, chunk );
            }
        }
    }
}
예제 #21
0
/**
 * Attempts to harm a creature with a projectile.
 *
 * @param source Pointer to the creature who shot the projectile.
 * @param attack A structure describing the attack and its results.
 */
void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack &attack )
{
    const double missed_by = attack.missed_by;
    if( missed_by >= 1.0 ) {
        // Total miss
        return;
    }

    const projectile &proj = attack.proj;
    dealt_damage_instance &dealt_dam = attack.dealt_dam;
    const auto &proj_effects = proj.proj_effects;

    const bool u_see_this = g->u.sees(*this);

    const int avoid_roll = dodge_roll();
    // Do dice(10, speed) instead of dice(speed, 10) because speed could potentially be > 10000
    const int diff_roll = dice( 10, proj.speed );
    // Partial dodge, capped at [0.0, 1.0], added to missed_by
    const double dodge_rescaled = avoid_roll / static_cast<double>( diff_roll );
    const double goodhit = missed_by + std::max( 0.0, std::min( 1.0, dodge_rescaled ) ) ;

    if( goodhit >= 1.0 ) {
        // "Avoid" rather than "dodge", because it includes removing self from the line of fire
        //  rather than just Matrix-style bullet dodging
        if( source != nullptr && g->u.sees( *source ) ) {
            add_msg_player_or_npc(
                m_warning,
                _("You avoid %s projectile!"),
                _("<npcname> avoids %s projectile."),
                source->disp_name(true).c_str() );
        } else {
            add_msg_player_or_npc(
                m_warning,
                _("You avoid an incoming projectile!"),
                _("<npcname> avoids an incoming projectile.") );
        }

        attack.missed_by = 1.0; // Arbitrary value
        return;
    }

    // Bounce applies whether it does damage or not.
    if( proj.proj_effects.count( "BOUNCE" ) ) {
        add_effect( effect_bounced, 1_turns );
    }

    body_part bp_hit;
    double hit_value = missed_by + rng_float(-0.5, 0.5);
    // Headshots considered elsewhere
    if( hit_value <= 0.4 ) {
        bp_hit = bp_torso;
    } else if (one_in(4)) {
        if( one_in(2)) {
            bp_hit = bp_leg_l;
        } else {
            bp_hit = bp_leg_r;
        }
    } else {
        if( one_in(2)) {
            bp_hit = bp_arm_l;
        } else {
            bp_hit = bp_arm_r;
        }
    }

    double damage_mult = 1.0;

    std::string message = "";
    game_message_type gmtSCTcolor = m_neutral;

    if( goodhit < accuracy_headshot ) {
        message = _("Headshot!");
        gmtSCTcolor = m_headshot;
        damage_mult *= rng_float(1.95, 2.05);
        bp_hit = bp_head; // headshot hits the head, of course

    } else if( goodhit < accuracy_critical ) {
        message = _("Critical!");
        gmtSCTcolor = m_critical;
        damage_mult *= rng_float(1.5, 2.0);

    } else if( goodhit < accuracy_goodhit ) {
        message = _("Good hit!");
        gmtSCTcolor = m_good;
        damage_mult *= rng_float(1, 1.5);

    } else if( goodhit < accuracy_standard ) {
        damage_mult *= rng_float(0.5, 1);

    } else if( goodhit < accuracy_grazing ) {
        message = _("Grazing hit.");
        gmtSCTcolor = m_grazing;
        damage_mult *= rng_float(0, .25);
    }

    if( source != nullptr && !message.empty() ) {
        source->add_msg_if_player(m_good, message.c_str());
    }

    attack.missed_by = goodhit;

    // copy it, since we're mutating
    damage_instance impact = proj.impact;
    if( damage_mult > 0.0f && proj_effects.count( "NO_DAMAGE_SCALING" ) ) {
        damage_mult = 1.0f;
    }

    impact.mult_damage(damage_mult);

    if( proj_effects.count( "NOGIB" ) > 0 ) {
        float dmg_ratio = (float)impact.total_damage() / get_hp_max( player::bp_to_hp( bp_hit ) );
        if( dmg_ratio > 1.25f ) {
            impact.mult_damage( 1.0f / dmg_ratio );
        }
    }

    dealt_dam = deal_damage(source, bp_hit, impact);
    dealt_dam.bp_hit = bp_hit;

    // Apply ammo effects to target.
    if (proj.proj_effects.count("FLAME")) {
        if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) ||
            made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) ||
            made_of( material_id( "wood" ) ) ) {
            add_effect( effect_onfire, rng( 8_turns, 20_turns ), bp_hit );
        } else if (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) {
            add_effect( effect_onfire, rng( 5_turns, 10_turns ), bp_hit );
        }
    } else if (proj.proj_effects.count("INCENDIARY") ) {
        if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) ||
            made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) ||
            made_of( material_id( "wood" ) ) ) {
            add_effect( effect_onfire, rng( 2_turns, 6_turns ), bp_hit );
        } else if ( (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) &&
                    one_in(4) ) {
            add_effect( effect_onfire, rng( 1_turns, 4_turns ), bp_hit );
        }
    } else if (proj.proj_effects.count("IGNITE")) {
        if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) ||
            made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) ||
            made_of( material_id( "wood" ) ) ) {
            add_effect( effect_onfire, 6_turns, bp_hit );
        } else if (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) {
            add_effect( effect_onfire, 10_turns, bp_hit );
        }
    }

    if( bp_hit == bp_head && proj_effects.count( "BLINDS_EYES" ) ) {
        // TODO: Change this to require bp_eyes
        add_env_effect( effect_blind, bp_eyes, 5, rng( 3_turns, 10_turns ) );
    }

    if( proj_effects.count( "APPLY_SAP" ) ) {
        add_effect( effect_sap, 1_turns * dealt_dam.total_damage() );
    }

    int stun_strength = 0;
    if (proj.proj_effects.count("BEANBAG")) {
        stun_strength = 4;
    }
    if (proj.proj_effects.count("LARGE_BEANBAG")) {
        stun_strength = 16;
    }
    if( stun_strength > 0 ) {
        switch( get_size() ) {
        case MS_TINY:
            stun_strength *= 4;
            break;
        case MS_SMALL:
            stun_strength *= 2;
            break;
        case MS_MEDIUM:
        default:
            break;
        case MS_LARGE:
            stun_strength /= 2;
            break;
        case MS_HUGE:
            stun_strength /= 4;
            break;
        }
        add_effect( effect_stunned, 1_turns * rng( stun_strength / 2, stun_strength ) );
    }

    if(u_see_this) {
        if( damage_mult == 0 ) {
            if( source != nullptr ) {
                add_msg( source->is_player() ? _("You miss!") : _("The shot misses!") );
            }
        } else if( dealt_dam.total_damage() == 0 ) {
            //~ 1$ - monster name, 2$ - character's bodypart or monster's skin/armor
            add_msg( _("The shot reflects off %1$s %2$s!"), disp_name(true).c_str(),
                     is_monster() ?
                        skin_name().c_str() :
                        body_part_name_accusative(bp_hit).c_str() );
        } else if( is_player() ) {
                //monster hits player ranged
                //~ Hit message. 1$s is bodypart name in accusative. 2$d is damage value.
                add_msg_if_player(m_bad, _( "You were hit in the %1$s for %2$d damage." ),
                                  body_part_name_accusative(bp_hit).c_str(),
                                  dealt_dam.total_damage());
        } else if( source != nullptr ) {
            if( source->is_player() ) {
                //player hits monster ranged
                SCT.add(posx(), posy(),
                        direction_from(0, 0, posx() - source->posx(), posy() - source->posy()),
                        get_hp_bar(dealt_dam.total_damage(), get_hp_max(), true).first,
                        m_good, message, gmtSCTcolor);

                if (get_hp() > 0) {
                    SCT.add(posx(), posy(),
                            direction_from(0, 0, posx() - source->posx(), posy() - source->posy()),
                            get_hp_bar(get_hp(), get_hp_max(), true).first, m_good,
                            //~ "hit points", used in scrolling combat text
                            _("hp"), m_neutral, "hp");
                } else {
                    SCT.removeCreatureHP();
                }

                add_msg(m_good, _("You hit %s for %d damage."),
                        disp_name().c_str(), dealt_dam.total_damage());
            } else if( u_see_this ) {
                //~ 1$ - shooter, 2$ - target
                add_msg(_("%1$s shoots %2$s."),
                        source->disp_name().c_str(), disp_name().c_str());
            }
        }
    }

    check_dead_state();
    attack.hit_critter = this;
    attack.missed_by = goodhit;
}
예제 #22
0
const efftype_id effect_bounced( "bounced" );
const efftype_id effect_downed( "downed" );
const efftype_id effect_onfire( "onfire" );
const efftype_id effect_sap( "sap" );
const efftype_id effect_sleep( "sleep" );
const efftype_id effect_stunned( "stunned" );
const efftype_id effect_zapped( "zapped" );
const efftype_id effect_lying_down( "lying_down" );

const std::map<std::string, m_size> Creature::size_map = {
    {"TINY", MS_TINY}, {"SMALL", MS_SMALL}, {"MEDIUM", MS_MEDIUM},
    {"LARGE", MS_LARGE}, {"HUGE", MS_HUGE}
};

const std::set<material_id> Creature::cmat_flesh{
    material_id( "flesh" ), material_id( "iflesh" )
};
const std::set<material_id> Creature::cmat_fleshnveg{
    material_id( "flesh" ),  material_id( "iflesh" ), material_id( "veggy" )
};
const std::set<material_id> Creature::cmat_flammable{
    material_id( "paper" ), material_id( "powder" ), material_id( "wood" ),
    material_id( "cotton" ), material_id( "wool" )
};
const std::set<material_id> Creature::cmat_flameres{
    material_id( "stone" ), material_id( "kevlar" ), material_id( "steel" )
};

Creature::Creature()
{
    moves = 0;
void LLMaterialMgr::onGetAllResponse(bool success, const LLSD& content, const LLUUID& region_id)
{
	if (!success)
	{
		// *TODO: is there any kind of error handling we can do here?
		LL_WARNS("Materials")<< "failed"<<LL_ENDL;
		return;
	}

	llassert(content.isMap());
	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());

	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
	std::istringstream content_stream(content_string);

	LLSD response_data;
	if (!unzip_llsd(response_data, content_stream, content_binary.size()))
	{
		LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL;
		return;
	}

	get_queue_t::iterator itQueue = mGetQueue.find(region_id);
	material_map_t materials;

	llassert(response_data.isArray());
	LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL;
	for (LLSD::array_const_iterator itMaterial = response_data.beginArray(); itMaterial != response_data.endArray(); ++itMaterial)
	{
		const LLSD& material_data = *itMaterial;
		llassert(material_data.isMap());

		llassert(material_data.has(MATERIALS_CAP_OBJECT_ID_FIELD));
		llassert(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].isBinary());
		LLMaterialID material_id(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].asBinary());
		if (mGetQueue.end() != itQueue)
		{
			itQueue->second.erase(material_id);
		}

		llassert(material_data.has(MATERIALS_CAP_MATERIAL_FIELD));
		llassert(material_data[MATERIALS_CAP_MATERIAL_FIELD].isMap());
		LLMaterialPtr material = setMaterial(region_id, material_id, material_data[MATERIALS_CAP_MATERIAL_FIELD]);
		
		materials[material_id] = material;
	}

	getall_callback_map_t::iterator itCallback = mGetAllCallbacks.find(region_id);
	if (itCallback != mGetAllCallbacks.end())
	{
		(*itCallback->second)(region_id, materials);

		delete itCallback->second;
		mGetAllCallbacks.erase(itCallback);
	}

	if ( (mGetQueue.end() != itQueue) && (itQueue->second.empty()) )
	{
		mGetQueue.erase(itQueue);
	}

	LL_DEBUGS("Materials")<< "recording that getAll has been done for region id " << region_id << LL_ENDL;	
	mGetAllRequested.insert(region_id); // prevents subsequent getAll requests for this region
	mGetAllPending.erase(region_id);	// Invalidates region_id
}
예제 #24
0
bool material_type::is_null() const
{
    return ( _ident == material_id( "null" ) );
}