void stomach_contents::ingest( player &p, item &food, int charges = 1 ) { item comest; if( food.is_container() ) { comest = food.get_contained(); } else { comest = food; } if( charges == 0 ) { // if charges is 0, it means the item is not count_by_charges charges = 1; } // maybe move tapeworm to digestion for( const auto &v : p.vitamins_from( comest ) ) { vitamins[v.first] += p.has_effect( efftype_id( "tapeworm" ) ) ? v.second / 2 : v.second; } auto &comest_t = comest.type->comestible; const units::volume add_water = std::max( 0_ml, comest_t->quench * 5_ml ); // if this number is negative, we decrease the quench/increase the thirst of the player if( comest_t->quench < 0 ) { p.mod_thirst( -comest_t->quench ); } else { mod_quench( comest_t->quench ); } // @TODO: Move quench values to mL and remove the magic number here mod_contents( ( comest.base_volume() * charges ) - add_water ); last_ate = calendar::turn; mod_calories( comest_t->get_calories() ); }
mon_effect_data load_mon_effect_data( JsonObject &e ) { return mon_effect_data( efftype_id( e.get_string( "id" ) ), e.get_int( "duration", 0 ), e.get_bool( "affect_hit_bp", false ), get_body_part_token( e.get_string( "bp", "NUM_BP" ) ), e.get_bool( "permanent", false ), e.get_int( "chance", 100 ) ); }
npc create_model() { npc model_npc; model_npc.normalize(); model_npc.randomize( NC_NONE ); for( trait_id tr : model_npc.get_mutations() ) { model_npc.unset_mutation( tr ); } model_npc.set_hunger( 0 ); model_npc.set_thirst( 0 ); model_npc.set_fatigue( 0 ); model_npc.remove_effect( efftype_id( "sleep" ) ); // An ugly hack to prevent NPC falling asleep during testing due to massive fatigue model_npc.set_mutation( trait_id( "WEB_WEAVER" ) ); return model_npc; }
void mtype::load( JsonObject &jo ) { MonsterGenerator &gen = MonsterGenerator::generator(); // Name and name plural are not translated here, but when needed in // combination with the actual count in `mtype::nname`. mandatory( jo, was_loaded, "name", name ); // default behaviour: Assume the regular plural form (appending an “s”) optional( jo, was_loaded, "name_plural", name_plural, name + "s" ); mandatory( jo, was_loaded, "description", description, translated_string_reader ); // Have to overwrite the default { "hflesh" } here if( !was_loaded || jo.has_member( "material" ) ) { mat = { jo.get_string( "material" ) }; } optional( jo, was_loaded, "species", species, auto_flags_reader<species_id> {} ); optional( jo, was_loaded, "categories", categories, auto_flags_reader<> {} ); // See monfaction.cpp if( !was_loaded || jo.has_member( "default_faction" ) ) { const auto faction = mfaction_str_id( jo.get_string( "default_faction" ) ); default_faction = monfactions::get_or_add_faction( faction ); } if( !was_loaded || jo.has_member( "symbol" ) ) { sym = jo.get_string( "symbol" ); if( utf8_wrapper( sym ).display_width() != 1 ) { jo.throw_error( "monster symbol should be exactly one console cell width", "symbol" ); } } mandatory( jo, was_loaded, "color", color, color_reader{} ); const typed_flag_reader<decltype( Creature::size_map )> size_reader{ Creature::size_map, "invalid creature size" }; optional( jo, was_loaded, "size", size, size_reader, MS_MEDIUM ); const typed_flag_reader<decltype( gen.phase_map )> phase_reader{ gen.phase_map, "invalid phase id" }; optional( jo, was_loaded, "phase", phase, phase_reader, SOLID ); optional( jo, was_loaded, "diff", difficulty, 0 ); optional( jo, was_loaded, "aggression", agro, 0 ); optional( jo, was_loaded, "morale", morale, 0 ); optional( jo, was_loaded, "speed", speed, 0 ); optional( jo, was_loaded, "attack_cost", attack_cost, 100 ); optional( jo, was_loaded, "melee_skill", melee_skill, 0 ); optional( jo, was_loaded, "melee_dice", melee_dice, 0 ); optional( jo, was_loaded, "melee_dice_sides", melee_sides, 0 ); optional( jo, was_loaded, "melee_cut", melee_cut, 0 ); optional( jo, was_loaded, "dodge", sk_dodge, 0 ); optional( jo, was_loaded, "armor_bash", armor_bash, 0 ); optional( jo, was_loaded, "armor_cut", armor_cut, 0 ); optional( jo, was_loaded, "armor_acid", armor_acid, armor_cut / 2 ); optional( jo, was_loaded, "armor_fire", armor_fire, 0 ); optional( jo, was_loaded, "hp", hp, 0 ); optional( jo, was_loaded, "starting_ammo", starting_ammo ); optional( jo, was_loaded, "luminance", luminance, 0 ); optional( jo, was_loaded, "revert_to_itype", revert_to_itype, "" ); optional( jo, was_loaded, "vision_day", vision_day, 40 ); optional( jo, was_loaded, "vision_night", vision_night, 1 ); optional( jo, was_loaded, "armor_stab", armor_stab, 0.8f * armor_cut ); // TODO: allow adding/removing specific entries if `was_loaded` is true if( jo.has_array( "attack_effs" ) ) { JsonArray jsarr = jo.get_array( "attack_effs" ); while( jsarr.has_more() ) { JsonObject e = jsarr.next_object(); mon_effect_data new_eff( efftype_id( e.get_string( "id" ) ), e.get_int( "duration", 0 ), get_body_part_token( e.get_string( "bp", "NUM_BP" ) ), e.get_bool( "permanent", false ), e.get_int( "chance", 100 ) ); atk_effs.push_back( new_eff ); } } if( jo.has_member( "death_drops" ) ) { JsonIn &stream = *jo.get_raw( "death_drops" ); death_drops = item_group::load_item_group( stream, "distribution" ); } const typed_flag_reader<decltype( gen.death_map )> death_reader{ gen.death_map, "invalid monster death function" }; optional( jo, was_loaded, "death_function", dies, death_reader ); if( dies.empty() ) { // TODO: really needed? Is an empty `dies` container not allowed? dies.push_back( mdeath::normal ); } // TODO: allow overriding/adding/removing those if `was_loaded` is true gen.load_special_defense( this, jo, "special_when_hit" ); gen.load_special_attacks( this, jo, "special_attacks" ); // Disable upgrading when JSON contains `"upgrades": false`, but fallback to the // normal behavior (including error checking) if "upgrades" is not boolean or not `false`. if( jo.has_bool( "upgrades" ) && !jo.get_bool( "upgrades" ) ) { upgrade_group = mongroup_id::NULL_ID; upgrade_into = mtype_id::NULL_ID; upgrades = false; } else if( jo.has_member( "upgrades" ) ) { JsonObject up = jo.get_object( "upgrades" ); optional( up, was_loaded, "half_life", half_life, -1 ); optional( up, was_loaded, "into_group", upgrade_group, auto_flags_reader<mongroup_id> {}, mongroup_id::NULL_ID ); optional( up, was_loaded, "into", upgrade_into, auto_flags_reader<mtype_id> {}, mtype_id::NULL_ID ); upgrades = true; } const typed_flag_reader<decltype( gen.flag_map )> flag_reader{ gen.flag_map, "invalid monster flag" }; optional( jo, was_loaded, "flags", flags, flag_reader ); const typed_flag_reader<decltype( gen.trigger_map )> trigger_reader{ gen.trigger_map, "invalid monster trigger" }; optional( jo, was_loaded, "anger_triggers", anger, trigger_reader ); optional( jo, was_loaded, "placate_triggers", placate, trigger_reader ); optional( jo, was_loaded, "fear_triggers", fear, trigger_reader ); }
void erase_next( JsonIn &jin, C &container ) const { const efftype_id id = efftype_id( jin.get_string() ); reader_detail::handler<C>().erase_if( container, [&id]( const mon_effect_data & e ) { return e.id == id; } ); }
efftype_id ma_buff::get_effect_id() const { return efftype_id( std::string( "mabuff:" ) + id.str() ); }
mon_effect_data get_next( JsonIn &jin ) const { JsonObject e = jin.get_object(); return mon_effect_data( efftype_id( e.get_string( "id" ) ), e.get_int( "duration", 0 ), get_body_part_token( e.get_string( "bp", "NUM_BP" ) ), e.get_bool( "permanent", false ), e.get_int( "chance", 100 ) ); }
while( dummy.takeoff( dummy.i_at( -2 ), &temp ) ); dummy.inv.clear(); dummy.remove_weapon(); return dummy; } TEST_CASE( "use_eyedrops" ) { player &dummy = get_sanitized_player(); item &test_item = dummy.i_add( item( "saline", 0, item::default_charges_tag{} ) ); REQUIRE( test_item.charges == 5 ); dummy.add_env_effect( efftype_id( "boomered" ), bp_eyes, 3, 12_turns ); int test_item_pos = dummy.inv.position_by_item( &test_item ); REQUIRE( test_item_pos != INT_MIN ); dummy.consume( test_item_pos ); test_item_pos = dummy.inv.position_by_item( &test_item ); REQUIRE( test_item_pos != INT_MIN ); REQUIRE( test_item.charges == 4 ); REQUIRE( !dummy.has_effect( efftype_id( "boomered" ) ) ); dummy.consume( test_item_pos ); dummy.consume( test_item_pos ); dummy.consume( test_item_pos ); dummy.consume( test_item_pos );