From 211d2aa02fe38436dd198f55d8ce6bbe2d4e6948 Mon Sep 17 00:00:00 2001 From: Eric <52087122+Ramza13@users.noreply.github.com> Date: Mon, 20 Jan 2020 18:56:36 -0500 Subject: [PATCH] Migrate/cleanup consumption.cpp from player to character (#36991) --- src/character.h | 112 ++++++++++++- src/consumption.cpp | 398 ++++++++++++++++++++++++++------------------ src/player.h | 115 +------------ 3 files changed, 346 insertions(+), 279 deletions(-) diff --git a/src/character.h b/src/character.h index c6487bfb398ab..fdea01833c253 100644 --- a/src/character.h +++ b/src/character.h @@ -123,6 +123,38 @@ enum sleep_deprivation_levels { SLEEP_DEPRIVATION_MASSIVE = 14 * 24 * 60 }; +// This tries to represent both rating and +// character's decision to respect said rating +enum edible_rating { + // Edible or we pretend it is + EDIBLE, + // Not food at all + INEDIBLE, + // Not food because mutated mouth/system + INEDIBLE_MUTATION, + // You can eat it, but it will hurt morale + ALLERGY, + // Smaller allergy penalty + ALLERGY_WEAK, + // Cannibalism (unless psycho/cannibal) + CANNIBALISM, + // Rotten or not rotten enough (for saprophages) + ROTTEN, + // Can provoke vomiting if you already feel nauseous. + NAUSEA, + // We can eat this, but we'll overeat + TOO_FULL, + // Some weird stuff that requires a tool we don't have + NO_TOOL +}; + +enum class rechargeable_cbm { + none = 0, + reactor, + furnace, + other +}; + struct layer_details { std::vector pieces; @@ -309,6 +341,8 @@ class Character : public Creature, public visitable virtual int get_hunger() const; virtual int get_starvation() const; virtual int get_thirst() const; + /** Gets character's minimum hunger and thirst */ + int stomach_capacity() const; virtual std::pair get_thirst_description() const; virtual std::pair get_hunger_description() const; virtual std::pair get_fatigue_description() const; @@ -1594,17 +1628,89 @@ class Character : public Creature, public visitable */ int vitamin_get( const vitamin_id &vit ) const; /** - * Add or subtract vitamins from player storage pools + * Sets level of a vitamin or returns false if id given in vit does not exist + * + * @note status effects are still set for deficiency/excess + * + * @param[in] vit ID of vitamin to adjust quantity for + * @param[in] qty Quantity to set level to + * @returns false if given vitamin_id does not exist, otherwise true + */ + bool vitamin_set( const vitamin_id &vit, int qty ); + /** + * Add or subtract vitamins from character storage pools * @param vit ID of vitamin to modify * @param qty amount by which to adjust vitamin (negative values are permitted) * @param capped if true prevent vitamins which can accumulate in excess from doing so * @return adjusted level for the vitamin or zero if vitamin does not exist */ int vitamin_mod( const vitamin_id &vit, int qty, bool capped = true ); + /** Handles the nutrition value for a comestible **/ + int nutrition_for( const item &comest ) const; + /** Can the food be [theoretically] eaten no matter the consequen + ces? */ + ret_val can_eat( const item &food ) const; + /** + * Same as @ref can_eat, but takes consequences into account. + * Asks about them if @param interactive is true, refuses otherwise. + */ + ret_val will_eat( const item &food, bool interactive = false ) const; + /** Determine character's capability of recharging their CBMs. */ + bool can_feed_reactor_with( const item &it ) const; + bool can_feed_furnace_with( const item &it ) const; + rechargeable_cbm get_cbm_rechargeable_with( const item &it ) const; + int get_acquirable_energy( const item &it, rechargeable_cbm cbm ) const; + int get_acquirable_energy( const item &it ) const; - /** Returns true if the player is wearing something on the entered body_part */ + /** + * Recharge CBMs whenever possible. + * @return true when recharging was successful. + */ + bool feed_reactor_with( item &it ); + bool feed_furnace_with( item &it ); + bool fuel_bionic_with( item &it ); + /** Used to apply stimulation modifications from food and medication **/ + void modify_stimulation( const islot_comestible &comest ); + /** Used to apply addiction modifications from food and medication **/ + void modify_addiction( const islot_comestible &comest ); + /** Used to apply health modifications from food and medication **/ + void modify_health( const islot_comestible &comest ); + /** Handles the effects of consuming an item */ + bool consume_effects( item &food ); + /** Check character's capability of consumption overall */ + bool can_consume( const item &it ) const; + /** True if the character has enough skill (in cooking or survival) to estimate time to rot */ + bool can_estimate_rot() const; + /** Check whether character can consume this very item */ + bool can_consume_as_is( const item &it ) const; + /** + * Returns a reference to the item itself (if it's consumable), + * the first of its contents (if it's consumable) or null item otherwise. + * WARNING: consumable does not necessarily guarantee the comestible type. + */ + item &get_consumable_from( item &it ) const; + + hint_rating rate_action_eat( const item &it ) const; + + /** Get calorie & vitamin contents for a comestible, taking into + * account character traits */ + /** Get range of possible nutrient content, for a particular recipe, + * depending on choice of ingredients */ + std::pair compute_nutrient_range( + const item &, const recipe_id &, + const cata::flat_set &extra_flags = {} ) const; + /** Same, but across arbitrary recipes */ + std::pair compute_nutrient_range( + const itype_id &, const cata::flat_set &extra_flags = {} ) const; + /** Get vitamin usage rate (minutes per unit) accounting for bionics, mutations and effects */ + time_duration vitamin_rate( const vitamin_id &vit ) const; + void vitamins_mod( const std::map &, bool capped = true ); + /** Returns allergy type or MORALE_NULL if not allergic for this character */ + morale_type allergy_type( const item &food ) const; + nutrients compute_effective_nutrients( const item & ) const; + /** Returns true if the character is wearing something on the entered body_part */ bool wearing_something_on( body_part bp ) const; - /** Returns true if the player is wearing something occupying the helmet slot */ + /** Returns true if the character is wearing something occupying the helmet slot */ bool is_wearing_helmet() const; /** Returns the total encumbrance of all SKINTIGHT and HELMET_COMPAT items coveringi * the head */ diff --git a/src/consumption.cpp b/src/consumption.cpp index 80650e07ed2f2..bcca68b406520 100644 --- a/src/consumption.cpp +++ b/src/consumption.cpp @@ -59,15 +59,104 @@ static const bionic_id bio_advreactor( "bio_advreactor" ); static const bionic_id bio_digestion( "bio_digestion" ); static const bionic_id bio_furnace( "bio_furnace" ); static const bionic_id bio_reactor( "bio_reactor" ); +static const bionic_id bio_syringe( "bio_syringe" ); static const bionic_id bio_taste_blocker( "bio_taste_blocker" ); +static const trait_id trait_ACIDBLOOD( "ACIDBLOOD" ); +static const trait_id trait_AMORPHOUS( "AMORPHOUS" ); +static const trait_id trait_ANTIFRUIT( "ANTIFRUIT" ); +static const trait_id trait_ANTIJUNK( "ANTIJUNK" ); +static const trait_id trait_ANTIWHEAT( "ANTIWHEAT" ); +static const trait_id trait_BEAK_HUM( "BEAK_HUM" ); +static const trait_id trait_CANNIBAL( "CANNIBAL" ); +static const trait_id trait_CARNIVORE( "CARNIVORE" ); +static const trait_id trait_EATDEAD( "EATDEAD" ); +static const trait_id trait_EATHEALTH( "EATHEALTH" ); +static const trait_id trait_EATPOISON( "EATPOISON" ); +static const trait_id trait_GIZZARD( "GIZZARD" ); +static const trait_id trait_GOURMAND( "GOURMAND" ); +static const trait_id trait_FANGS_SPIDER( "FANGS_SPIDER" ); +static const trait_id trait_HERBIVORE( "HERBIVORE" ); +static const trait_id trait_HIBERNATE( "HIBERNATE" ); +static const trait_id trait_LACTOSE( "LACTOSE" ); +static const trait_id trait_M_DEPENDENT( "M_DEPENDENT" ); +static const trait_id trait_M_IMMUNE( "M_IMMUNE" ); +static const trait_id trait_MANDIBLES( "MANDIBLES" ); +static const trait_id trait_MEATARIAN( "MEATARIAN" ); +static const trait_id trait_MOUTH_TENTACLES( "MOUTH_TENTACLES" ); +static const trait_id trait_PARAIMMUNE( "PARAIMMUNE" ); +static const trait_id trait_PROBOSCIS( "PROBOSCIS" ); +static const trait_id trait_PROJUNK( "PROJUNK" ); +static const trait_id trait_PROJUNK2( "PROJUNK2" ); +static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" ); +static const trait_id trait_SABER_TEETH( "SABER_TEETH" ); +static const trait_id trait_SAPIOVORE( "SAPIOVORE" ); +static const trait_id trait_SAPROPHAGE( "SAPROPHAGE" ); +static const trait_id trait_SAPROVORE( "SAPROVORE" ); +static const trait_id trait_SHARKTEETH( "SHARKTEETH" ); +static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" ); +static const trait_id trait_SLIMESPAWNER( "SLIMESPAWNER" ); +static const trait_id trait_SPIRITUAL( "SPIRITUAL" ); +static const trait_id trait_STIMBOOST( "STIMBOOST" ); +static const trait_id trait_RUMINANT( "RUMINANT" ); +static const trait_id trait_TABLEMANNERS( "TABLEMANNERS" ); +static const trait_id trait_THRESH_BIRD( "THRESH_BIRD" ); +static const trait_id trait_THRESH_CATTLE( "THRESH_CATTLE" ); +static const trait_id trait_THRESH_LUPINE( "THRESH_LUPINE" ); +static const trait_id trait_THRESH_FELINE( "THRESH_FELINE" ); +static const trait_id trait_THRESH_PLANT( "THRESH_PLANT" ); +static const trait_id trait_THRESH_URSINE( "THRESH_URSINE" ); +static const trait_id trait_WATERSLEEP( "WATERSLEEP" ); +static const trait_id trait_VEGETARIAN( "VEGETARIAN" ); + +static const std::string flag_ALLERGEN_EGG( "ALLERGEN_EGG" ); +static const std::string flag_ALLERGEN_FRUIT( "ALLERGEN_FRUIT" ); +static const std::string flag_ALLERGEN_JUNK( "ALLERGEN_JUNK" ); +static const std::string flag_ALLERGEN_MEAT( "ALLERGEN_MEAT" ); +static const std::string flag_ALLERGEN_MILK( "ALLERGEN_MILK" ); +static const std::string flag_ALLERGEN_WHEAT( "ALLERGEN_WHEAT" ); +static const std::string flag_ALLERGEN_VEGGY( "ALLERGEN_VEGGY" ); +static const std::string flag_BIRD( "BIRD" ); +static const std::string flag_BYPRODUCT( "BYPRODUCT" ); +static const std::string flag_CANNIBALISM( "CANNIBALISM" ); +static const std::string flag_CARNIVORE_OK( "CARNIVORE_OK" ); +static const std::string flag_CATTLE( "CATTLE" ); +static const std::string flag_COOKED( "COOKED" ); +static const std::string flag_COLD( "COLD" ); +static const std::string flag_CORPSE( "CORPSE" ); +static const std::string flag_EATEN_COLD( "EATEN_COLD" ); +static const std::string flag_EDIBLE_FROZEN( "EDIBLE_FROZEN" ); +static const std::string flag_EATEN_HOT( "EATEN_HOT" ); +static const std::string flag_INEDIBLE( "INEDIBLE" ); +static const std::string flag_FERTILIZER( "FERTILIZER" ); +static const std::string flag_FELINE( "FELINE" ); +static const std::string flag_FROZEN( "FROZEN" ); +static const std::string flag_FUNGAL_VECTOR( "FUNGAL_VECTOR" ); +static const std::string flag_HIDDEN_HALLU( "HIDDEN_HALLU" ); +static const std::string flag_HOT( "HOT" ); +static const std::string flag_LUPINE( "LUPINE" ); +static const std::string flag_MYCUS_OK( "MYCUS_OK" ); +static const std::string flag_MELTS( "MELTS" ); +static const std::string flag_MUSHY( "MUSHY" ); +static const std::string flag_NEGATIVE_MONOTONY_OK( "NEGATIVE_MONOTONY_OK" ); +static const std::string flag_NO_PARASITES( "NO_PARASITES" ); +static const std::string flag_NO_RELOAD( "NO_RELOAD" ); +static const std::string flag_NUTRIENT_OVERRIDE( "NUTRIENT_OVERRIDE" ); +static const std::string flag_RADIOACTIVE( "RADIOACTIVE" ); +static const std::string flag_RAW( "RAW" ); +static const std::string flag_USE_EAT_VERB( "USE_EAT_VERB" ); +static const std::string flag_URSINE_HONEY( "URSINE_HONEY" ); + +static const std::string comesttype_FOOD( "FOOD" ); +static const std::string comesttype_DRINK( "DRINK" ); + const std::vector carnivore_blacklist {{ - "ALLERGEN_VEGGY", "ALLERGEN_FRUIT", "ALLERGEN_WHEAT", + flag_ALLERGEN_VEGGY, flag_ALLERGEN_FRUIT, flag_ALLERGEN_WHEAT, } }; // This ugly temp array is here because otherwise it goes // std::vector(char*, char*)->vector(InputIterator,InputIterator) or some such -const std::array temparray {{"ALLERGEN_MEAT", "ALLERGEN_EGG"}}; +const std::array temparray {{flag_ALLERGEN_MEAT, flag_ALLERGEN_EGG}}; const std::vector herbivore_blacklist( temparray.begin(), temparray.end() ); // Defines the maximum volume that a internal furnace can consume @@ -80,17 +169,17 @@ const std::map plut_charges = { { "plut_slurry", PLUTONIUM_CHARGES / 2 } }; -int player::stomach_capacity() const +int Character::stomach_capacity() const { - if( has_trait( trait_id( "GIZZARD" ) ) ) { + if( has_trait( trait_GIZZARD ) ) { return 0; } - if( has_active_mutation( trait_id( "HIBERNATE" ) ) ) { + if( has_active_mutation( trait_HIBERNATE ) ) { return -620; } - if( has_trait( trait_id( "GOURMAND" ) ) || has_trait( trait_id( "HIBERNATE" ) ) ) { + if( has_trait( trait_GOURMAND ) || has_trait( trait_HIBERNATE ) ) { return -60; } @@ -98,14 +187,9 @@ int player::stomach_capacity() const } // TODO: Move pizza scraping here. -static int compute_default_effective_kcal( const item &comest, const player &p, +static int compute_default_effective_kcal( const item &comest, const Character &you, const cata::flat_set &extra_flags = {} ) { - static const trait_id trait_CARNIVORE( "CARNIVORE" ); - static const trait_id trait_GIZZARD( "GIZZARD" ); - static const trait_id trait_SAPROPHAGE( "SAPROPHAGE" ); - static const std::string flag_CARNIVORE_OK( "CARNIVORE_OK" ); - if( !comest.get_comestible() ) { return 0; } @@ -114,16 +198,16 @@ static int compute_default_effective_kcal( const item &comest, const player &p, float kcal = comest.get_comestible()->default_nutrition.kcal; // Many raw foods give less calories, as your body has expends more energy digesting them. - bool cooked = comest.has_flag( "COOKED" ) || extra_flags.count( "COOKED" ); - if( comest.has_flag( "RAW" ) && !cooked ) { + bool cooked = comest.has_flag( flag_COOKED ) || extra_flags.count( flag_COOKED ); + if( comest.has_flag( flag_RAW ) && !cooked ) { kcal *= 0.75f; } - if( p.has_trait( trait_GIZZARD ) ) { + if( you.has_trait( trait_GIZZARD ) ) { kcal *= 0.6f; } - if( p.has_trait( trait_CARNIVORE ) && comest.has_flag( flag_CARNIVORE_OK ) && + if( you.has_trait( trait_CARNIVORE ) && comest.has_flag( flag_CARNIVORE_OK ) && comest.has_any_flag( carnivore_blacklist ) ) { // TODO: Comment pizza scrapping kcal *= 0.5f; @@ -131,7 +215,7 @@ static int compute_default_effective_kcal( const item &comest, const player &p, const float relative_rot = comest.get_relative_rot(); // Saprophages get full nutrition from rotting food - if( relative_rot > 1.0f && !p.has_trait( trait_SAPROPHAGE ) ) { + if( relative_rot > 1.0f && !you.has_trait( trait_SAPROPHAGE ) ) { // everyone else only gets a portion of the nutrition // Scaling linearly from 100% at just-rotten to 0 at halfway-rotten-away const float rottedness = clamp( 2 * relative_rot - 2.0f, 0.1f, 1.0f ); @@ -139,7 +223,7 @@ static int compute_default_effective_kcal( const item &comest, const player &p, } // Bionic digestion gives extra nutrition - if( p.has_bionic( bio_digestion ) ) { + if( you.has_bionic( bio_digestion ) ) { kcal *= 1.5f; } @@ -149,7 +233,7 @@ static int compute_default_effective_kcal( const item &comest, const player &p, // Compute default effective vitamins for an item, taking into account player // traits, but not components of the item. static std::map compute_default_effective_vitamins( - const item &it, const player &p ) + const item &it, const Character &you ) { if( !it.get_comestible() ) { return {}; @@ -157,7 +241,7 @@ static std::map compute_default_effective_vitamins( std::map res = it.get_comestible()->default_nutrition.vitamins; - for( const trait_id &trait : p.get_mutations() ) { + for( const trait_id &trait : you.get_mutations() ) { const auto &mut = trait.obj(); // make sure to iterate over every material defined for vitamin absorption // TODO: put this loop into a function and utilize it again for bionics @@ -179,31 +263,31 @@ static std::map compute_default_effective_vitamins( } // Calculate the effective nutrients for a given item, taking -// into account player traits but not item components. +// into account character traits but not item components. static nutrients compute_default_effective_nutrients( const item &comest, - const player &p, const cata::flat_set &extra_flags = {} ) + const Character &you, const cata::flat_set &extra_flags = {} ) { - return { compute_default_effective_kcal( comest, p, extra_flags ), - compute_default_effective_vitamins( comest, p ) }; + return { compute_default_effective_kcal( comest, you, extra_flags ), + compute_default_effective_vitamins( comest, you ) }; } -// Calculate the nutrients that the given player would receive from consuming -// the given item, taking into account the item components and the player's +// Calculate the nutrients that the given character would receive from consuming +// the given item, taking into account the item components and the character's // traits. -// This is used by item display, making actual nutrition available to player. -nutrients player::compute_effective_nutrients( const item &comest ) const +// This is used by item display, making actual nutrition available to character. +nutrients Character::compute_effective_nutrients( const item &comest ) const { if( !comest.is_comestible() ) { return {}; } // if item has components, will derive calories from that instead. - if( !comest.components.empty() && !comest.has_flag( "NUTRIENT_OVERRIDE" ) ) { + if( !comest.components.empty() && !comest.has_flag( flag_NUTRIENT_OVERRIDE ) ) { nutrients tally{}; for( const item &component : comest.components ) { nutrients component_value = compute_effective_nutrients( component ) * component.charges; - if( component.has_flag( "BYPRODUCT" ) ) { + if( component.has_flag( flag_BYPRODUCT ) ) { tally -= component_value; } else { tally += component_value; @@ -217,7 +301,7 @@ nutrients player::compute_effective_nutrients( const item &comest ) const // Calculate range of nutrients obtainable for a given item when crafted via // the given recipe -std::pair player::compute_nutrient_range( +std::pair Character::compute_nutrient_range( const item &comest, const recipe_id &recipe_i, const cata::flat_set &extra_flags ) const { @@ -226,7 +310,7 @@ std::pair player::compute_nutrient_range( } // if item has components, will derive calories from that instead. - if( comest.has_flag( "NUTRIENT_OVERRIDE" ) ) { + if( comest.has_flag( flag_NUTRIENT_OVERRIDE ) ) { nutrients result = compute_default_effective_nutrients( comest, *this ); return { result, result }; } @@ -239,7 +323,7 @@ std::pair player::compute_nutrient_range( cata::flat_set our_extra_flags = extra_flags; if( rec.hot_result() ) { - our_extra_flags.insert( "COOKED" ); + our_extra_flags.insert( flag_COOKED ); } const requirement_data requirements = rec.simple_requirements(); @@ -281,7 +365,7 @@ std::pair player::compute_nutrient_range( // Calculate the range of nturients possible for a given item across all // possible recipes -std::pair player::compute_nutrient_range( +std::pair Character::compute_nutrient_range( const itype_id &comest_id, const cata::flat_set &extra_flags ) const { const itype *comest = item::find_type( comest_id ); @@ -293,7 +377,7 @@ std::pair player::compute_nutrient_range( // The default nutrients are always a possibility nutrients min_nutr = compute_default_effective_nutrients( comest_it, *this, extra_flags ); - if( comest->item_tags.count( "NUTRIENT_OVERRIDE" ) || + if( comest->item_tags.count( flag_NUTRIENT_OVERRIDE ) || recipe_dict.is_item_on_loop( comest->get_id() ) ) { return { min_nutr, min_nutr }; } @@ -323,24 +407,13 @@ std::pair player::compute_nutrient_range( return { min_nutr, max_nutr }; } -int player::nutrition_for( const item &comest ) const +int Character::nutrition_for( const item &comest ) const { return compute_effective_nutrients( comest ).kcal / islot_comestible::kcal_per_nutr; } std::pair Character::fun_for( const item &comest ) const { - static const trait_id trait_GOURMAND( "GOURMAND" ); - static const trait_id trait_SAPROPHAGE( "SAPROPHAGE" ); - static const trait_id trait_SAPROVORE( "SAPROVORE" ); - static const trait_id trait_LUPINE( "THRESH_LUPINE" ); - static const trait_id trait_FELINE( "THRESH_FELINE" ); - static const std::string flag_EATEN_COLD( "EATEN_COLD" ); - static const std::string flag_COLD( "COLD" ); - static const std::string flag_FROZEN( "FROZEN" ); - static const std::string flag_MELTS( "MELTS" ); - static const std::string flag_LUPINE( "LUPINE" ); - static const std::string flag_FELINE( "FELINE" ); if( !comest.is_comestible() ) { return std::pair( 0, 0 ); } @@ -368,14 +441,14 @@ std::pair Character::fun_for( const item &comest ) const } // Food is less enjoyable when eaten too often. - if( fun > 0 || comest.has_flag( "NEGATIVE_MONOTONY_OK" ) ) { + if( fun > 0 || comest.has_flag( flag_NEGATIVE_MONOTONY_OK ) ) { for( const consumption_event &event : consumption_history ) { if( event.time > calendar::turn - 2_days && event.type_id == comest.typeId() && event.component_hash == comest.make_component_hash() ) { fun -= comest.get_comestible()->monotony_penalty; // This effect can't drop fun below 0, unless the food has the right flag. // 0 is the lowest we'll go, no need to keep looping. - if( fun <= 0 && !comest.has_flag( "NEGATIVE_MONOTONY_OK" ) ) { + if( fun <= 0 && !comest.has_flag( flag_NEGATIVE_MONOTONY_OK ) ) { fun = 0; break; } @@ -403,8 +476,8 @@ std::pair Character::fun_for( const item &comest ) const } } - if( ( comest.has_flag( flag_LUPINE ) && has_trait( trait_LUPINE ) ) || - ( comest.has_flag( flag_FELINE ) && has_trait( trait_FELINE ) ) ) { + if( ( comest.has_flag( flag_LUPINE ) && has_trait( trait_THRESH_LUPINE ) ) || + ( comest.has_flag( flag_FELINE ) && has_trait( trait_THRESH_FELINE ) ) ) { if( fun < 0 ) { fun = -fun; fun /= 2; @@ -430,7 +503,7 @@ std::pair Character::fun_for( const item &comest ) const return { static_cast< int >( fun ), static_cast< int >( fun_max ) }; } -time_duration player::vitamin_rate( const vitamin_id &vit ) const +time_duration Character::vitamin_rate( const vitamin_id &vit ) const { time_duration res = vit.obj().rate(); @@ -466,7 +539,7 @@ int Character::vitamin_mod( const vitamin_id &vit, int qty, bool capped ) return it->second; } -void player::vitamins_mod( const std::map &vitamins, bool capped ) +void Character::vitamins_mod( const std::map &vitamins, bool capped ) { for( auto vit : vitamins ) { vitamin_mod( vit.first, vit.second, capped ); @@ -483,7 +556,7 @@ int Character::vitamin_get( const vitamin_id &vit ) const return v != vitamin_levels.end() ? v->second : 0; } -bool player::vitamin_set( const vitamin_id &vit, int qty ) +bool Character::vitamin_set( const vitamin_id &vit, int qty ) { auto v = vitamin_levels.find( vit ); if( v == vitamin_levels.end() ) { @@ -525,16 +598,16 @@ float Character::metabolic_rate() const return modifier * metabolic_rate_base(); } -morale_type player::allergy_type( const item &food ) const +morale_type Character::allergy_type( const item &food ) const { using allergy_tuple = std::tuple; static const std::array allergy_tuples = {{ - std::make_tuple( trait_id( "VEGETARIAN" ), "ALLERGEN_MEAT", MORALE_VEGETARIAN ), - std::make_tuple( trait_id( "MEATARIAN" ), "ALLERGEN_VEGGY", MORALE_MEATARIAN ), - std::make_tuple( trait_id( "LACTOSE" ), "ALLERGEN_MILK", MORALE_LACTOSE ), - std::make_tuple( trait_id( "ANTIFRUIT" ), "ALLERGEN_FRUIT", MORALE_ANTIFRUIT ), - std::make_tuple( trait_id( "ANTIJUNK" ), "ALLERGEN_JUNK", MORALE_ANTIJUNK ), - std::make_tuple( trait_id( "ANTIWHEAT" ), "ALLERGEN_WHEAT", MORALE_ANTIWHEAT ) + std::make_tuple( trait_VEGETARIAN, flag_ALLERGEN_MEAT, MORALE_VEGETARIAN ), + std::make_tuple( trait_MEATARIAN, flag_ALLERGEN_VEGGY, MORALE_MEATARIAN ), + std::make_tuple( trait_LACTOSE, flag_ALLERGEN_MILK, MORALE_LACTOSE ), + std::make_tuple( trait_ANTIFRUIT, flag_ALLERGEN_FRUIT, MORALE_ANTIFRUIT ), + std::make_tuple( trait_ANTIJUNK, flag_ALLERGEN_JUNK, MORALE_ANTIJUNK ), + std::make_tuple( trait_ANTIWHEAT, flag_ALLERGEN_WHEAT, MORALE_ANTIWHEAT ) } }; @@ -548,7 +621,7 @@ morale_type player::allergy_type( const item &food ) const return MORALE_NULL; } -ret_val player::can_eat( const item &food ) const +ret_val Character::can_eat( const item &food ) const { const auto &comest = food.get_comestible(); @@ -556,11 +629,11 @@ ret_val player::can_eat( const item &food ) const return ret_val::make_failure( _( "That doesn't look edible." ) ); } - if( food.has_flag( "INEDIBLE" ) ) { - if( ( food.has_flag( "CATTLE" ) && !has_trait( trait_id( "THRESH_CATTLE" ) ) ) || - ( food.has_flag( "FELINE" ) && !has_trait( trait_id( "THRESH_FELINE" ) ) ) || - ( food.has_flag( "LUPINE" ) && !has_trait( trait_id( "THRESH_LUPINE" ) ) ) || - ( food.has_flag( "BIRD" ) && !has_trait( trait_id( "THRESH_BIRD" ) ) ) ) { + if( food.has_flag( flag_INEDIBLE ) ) { + if( ( food.has_flag( flag_CATTLE ) && !has_trait( trait_THRESH_CATTLE ) ) || + ( food.has_flag( flag_FELINE ) && !has_trait( trait_THRESH_FELINE ) ) || + ( food.has_flag( flag_LUPINE ) && !has_trait( trait_THRESH_LUPINE ) ) || + ( food.has_flag( flag_BIRD ) && !has_trait( trait_THRESH_BIRD ) ) ) { return ret_val::make_failure( _( "That doesn't look edible to you." ) ); } } @@ -574,13 +647,13 @@ ret_val player::can_eat( const item &food ) const _( "This is full of dirt after being on the ground." ) ); } - const bool eat_verb = food.has_flag( "USE_EAT_VERB" ); - const bool edible = eat_verb || comest->comesttype == "FOOD"; - const bool drinkable = !eat_verb && comest->comesttype == "DRINK"; + const bool eat_verb = food.has_flag( flag_USE_EAT_VERB ); + const bool edible = eat_verb || comest->comesttype == comesttype_FOOD; + const bool drinkable = !eat_verb && comest->comesttype == comesttype_DRINK; // TODO: This condition occurs way too often. Unify it. // update Sep. 26 2018: this apparently still occurs way too often. yay! - if( is_underwater() && !has_trait( trait_id( "WATERSLEEP" ) ) ) { + if( is_underwater() && !has_trait( trait_WATERSLEEP ) ) { return ret_val::make_failure( _( "You can't do that while underwater." ) ); } @@ -591,8 +664,8 @@ ret_val player::can_eat( const item &food ) const } } } - if( food.item_tags.count( "FROZEN" ) && !food.has_flag( "EDIBLE_FROZEN" ) && - !food.has_flag( "MELTS" ) ) { + if( food.item_tags.count( flag_FROZEN ) && !food.has_flag( flag_EDIBLE_FROZEN ) && + !food.has_flag( flag_MELTS ) ) { if( edible ) { return ret_val::make_failure( _( "It's frozen solid. You must defrost it before you can eat it." ) ); @@ -614,22 +687,22 @@ ret_val player::can_eat( const item &food ) const } // For all those folks who loved eating marloss berries. D:< mwuhahaha - if( has_trait( trait_id( "M_DEPENDENT" ) ) && !food.has_flag( "MYCUS_OK" ) ) { + if( has_trait( trait_M_DEPENDENT ) && !food.has_flag( flag_MYCUS_OK ) ) { return ret_val::make_failure( INEDIBLE_MUTATION, _( "We can't eat that. It's not right for us." ) ); } // Here's why PROBOSCIS is such a negative trait. - if( has_trait( trait_id( "PROBOSCIS" ) ) && !( drinkable || food.is_medication() ) ) { + if( has_trait( trait_PROBOSCIS ) && !( drinkable || food.is_medication() ) ) { return ret_val::make_failure( INEDIBLE_MUTATION, _( "Ugh, you can't drink that!" ) ); } - if( has_trait( trait_id( "CARNIVORE" ) ) && nutrition_for( food ) > 0 && - food.has_any_flag( carnivore_blacklist ) && !food.has_flag( "CARNIVORE_OK" ) ) { + if( has_trait( trait_CARNIVORE ) && nutrition_for( food ) > 0 && + food.has_any_flag( carnivore_blacklist ) && !food.has_flag( flag_CARNIVORE_OK ) ) { return ret_val::make_failure( INEDIBLE_MUTATION, _( "Eww. Inedible plant stuff!" ) ); } - if( ( has_trait( trait_id( "HERBIVORE" ) ) || has_trait( trait_id( "RUMINANT" ) ) ) && + if( ( has_trait( trait_HERBIVORE ) || has_trait( trait_RUMINANT ) ) && food.has_any_flag( herbivore_blacklist ) ) { // Like non-cannibal, but more strict! return ret_val::make_failure( INEDIBLE_MUTATION, @@ -645,7 +718,7 @@ ret_val player::can_eat( const item &food ) const return ret_val::make_success(); } -ret_val player::will_eat( const item &food, bool interactive ) const +ret_val Character::will_eat( const item &food, bool interactive ) const { const auto ret = can_eat( food ); if( !ret.success() ) { @@ -660,33 +733,33 @@ ret_val player::will_eat( const item &food, bool interactive ) co consequences.emplace_back( ret_val::make_failure( code, msg ) ); }; - const bool saprophage = has_trait( trait_id( "SAPROPHAGE" ) ); + const bool saprophage = has_trait( trait_SAPROPHAGE ); const auto &comest = food.get_comestible(); if( food.rotten() ) { - const bool saprovore = has_trait( trait_id( "SAPROVORE" ) ); + const bool saprovore = has_trait( trait_SAPROVORE ); if( !saprophage && !saprovore ) { add_consequence( _( "This is rotten and smells awful!" ), ROTTEN ); } } - const bool carnivore = has_trait( trait_id( "CARNIVORE" ) ); - if( food.has_flag( "CANNIBALISM" ) && !has_trait_flag( "CANNIBAL" ) ) { + const bool carnivore = has_trait( trait_CARNIVORE ); + if( food.has_flag( flag_CANNIBALISM ) && !has_trait_flag( "CANNIBAL" ) ) { add_consequence( _( "The thought of eating human flesh makes you feel sick." ), CANNIBALISM ); } - const bool edible = comest->comesttype == "FOOD" || food.has_flag( "USE_EAT_VERB" ); + const bool edible = comest->comesttype == comesttype_FOOD || food.has_flag( flag_USE_EAT_VERB ); if( edible && has_effect( effect_nausea ) ) { add_consequence( _( "You still feel nauseous and will probably puke it all up again." ), NAUSEA ); } - if( ( allergy_type( food ) != MORALE_NULL ) || ( carnivore && food.has_flag( "ALLERGEN_JUNK" ) && - !food.has_flag( "CARNIVORE_OK" ) ) ) { + if( ( allergy_type( food ) != MORALE_NULL ) || ( carnivore && food.has_flag( flag_ALLERGEN_JUNK ) && + !food.has_flag( flag_CARNIVORE_OK ) ) ) { add_consequence( _( "Your stomach won't be happy (allergy)." ), ALLERGY ); } - if( saprophage && edible && food.rotten() && !food.has_flag( "FERTILIZER" ) ) { + if( saprophage && edible && food.rotten() && !food.has_flag( flag_FERTILIZER ) ) { // Note: We're allowing all non-solid "food". This includes drugs // Hard-coding fertilizer for now - should be a separate flag later //~ No, we don't eat "rotten" food. We eat properly aged food, like a normal person. @@ -712,12 +785,12 @@ ret_val player::will_eat( const item &food, bool interactive ) co req += elem.str() + "\n"; } - const bool eat_verb = food.has_flag( "USE_EAT_VERB" ); + const bool eat_verb = food.has_flag( flag_USE_EAT_VERB ); std::string food_tame = food.tname(); const nc_color food_color = food.color_in_inventory(); - if( eat_verb || comest->comesttype == "FOOD" ) { + if( eat_verb || comest->comesttype == comesttype_FOOD ) { req += string_format( _( "Eat your %s anyway?" ), colorize( food_tame, food_color ) ); - } else if( !eat_verb && comest->comesttype == "DRINK" ) { + } else if( !eat_verb && comest->comesttype == comesttype_DRINK ) { req += string_format( _( "Drink your %s anyway?" ), colorize( food_tame, food_color ) ); } else { req += string_format( _( "Consume your %s anyway?" ), colorize( food_tame, food_color ) ); @@ -758,15 +831,16 @@ bool player::eat( item &food, bool force ) // Note: the block below assumes we decided to eat it // No coming back from here - const bool hibernate = has_active_mutation( trait_id( "HIBERNATE" ) ); + const bool hibernate = has_active_mutation( trait_HIBERNATE ); const int nutr = nutrition_for( food ); const int quench = food.get_comestible()->quench; const bool spoiled = food.rotten(); // The item is solid food - const bool chew = food.get_comestible()->comesttype == "FOOD" || food.has_flag( "USE_EAT_VERB" ); + const bool chew = food.get_comestible()->comesttype == comesttype_FOOD || + food.has_flag( flag_USE_EAT_VERB ); // This item is a drink and not a solid food (and not a thick soup) - const bool drinkable = !chew && food.get_comestible()->comesttype == "DRINK"; + const bool drinkable = !chew && food.get_comestible()->comesttype == comesttype_DRINK; // If neither of the above is true then it's a drug and shouldn't get mealtime penalty/bonus if( hibernate && @@ -780,10 +854,10 @@ bool player::eat( item &food, bool force ) rng( units::to_milliliter( stomach.capacity( *this ) ) / 2, units::to_milliliter( stomach.contains() ) ) > units::to_milliliter( stomach.capacity( *this ) ); - const bool saprophage = has_trait( trait_id( "SAPROPHAGE" ) ); + const bool saprophage = has_trait( trait_SAPROPHAGE ); if( spoiled && !saprophage ) { add_msg_if_player( m_bad, _( "Ick, this %s doesn't taste so good…" ), food.tname() ); - if( !has_trait( trait_id( "SAPROVORE" ) ) && !has_trait( trait_id( "EATDEAD" ) ) && + if( !has_trait( trait_SAPROVORE ) && !has_trait( trait_EATDEAD ) && ( !has_bionic( bio_digestion ) || one_in( 3 ) ) ) { add_effect( effect_foodpoison, rng( 6_minutes, ( nutr + 1 ) * 6_minutes ) ); } @@ -799,26 +873,26 @@ bool player::eat( item &food, bool force ) } food.mod_charges( -1 ); - const bool amorphous = has_trait( trait_id( "AMORPHOUS" ) ); + const bool amorphous = has_trait( trait_AMORPHOUS ); int mealtime = 250; if( drinkable || chew ) { // Those bonuses/penalties only apply to food // Not to smoking weed or applying bandages! - if( has_trait( trait_id( "MOUTH_TENTACLES" ) ) || has_trait( trait_id( "MANDIBLES" ) ) || - has_trait( trait_id( "FANGS_SPIDER" ) ) ) { + if( has_trait( trait_MOUTH_TENTACLES ) || has_trait( trait_MANDIBLES ) || + has_trait( trait_FANGS_SPIDER ) ) { mealtime /= 2; - } else if( has_trait( trait_id( "SHARKTEETH" ) ) ) { + } else if( has_trait( trait_SHARKTEETH ) ) { // SHARKBAIT! HOO HA HA! mealtime /= 3; - } else if( has_trait( trait_id( "GOURMAND" ) ) ) { + } else if( has_trait( trait_GOURMAND ) ) { // Don't stack those two - that would be 25 moves per item mealtime -= 100; } - if( has_trait( trait_id( "BEAK_HUM" ) ) && !drinkable ) { + if( has_trait( trait_BEAK_HUM ) && !drinkable ) { // Much better than PROBOSCIS but still optimized for fluids mealtime += 200; - } else if( has_trait( trait_id( "SABER_TEETH" ) ) ) { + } else if( has_trait( trait_SABER_TEETH ) ) { // They get In The Way mealtime += 250; } @@ -834,8 +908,8 @@ bool player::eat( item &food, bool force ) // If it's poisonous... poison us. // TODO: Move this to a flag - if( food.poison > 0 && !has_trait( trait_id( "EATPOISON" ) ) && - !has_trait( trait_id( "EATDEAD" ) ) ) { + if( food.poison > 0 && !has_trait( trait_EATPOISON ) && + !has_trait( trait_EATDEAD ) ) { if( food.poison >= rng( 2, 4 ) ) { add_effect( effect_poison, food.poison * 10_minutes ); } @@ -843,8 +917,8 @@ bool player::eat( item &food, bool force ) add_effect( effect_foodpoison, food.poison * 30_minutes ); } - const bool spiritual = has_trait( trait_id( "SPIRITUAL" ) ); - if( food.has_flag( "HIDDEN_HALLU" ) ) { + const bool spiritual = has_trait( trait_SPIRITUAL ); + if( food.has_flag( flag_HIDDEN_HALLU ) ) { if( spiritual ) { add_morale( MORALE_FOOD_GOOD, 36, 72, 2_hours, 1_hours, false ); } else { @@ -859,7 +933,7 @@ bool player::eat( item &food, bool force ) add_msg_player_or_npc( _( "You assimilate your %s." ), _( " assimilates a %s." ), food.tname() ); } else if( drinkable ) { - if( ( has_trait( trait_id( "SCHIZOPHRENIC" ) ) || has_artifact_with( AEP_SCHIZO ) ) && + if( ( has_trait( trait_SCHIZOPHRENIC ) || has_artifact_with( AEP_SCHIZO ) ) && one_in( 50 ) && !spoiled && food.goes_bad() && is_player() ) { add_msg( m_bad, _( "Ick, this %s (rotten) doesn't taste so good…" ), food.tname() ); @@ -869,7 +943,7 @@ bool player::eat( item &food, bool force ) food.tname() ); } } else if( chew ) { - if( ( has_trait( trait_id( "SCHIZOPHRENIC" ) ) || has_artifact_with( AEP_SCHIZO ) ) && + if( ( has_trait( trait_SCHIZOPHRENIC ) || has_artifact_with( AEP_SCHIZO ) ) && one_in( 50 ) && !spoiled && food.goes_bad() && is_player() ) { add_msg( m_bad, _( "Ick, this %s (rotten) doesn't taste so good…" ), food.tname() ); @@ -877,7 +951,7 @@ bool player::eat( item &food, bool force ) } else { add_msg_player_or_npc( _( "You eat your %s." ), _( " eats a %s." ), food.tname() ); - if( !spoiled && !food.has_flag( "ALLERGEN_JUNK" ) ) { + if( !spoiled && !food.has_flag( flag_ALLERGEN_JUNK ) ) { bool has_table_nearby = false; bool has_chair_nearby = false; for( const tripoint &pt : g->m.points_in_radius( pos(), 1 ) ) { @@ -892,14 +966,14 @@ bool player::eat( item &food, bool force ) } } if( has_chair_nearby && has_table_nearby ) { - if( has_trait( trait_id( "TABLEMANNERS" ) ) ) { + if( has_trait( trait_TABLEMANNERS ) ) { rem_morale( MORALE_ATE_WITHOUT_TABLE ); add_morale( MORALE_ATE_WITH_TABLE, 3, 3, 3_hours, 2_hours, true ); } else { add_morale( MORALE_ATE_WITH_TABLE, 1, 1, 3_hours, 2_hours, true ); } } else { - if( has_trait( trait_id( "TABLEMANNERS" ) ) ) { + if( has_trait( trait_TABLEMANNERS ) ) { rem_morale( MORALE_ATE_WITH_TABLE ); add_morale( MORALE_ATE_WITHOUT_TABLE, -2, -4, 3_hours, 2_hours, true ); } @@ -917,13 +991,13 @@ bool player::eat( item &food, bool force ) mod_power_level( units::from_kilojoule( -abs( food.get_comestible_fun() ) ) ); } - if( food.has_flag( "CANNIBALISM" ) ) { + if( food.has_flag( flag_CANNIBALISM ) ) { // Sapiovores don't recognize humans as the same species. // But let them possibly feel cool about eating sapient stuff - treat like psycho // However, spiritual sapiovores should still recognize humans as having a soul or special for religious reasons - const bool cannibal = has_trait( trait_id( "CANNIBAL" ) ); - const bool psycho = has_trait( trait_id( "PSYCHOPATH" ) ); - const bool sapiovore = has_trait( trait_id( "SAPIOVORE" ) ); + const bool cannibal = has_trait( trait_CANNIBAL ); + const bool psycho = has_trait( trait_PSYCHOPATH ); + const bool sapiovore = has_trait( trait_SAPIOVORE ); if( ( cannibal || sapiovore ) && psycho && spiritual ) { add_msg_if_player( m_good, _( "You feast upon the human flesh, and in doing so, devour their spirit." ) ); @@ -955,12 +1029,12 @@ bool player::eat( item &food, bool force ) } } - if( food.has_flag( "FUNGAL_VECTOR" ) && !has_trait( trait_id( "M_IMMUNE" ) ) ) { + if( food.has_flag( flag_FUNGAL_VECTOR ) && !has_trait( trait_M_IMMUNE ) ) { add_effect( effect_fungus, 1_turns, num_bp, true ); } // The fun changes for these effects are applied in fun_for(). - if( food.has_flag( "MUSHY" ) ) { + if( food.has_flag( flag_MUSHY ) ) { add_msg_if_player( m_bad, _( "You try to ignore its mushy texture, but it leaves you with an awful aftertaste." ) ); } @@ -979,12 +1053,12 @@ bool player::eat( item &food, bool force ) add_msg_if_player( m_bad, _( "Yuck! How can anybody eat this stuff?" ) ); add_morale( allergy, -75, -400, 30_minutes, 24_minutes ); } - if( food.has_flag( "ALLERGEN_JUNK" ) ) { - if( has_trait( trait_id( "PROJUNK" ) ) ) { + if( food.has_flag( flag_ALLERGEN_JUNK ) ) { + if( has_trait( trait_PROJUNK ) ) { add_msg_if_player( m_good, _( "Mmm, junk food." ) ); add_morale( MORALE_SWEETTOOTH, 5, 30, 30_minutes, 24_minutes ); } - if( has_trait( trait_id( "PROJUNK2" ) ) ) { + if( has_trait( trait_PROJUNK2 ) ) { if( !one_in( 100 ) ) { add_msg_if_player( m_good, _( "When life's got you down, there's always sugar." ) ); } else { @@ -995,21 +1069,21 @@ bool player::eat( item &food, bool force ) } // Carnivores CAN eat junk food, but they won't like it much. // Pizza-scraping happens in consume_effects. - if( has_trait( trait_id( "CARNIVORE" ) ) && food.has_flag( "ALLERGEN_JUNK" ) && - !food.has_flag( "CARNIVORE_OK" ) ) { + if( has_trait( trait_CARNIVORE ) && food.has_flag( flag_ALLERGEN_JUNK ) && + !food.has_flag( flag_CARNIVORE_OK ) ) { add_msg_if_player( m_bad, _( "Your stomach begins gurgling and you feel bloated and ill." ) ); add_morale( MORALE_NO_DIGEST, -25, -125, 30_minutes, 24_minutes ); } - if( !spoiled && chew && has_trait( trait_id( "SAPROPHAGE" ) ) ) { + if( !spoiled && chew && has_trait( trait_SAPROPHAGE ) ) { // It's OK to *drink* things that haven't rotted. Alternative is to ban water. D: add_msg_if_player( m_bad, _( "Your stomach begins gurgling and you feel bloated and ill." ) ); add_morale( MORALE_NO_DIGEST, -75, -400, 30_minutes, 24_minutes ); } - if( food.has_flag( "URSINE_HONEY" ) && ( !crossed_threshold() || - has_trait( trait_id( "THRESH_URSINE" ) ) ) && + if( food.has_flag( flag_URSINE_HONEY ) && ( !crossed_threshold() || + has_trait( trait_THRESH_URSINE ) ) && mutation_category_level["URSINE"] > 40 ) { // Need at least 5 bear mutations for effect to show, to filter out mutations in common with other categories - int honey_fun = has_trait( trait_id( "THRESH_URSINE" ) ) ? + int honey_fun = has_trait( trait_THRESH_URSINE ) ? std::min( mutation_category_level["URSINE"] / 8, 20 ) : mutation_category_level["URSINE"] / 12; if( honey_fun < 10 ) { @@ -1021,17 +1095,17 @@ bool player::eat( item &food, bool force ) } // Chance to become parasitised - if( !will_vomit && !( has_bionic( bio_digestion ) || has_trait( trait_id( "PARAIMMUNE" ) ) ) ) { - if( food.get_comestible()->parasites > 0 && !food.has_flag( "NO_PARASITES" ) && + if( !will_vomit && !( has_bionic( bio_digestion ) || has_trait( trait_PARAIMMUNE ) ) ) { + if( food.get_comestible()->parasites > 0 && !food.has_flag( flag_NO_PARASITES ) && one_in( food.get_comestible()->parasites ) ) { switch( rng( 0, 3 ) ) { case 0: - if( !has_trait( trait_id( "EATHEALTH" ) ) ) { + if( !has_trait( trait_EATHEALTH ) ) { add_effect( effect_tapeworm, 1_turns, num_bp, true ); } break; case 1: - if( !has_trait( trait_id( "ACIDBLOOD" ) ) ) { + if( !has_trait( trait_ACIDBLOOD ) ) { add_effect( effect_bloodworms, 1_turns, num_bp, true ); } break; @@ -1065,7 +1139,7 @@ bool player::eat( item &food, bool force ) return true; } -void player::modify_health( const islot_comestible &comest ) +void Character::modify_health( const islot_comestible &comest ) { const int effective_health = comest.healthy; // Effectively no cap on health modifiers from food and meds @@ -1073,7 +1147,7 @@ void player::modify_health( const islot_comestible &comest ) mod_healthy_mod( effective_health, effective_health >= 0 ? health_cap : -health_cap ); } -void player::modify_stimulation( const islot_comestible &comest ) +void Character::modify_stimulation( const islot_comestible &comest ) { const int current_stim = get_stim(); if( comest.stim != 0 && @@ -1085,7 +1159,7 @@ void player::modify_stimulation( const islot_comestible &comest ) set_stim( std::min( comest.stim * 3, current_stim + comest.stim ) ); } } - if( has_trait( trait_id( "STIMBOOST" ) ) && ( current_stim > 30 ) && + if( has_trait( trait_STIMBOOST ) && ( current_stim > 30 ) && ( ( comest.add == ADD_CAFFEINE ) || ( comest.add == ADD_SPEED ) || ( comest.add == ADD_COKE ) || ( comest.add == ADD_CRACK ) ) ) { int hallu_duration = ( current_stim - comest.stim < 30 ) ? current_stim - 30 : comest.stim; @@ -1108,7 +1182,7 @@ void player::modify_stimulation( const islot_comestible &comest ) } } -void player::modify_addiction( const islot_comestible &comest ) +void Character::modify_addiction( const islot_comestible &comest ) { add_addiction( comest.add, comest.addict ); if( addiction_craving( comest.add ) != MORALE_NULL ) { @@ -1119,7 +1193,7 @@ void player::modify_addiction( const islot_comestible &comest ) void Character::modify_morale( item &food, const int nutr ) { time_duration morale_time = 2_hours; - if( food.has_flag( "HOT" ) && food.has_flag( "EATEN_HOT" ) ) { + if( food.has_flag( flag_HOT ) && food.has_flag( flag_EATEN_HOT ) ) { morale_time = 3_hours; int clamped_nutr = std::max( 5, std::min( 20, nutr / 10 ) ); add_morale( MORALE_FOOD_HOT, clamped_nutr, 20, morale_time, morale_time / 2 ); @@ -1135,18 +1209,18 @@ void Character::modify_morale( item &food, const int nutr ) } } -bool player::consume_effects( item &food ) +bool Character::consume_effects( item &food ) { if( !food.is_comestible() ) { - debugmsg( "called player::consume_effects with non-comestible" ); + debugmsg( "called Character::consume_effects with non-comestible" ); return false; } - if( has_trait( trait_id( "THRESH_PLANT" ) ) && food.type->can_use( "PLANTBLECH" ) ) { + if( has_trait( trait_THRESH_PLANT ) && food.type->can_use( "PLANTBLECH" ) ) { // Was used to cap nutrition and thirst, but no longer does this return false; } - if( ( has_trait( trait_id( "HERBIVORE" ) ) || has_trait( trait_id( "RUMINANT" ) ) ) && + if( ( has_trait( trait_HERBIVORE ) || has_trait( trait_RUMINANT ) ) && food.has_any_flag( herbivore_blacklist ) ) { // No good can come of this. return false; @@ -1156,8 +1230,8 @@ bool player::consume_effects( item &food ) // Rotten food causes health loss const float relative_rot = food.get_relative_rot(); - if( relative_rot > 1.0f && !has_trait( trait_id( "SAPROPHAGE" ) ) && - !has_trait( trait_id( "SAPROVORE" ) ) && !has_bionic( bio_digestion ) ) { + if( relative_rot > 1.0f && !has_trait( trait_SAPROPHAGE ) && + !has_trait( trait_SAPROVORE ) && !has_bionic( bio_digestion ) ) { const float rottedness = clamp( 2 * relative_rot - 2.0f, 0.1f, 1.0f ); // ~-1 health per 1 nutrition at halfway-rotten-away, ~0 at "just got rotten" // But always round down @@ -1168,7 +1242,7 @@ bool player::consume_effects( item &food ) // Used in hibernation messages. const auto nutr = nutrition_for( food ); - const bool skip_health = has_trait( trait_id( "PROJUNK2" ) ) && comest.healthy < 0; + const bool skip_health = has_trait( trait_PROJUNK2 ) && comest.healthy < 0; // We can handle junk just fine if( !skip_health ) { modify_health( comest ); @@ -1177,7 +1251,7 @@ bool player::consume_effects( item &food ) modify_addiction( comest ); modify_morale( food, nutr ); - const bool hibernate = has_active_mutation( trait_id( "HIBERNATE" ) ); + const bool hibernate = has_active_mutation( trait_HIBERNATE ); if( hibernate ) { if( ( nutr > 0 && get_hunger() < -60 ) || ( comest.quench > 0 && get_thirst() < -60 ) ) { // Tell the player what's going on @@ -1214,7 +1288,7 @@ bool player::consume_effects( item &food ) int capacity = stomach_capacity(); // Moved here and changed a bit - it was too complex // Incredibly minor stuff like this shouldn't require complexity - if( !is_npc() && has_trait( trait_id( "SLIMESPAWNER" ) ) && + if( !is_npc() && has_trait( trait_SLIMESPAWNER ) && ( get_healthy_kcal() < get_stored_kcal() + 4000 && get_thirst() - stomach.get_water() / 5_ml < -20 ) && get_thirst() < 40 ) { add_msg_if_player( m_mixed, @@ -1234,7 +1308,7 @@ bool player::consume_effects( item &food ) } // Last thing that happens before capping hunger - if( get_hunger() < capacity && has_trait( trait_id( "EATHEALTH" ) ) ) { + if( get_hunger() < capacity && has_trait( trait_EATHEALTH ) ) { int excess_food = capacity - get_hunger(); add_msg_player_or_npc( _( "You feel the %s filling you out." ), _( " looks better after eating the %s." ), @@ -1261,7 +1335,7 @@ bool player::consume_effects( item &food ) compute_effective_nutrients( contained_food ) }; // Maybe move tapeworm to digestion - if( has_effect( efftype_id( "tapeworm" ) ) ) { + if( has_effect( effect_tapeworm ) ) { ingested.nutr /= 2; } @@ -1270,7 +1344,7 @@ bool player::consume_effects( item &food ) return true; } -hint_rating player::rate_action_eat( const item &it ) const +hint_rating Character::rate_action_eat( const item &it ) const { if( !can_consume( it ) ) { return HINT_CANT; @@ -1286,7 +1360,7 @@ hint_rating player::rate_action_eat( const item &it ) const return HINT_IFFY; } -bool player::can_feed_reactor_with( const item &it ) const +bool Character::can_feed_reactor_with( const item &it ) const { static const std::set acceptable = {{ ammotype( "reactor_slurry" ), @@ -1307,7 +1381,7 @@ bool player::can_feed_reactor_with( const item &it ) const } ); } -bool player::feed_reactor_with( item &it ) +bool Character::feed_reactor_with( item &it ) { if( !can_feed_reactor_with( it ) ) { return false; @@ -1333,9 +1407,9 @@ bool player::feed_reactor_with( item &it ) return true; } -bool player::can_feed_furnace_with( const item &it ) const +bool Character::can_feed_furnace_with( const item &it ) const { - if( !it.flammable() || it.has_flag( "RADIOACTIVE" ) || can_eat( it ).success() ) { + if( !it.flammable() || it.has_flag( flag_RADIOACTIVE ) || can_eat( it ).success() ) { return false; } @@ -1348,10 +1422,10 @@ bool player::can_feed_furnace_with( const item &it ) const return false; } - return !it.has_flag( "CORPSE" ); + return !it.has_flag( flag_CORPSE ); } -bool player::feed_furnace_with( item &it ) +bool Character::feed_furnace_with( item &it ) { if( !can_feed_furnace_with( it ) ) { return false; @@ -1409,7 +1483,7 @@ bool player::feed_furnace_with( item &it ) return true; } -bool player::fuel_bionic_with( item &it ) +bool Character::fuel_bionic_with( item &it ) { if( !can_fuel_bionic_with( it ) ) { return false; @@ -1441,7 +1515,7 @@ bool player::fuel_bionic_with( item &it ) return true; } -rechargeable_cbm player::get_cbm_rechargeable_with( const item &it ) const +rechargeable_cbm Character::get_cbm_rechargeable_with( const item &it ) const { if( can_feed_reactor_with( it ) ) { return rechargeable_cbm::reactor; @@ -1458,7 +1532,7 @@ rechargeable_cbm player::get_cbm_rechargeable_with( const item &it ) const return rechargeable_cbm::none; } -int player::get_acquirable_energy( const item &it, rechargeable_cbm cbm ) const +int Character::get_acquirable_energy( const item &it, rechargeable_cbm cbm ) const { switch( cbm ) { case rechargeable_cbm::none: @@ -1504,32 +1578,32 @@ int player::get_acquirable_energy( const item &it, rechargeable_cbm cbm ) const return 0; } -int player::get_acquirable_energy( const item &it ) const +int Character::get_acquirable_energy( const item &it ) const { return get_acquirable_energy( it, get_cbm_rechargeable_with( it ) ); } -bool player::can_estimate_rot() const +bool Character::can_estimate_rot() const { return get_skill_level( skill_cooking ) >= 3 || get_skill_level( skill_survival ) >= 4; } -bool player::can_consume_as_is( const item &it ) const +bool Character::can_consume_as_is( const item &it ) const { return it.is_comestible() || get_cbm_rechargeable_with( it ) != rechargeable_cbm::none; } -bool player::can_consume( const item &it ) const +bool Character::can_consume( const item &it ) const { if( can_consume_as_is( it ) ) { return true; } // Checking NO_RELOAD to prevent consumption of `battery` when contained in `battery_car` (#20012) - return !it.is_container_empty() && !it.has_flag( "NO_RELOAD" ) && + return !it.is_container_empty() && !it.has_flag( flag_NO_RELOAD ) && can_consume_as_is( it.contents.front() ); } -item &player::get_consumable_from( item &it ) const +item &Character::get_consumable_from( item &it ) const { if( !it.is_container_empty() && can_consume_as_is( it.contents.front() ) ) { return it.contents.front(); diff --git a/src/player.h b/src/player.h index 89de95852fe12..d4af1c29ff27e 100644 --- a/src/player.h +++ b/src/player.h @@ -80,31 +80,6 @@ class vehicle; struct w_point; struct targeting_data; -// This tries to represent both rating and -// player's decision to respect said rating -enum edible_rating { - // Edible or we pretend it is - EDIBLE, - // Not food at all - INEDIBLE, - // Not food because mutated mouth/system - INEDIBLE_MUTATION, - // You can eat it, but it will hurt morale - ALLERGY, - // Smaller allergy penalty - ALLERGY_WEAK, - // Cannibalism (unless psycho/cannibal) - CANNIBALISM, - // Rotten or not rotten enough (for saprophages) - ROTTEN, - // Can provoke vomiting if you already feel nauseous. - NAUSEA, - // We can eat this, but we'll overeat - TOO_FULL, - // Some weird stuff that requires a tool we don't have - NO_TOOL -}; - /** @relates ret_val */ template<> struct ret_val::default_success : public @@ -115,13 +90,6 @@ template<> struct ret_val::default_failure : public std::integral_constant {}; -enum class rechargeable_cbm { - none = 0, - reactor, - furnace, - other -}; - enum class comfort_level { impossible = -999, uncomfortable = -7, @@ -372,7 +340,6 @@ class player : public Character bool can_grab_break( const item &weap ) const; /** Returns true if the player is able to use a miss recovery technique */ bool can_miss_recovery( const item &weap ) const; - // melee.cpp /** Returns the best item for blocking with */ item &best_shield(); @@ -570,85 +537,21 @@ class player : public Character /** used for drinking from hands, returns how many charges were consumed */ int drink_from_hands( item &water ); - /** Check whether player can consume this very item */ - bool can_consume_as_is( const item &it ) const; /** Used for eating object at pos, returns true if object is removed from inventory (last charge was consumed) */ bool consume( item_location loc ); /** Used for eating a particular item that doesn't need to be in inventory. * Returns true if the item is to be removed (doesn't remove). */ bool consume_item( item &target ); - /** Returns allergy type or MORALE_NULL if not allergic for this player */ - morale_type allergy_type( const item &food ) const; + /** Used for eating entered comestible, returns true if comestible is successfully eaten */ bool eat( item &food, bool force = false ); - /** Used to apply health modifications from food and medication **/ - void modify_health( const islot_comestible &comest ); - /** Used to apply stimulation modifications from food and medication **/ - void modify_stimulation( const islot_comestible &comest ); - /** Used to apply addiction modifications from food and medication **/ - void modify_addiction( const islot_comestible &comest ); - - /** Can the food be [theoretically] eaten no matter the consequences? */ - ret_val can_eat( const item &food ) const; - /** - * Same as @ref can_eat, but takes consequences into account. - * Asks about them if @param interactive is true, refuses otherwise. - */ - ret_val will_eat( const item &food, bool interactive = false ) const; - - // TODO: Move these methods out of the class. - rechargeable_cbm get_cbm_rechargeable_with( const item &it ) const; - int get_acquirable_energy( const item &it, rechargeable_cbm cbm ) const; - int get_acquirable_energy( const item &it ) const; - - /** Gets player's minimum hunger and thirst */ - int stomach_capacity() const; - - /** Handles the nutrition value for a comestible **/ - int nutrition_for( const item &comest ) const; /** Handles the enjoyability value for a book. **/ int book_fun_for( const item &book, const player &p ) const; - /** - * Returns a reference to the item itself (if it's consumable), - * the first of its contents (if it's consumable) or null item otherwise. - * WARNING: consumable does not necessarily guarantee the comestible type. - */ - item &get_consumable_from( item &it ) const; std::pair get_hunger_description() const override; std::pair get_pain_description() const override; - /** Get calorie & vitamin contents for a comestible, taking into - * account player traits */ - nutrients compute_effective_nutrients( const item & ) const; - /** Get range of possible nutrient content, for a particular recipe, - * depending on choice of ingredients */ - std::pair compute_nutrient_range( - const item &, const recipe_id &, - const cata::flat_set &extra_flags = {} ) const; - /** Same, but across arbitrary recipes */ - std::pair compute_nutrient_range( - const itype_id &, const cata::flat_set &extra_flags = {} ) const; - - /** Get vitamin usage rate (minutes per unit) accounting for bionics, mutations and effects */ - time_duration vitamin_rate( const vitamin_id &vit ) const; - - void vitamins_mod( const std::map &, bool capped = true ); - - /** - * Sets level of a vitamin or returns false if id given in vit does not exist - * - * @note status effects are still set for deficiency/excess - * - * @param[in] vit ID of vitamin to adjust quantity for - * @param[in] qty Quantity to set level to - * @returns false if given vitamin_id does not exist, otherwise true - */ - bool vitamin_set( const vitamin_id &vit, int qty ); - - /** Handles the effects of consuming an item */ - bool consume_effects( item &food ); int get_lift_assist() const; bool list_ammo( const item &base, std::vector &ammo_list, @@ -693,11 +596,6 @@ class player : public Character * @param it Thing to be wielded */ ret_val can_wield( const item &it ) const; - /** Check player's capability of consumption overall */ - bool can_consume( const item &it ) const; - - /** True if the player has enough skill (in cooking or survival) to estimate time to rot */ - bool can_estimate_rot() const; bool unwield(); @@ -812,7 +710,6 @@ class player : public Character * rates usability lower for non-tools (books, etc.) */ hint_rating rate_action_use( const item &it ) const; hint_rating rate_action_wear( const item &it ) const; - hint_rating rate_action_eat( const item &it ) const; hint_rating rate_action_takeoff( const item &it ) const; hint_rating rate_action_reload( const item &it ) const; hint_rating rate_action_unload( const item &it ) const; @@ -1224,16 +1121,6 @@ class player : public Character */ bool is_visible_in_range( const Creature &critter, int range ) const; - /** Determine player's capability of recharging their CBMs. */ - bool can_feed_reactor_with( const item &it ) const; - bool can_feed_furnace_with( const item &it ) const; - /** - * Recharge CBMs whenever possible. - * @return true when recharging was successful. - */ - bool feed_reactor_with( item &it ); - bool feed_furnace_with( item &it ); - bool fuel_bionic_with( item &it ); /** * Consumes an item as medication. * @param target Item consumed. Must be a medication or a container of medication.