diff options
Diffstat (limited to 'vampirism.patch')
-rw-r--r-- | vampirism.patch | 730 |
1 files changed, 405 insertions, 325 deletions
diff --git a/vampirism.patch b/vampirism.patch index 319e1fd..4e1ce30 100644 --- a/vampirism.patch +++ b/vampirism.patch @@ -1,47 +1,54 @@ --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp -@@ -231,6 +231,7 @@ - static const species_id species_HUMAN( "HUMAN" ); - static const species_id species_ZOMBIE( "ZOMBIE" ); +@@ -190,6 +190,7 @@ + static const itype_id itype_burnt_out_bionic( "burnt_out_bionic" ); + static const itype_id itype_muscle( "muscle" ); +static const json_character_flag json_flag_VAMPIRE( "VAMPIRE" ); static const json_character_flag json_flag_CANNIBAL( "CANNIBAL" ); static const json_character_flag json_flag_PSYCHOPATH( "PSYCHOPATH" ); static const json_character_flag json_flag_SAPIOVORE( "SAPIOVORE" ); -@@ -616,7 +619,8 @@ +@@ -506,7 +507,8 @@ !corpse.in_species( species_ZOMBIE ) ); - if( is_human && !( u.has_trait_flag( json_flag_CANNIBAL ) || - u.has_trait_flag( json_flag_PSYCHOPATH ) || -- u.has_trait_flag( json_flag_SAPIOVORE ) ) ) { -+ u.has_trait_flag( json_flag_SAPIOVORE ) || -+ u.has_trait_flag( json_flag_VAMPIRE ) ) ) { + if( is_human && !( you.has_flag( json_flag_CANNIBAL ) || + you.has_flag( json_flag_PSYCHOPATH ) || +- you.has_flag( json_flag_SAPIOVORE ) ) ) { ++ you.has_flag( json_flag_SAPIOVORE ) || ++ you.has_flag( json_flag_VAMPIRE ) ) ) { - if( u.is_player() ) { + if( you.is_avatar() ) { if( query_yn( _( "Would you dare desecrate the mortal remains of a fellow human being?" ) ) ) { --- a/src/character.cpp +++ b/src/character.cpp -@@ -343,6 +343,9 @@ +@@ -441,6 +441,9 @@ static const trait_id trait_NOMAD2( "NOMAD2" ); static const trait_id trait_NOMAD3( "NOMAD3" ); static const trait_id trait_NOPAIN( "NOPAIN" ); +static const trait_id trait_PAINREC1( "PAINREC1" ); +static const trait_id trait_PAINREC2( "PAINREC2" ); +static const trait_id trait_PAINREC3( "PAINREC3" ); + static const trait_id trait_PACIFIST( "PACIFIST" ); static const trait_id trait_PADDED_FEET( "PADDED_FEET" ); - static const trait_id trait_PAWS( "PAWS" ); - static const trait_id trait_PAWS_LARGE( "PAWS_LARGE" ); -@@ -370,6 +373,9 @@ + static const trait_id trait_PAINRESIST( "PAINRESIST" ); +@@ -477,6 +480,8 @@ static const trait_id trait_TOUGH_FEET( "TOUGH_FEET" ); static const trait_id trait_TRANSPIRATION( "TRANSPIRATION" ); static const trait_id trait_URSINE_EYE( "URSINE_EYE" ); -+static const trait_id trait_VAMP_HUNGER( "VAMP_HUNGER" ); +static const trait_id trait_VAMP_SKIN( "VAMP_SKIN" ); +static const trait_id trait_VAMP_VISION( "VAMP_VISION" ); static const trait_id trait_VISCOUS( "VISCOUS" ); static const trait_id trait_WATERSLEEP( "WATERSLEEP" ); - static const trait_id trait_WEBBED( "WEBBED" ); -@@ -2095,6 +2096,9 @@ + static const trait_id trait_WEB_SPINNER( "WEB_SPINNER" ); +@@ -500,6 +505,7 @@ + case blood_type::blood_A: return "A"; + case blood_type::blood_B: return "B"; + case blood_type::blood_AB: return "AB"; ++ case blood_type::blood_V: return "V"; + // *INDENT-ON* + case blood_type::num_bt: + break; +@@ -2270,6 +2276,9 @@ if( has_trait( trait_DEBUG_NIGHTVISION ) ) { vision_mode_cache.set( DEBUG_NIGHTVISION ); } @@ -51,10 +58,10 @@ if( has_nv() ) { vision_mode_cache.set( NV_GOGGLES ); } -@@ -2168,8 +2172,10 @@ - } +@@ -2337,8 +2346,10 @@ + ( LIGHT_AMBIENT_LIT - LIGHT_AMBIENT_MINIMAL ) ); - float range = get_per() / 3.0f - eyes_encumb / 10.0f; + float range = get_per() / 3.0f; - if( vision_mode_cache[NV_GOGGLES] || vision_mode_cache[NIGHTVISION_3] || - vision_mode_cache[FULL_ELFA_VISION] || vision_mode_cache[CEPH_VISION] ) { + if( vision_mode_cache[VAMP_VISION] ) { @@ -64,7 +71,7 @@ range += 10; } else if( vision_mode_cache[NIGHTVISION_2] || vision_mode_cache[FELINE_VISION] || vision_mode_cache[URSINE_VISION] || vision_mode_cache[ELFA_VISION] ) { -@@ -5442,7 +5447,15 @@ +@@ -4274,7 +4285,15 @@ { int pain_ticks = rate_multiplier; while( get_pain() > 0 && pain_ticks-- > 0 ) { @@ -81,29 +88,12 @@ } float rest = rest_quality(); -@@ -5745,6 +5758,7 @@ - const bool npc_no_food = is_npc() && get_option<bool>( "NO_NPC_FOOD" ); - const bool foodless = debug_ls || npc_no_food; - const bool no_thirst = has_flag( json_flag_NO_THIRST ); -+ const bool vamp = has_trait( trait_VAMP_HUNGER ); - const bool mycus = has_trait( trait_M_DEPENDENT ); - const float kcal_per_time = get_bmr() / ( 12.0f * 24.0f ); - const int five_mins = ticks_between( from, to, 5_minutes ); -@@ -5821,7 +5835,7 @@ - } - // Mycus and Metabolic Rehydration makes thirst unnecessary - // since water is not limited by intake but by absorption, we can just set thirst to zero -- if( mycus || no_thirst ) { -+ if( mycus || vamp || no_thirst ) { - set_thirst( 0 ); - } - -@@ -6153,19 +6167,21 @@ +@@ -4732,19 +4751,21 @@ void Character::check_needs_extremes() { // Check if we've overdosed... in any deadly way. - if( get_stim() > 250 ) { -+ if( ( get_stim() > 250 ) && !( has_trait( trait_VAMP_SKIN ) ) ) { ++ if( ( get_stim() > 250 ) && !( has_trait( trait_VAMP_SKIN ) ) ) { add_msg_player_or_npc( m_bad, _( "You have a sudden heart attack!" ), _( "<npcname> has a sudden heart attack!" ) ); @@ -120,10 +110,10 @@ + } else if( ( has_effect( effect_jetinjector ) && + get_effect_dur( effect_jetinjector ) > 40_minutes ) && + !( has_trait( trait_VAMP_SKIN ) ) ) { - if( !( has_trait( trait_NOPAIN ) ) ) { + if( !has_trait( trait_NOPAIN ) ) { add_msg_player_or_npc( m_bad, _( "Your heart spasms painfully and stops." ), -@@ -6176,13 +6192,14 @@ +@@ -4755,13 +4776,14 @@ } get_event_bus().send<event_type::dies_from_drug_overdose>( getID(), effect_jetinjector ); set_part_hp_cur( body_part_torso, 0 ); @@ -140,7 +130,27 @@ add_msg_player_or_npc( m_bad, _( "Your breathing slows down to a stop." ), _( "<npcname>'s breathing slows down to a stop." ) ); -@@ -6447,7 +6464,7 @@ +@@ -8844,7 +8866,7 @@ + int Character::heartrate_bpm() const + { + //Dead have no heartbeat usually and no heartbeat in omnicell +- if( is_dead_state() || has_trait( trait_SLIMESPAWNER ) ) { ++ if( is_dead_state() || has_trait( trait_SLIMESPAWNER ) || has_trait( trait_VAMP_SKIN ) ) { + return 0; + } + + +--- a/src/character_body.cpp ++++ b/src/character_body.cpp +@@ -76,6 +76,7 @@ + static const trait_id trait_PYROMANIA( "PYROMANIA" ); + static const trait_id trait_SLIMY( "SLIMY" ); + static const trait_id trait_URSINE_FUR( "URSINE_FUR" ); ++static const trait_id trait_VAMP_SKIN( "VAMP_SKIN" ); + + static const vitamin_id vitamin_blood( "blood" ); + +@@ -402,7 +403,7 @@ void Character::update_bodytemp() { @@ -149,19 +159,10 @@ set_all_parts_temp_conv( BODYTEMP_NORM ); set_all_parts_temp_cur( BODYTEMP_NORM ); return; -@@ -11496,7 +11513,7 @@ - int Character::heartrate_bpm() const - { - //Dead have no heartbeat usually and no heartbeat in omnicell -- if( is_dead_state() || has_trait( trait_SLIMESPAWNER ) ) { -+ if( is_dead_state() || has_trait( trait_SLIMESPAWNER ) || has_trait( trait_VAMP_SKIN ) ) { - return 0; - } - //This function returns heartrate in BPM basing of health, physical state, tiredness, --- a/src/character.h +++ b/src/character.h -@@ -111,6 +111,7 @@ +@@ -120,6 +120,7 @@ /// @note vision modes do not necessarily match json ids or flags enum vision_modes { DEBUG_NIGHTVISION, @@ -169,11 +170,19 @@ NV_GOGGLES, NIGHTVISION_1, NIGHTVISION_2, -@@ -256,6 +256,8 @@ +@@ -241,6 +242,7 @@ + blood_A, + blood_B, + blood_AB, ++ blood_V, + num_bt + }; + +@@ -265,6 +267,8 @@ ALLERGY_WEAK, /// Penalty for eating human flesh (unless psycho/cannibal) CANNIBALISM, -+ // Vampirism (unless psycho/cannibal) ++ /// Penalty for drinking human blood (unless vampire) + VAMPIRISM, /// Comestible has parasites PARASITES, @@ -181,7 +190,25 @@ --- a/src/consumption.cpp +++ b/src/consumption.cpp -@@ -132,6 +132,7 @@ +@@ -77,11 +77,17 @@ + static const efftype_id effect_took_thorazine( "took_thorazine" ); + static const efftype_id effect_visuals( "visuals" ); + ++static const flag_id json_flag_ALLERGEN_ALCOHOL( "ALLERGEN_ALCOHOL" ); + static const flag_id json_flag_ALLERGEN_EGG( "ALLERGEN_EGG" ); ++static const flag_id json_flag_ALLERGEN_FOODSTUFF( "ALLERGEN_FOODSTUFF" ); + static const flag_id json_flag_ALLERGEN_FRUIT( "ALLERGEN_FRUIT" ); ++static const flag_id json_flag_ALLERGEN_HONEY( "ALLERGEN_HONEY" ); ++static const flag_id json_flag_ALLERGEN_JUNK( "ALLERGEN_JUNK" ); + static const flag_id json_flag_ALLERGEN_MEAT( "ALLERGEN_MEAT" ); ++static const flag_id json_flag_ALLERGEN_MILK( "ALLERGEN_MILK" ); + static const flag_id json_flag_ALLERGEN_NUT( "ALLERGEN_NUT" ); + static const flag_id json_flag_ALLERGEN_VEGGY( "ALLERGEN_VEGGY" ); ++static const flag_id json_flag_ALLERGEN_WATER( "ALLERGEN_WATER" ); + static const flag_id json_flag_ALLERGEN_WHEAT( "ALLERGEN_WHEAT" ); + + static const item_category_id item_category_chems( "chems" ); +@@ -144,6 +150,7 @@ static const trait_id trait_THRESH_LUPINE( "THRESH_LUPINE" ); static const trait_id trait_THRESH_PLANT( "THRESH_PLANT" ); static const trait_id trait_THRESH_URSINE( "THRESH_URSINE" ); @@ -189,57 +216,53 @@ static const trait_id trait_VEGETARIAN( "VEGETARIAN" ); static const trait_id trait_WATERSLEEP( "WATERSLEEP" ); -@@ -146,6 +147,15 @@ - flag_id( "ALLERGEN_MEAT" ), flag_id( "ALLERGEN_EGG" ) +@@ -154,6 +161,15 @@ + json_flag_ALLERGEN_WHEAT, json_flag_ALLERGEN_NUT }}; -+static const std::array<flag_id, 11> vamp_blacklist {{ -+ flag_id( "ALLERGEN_VEGGY" ), flag_id( "ALLERGEN_FRUIT" ), -+ flag_id( "ALLERGEN_WHEAT" ), flag_id( "ALLERGEN_NUT" ), -+ flag_id( "ALLERGEN_MEAT" ), flag_id( "ALLERGEN_EGG" ), -+ flag_id( "ALLERGEN_JUNK" ), flag_id( "ALLERGEN_MILK" ), -+ flag_id( "ALLERGEN_HONEY" ), flag_id( "ALLERGEN_FOODSTUFF" ), -+ flag_id( "ALLERGEN_ALCOHOL" ) ++static const std::array<flag_id, 12> vamp_blacklist {{ ++ json_flag_ALLERGEN_VEGGY, json_flag_ALLERGEN_FRUIT, ++ json_flag_ALLERGEN_WHEAT, json_flag_ALLERGEN_NUT, ++ json_flag_ALLERGEN_MEAT, json_flag_ALLERGEN_EGG, ++ json_flag_ALLERGEN_JUNK, json_flag_ALLERGEN_MILK, ++ json_flag_ALLERGEN_HONEY, json_flag_ALLERGEN_FOODSTUFF, ++ json_flag_ALLERGEN_ALCOHOL, json_flag_ALLERGEN_WATER + }}; + - // TODO: Move pizza scraping here. - static int compute_default_effective_kcal( const item &comest, const Character &you, - const cata::flat_set<flag_id> &extra_flags = {} ) -@@ -711,6 +721,13 @@ - return ret_val<edible_rating>::make_failure( INEDIBLE_MUTATION, _( "Ugh, you can't drink that!" ) ); + static const std::array<flag_id, 2> herbivore_blacklist {{ + json_flag_ALLERGEN_MEAT, json_flag_ALLERGEN_EGG + }}; +@@ -805,6 +821,12 @@ + _( "Eww. Inedible plant stuff!" ) ); } -+ if( has_trait_flag( STATIC( json_character_flag( "VAMPIRE" ) ) ) && -+ food.has_any_flag( vamp_blacklist ) && ++ if( has_trait( trait_VAMP_HUNGER ) && food.has_any_flag( vamp_blacklist ) && + !food.has_flag( flag_VAMPIRISM_OK ) ) { + return ret_val<edible_rating>::make_failure( INEDIBLE_MUTATION, + _( "Bleh. This isn't blood!" ) ); + } + - if( has_trait( trait_CARNIVORE ) && nutrition_for( food ) > 0 && - food.has_any_flag( carnivore_blacklist ) && !food.has_flag( flag_CARNIVORE_OK ) ) { - return ret_val<edible_rating>::make_failure( INEDIBLE_MUTATION, -@@ -763,11 +780,18 @@ + if( ( has_trait( trait_HERBIVORE ) || has_trait( trait_RUMINANT ) ) && + food.has_any_flag( herbivore_blacklist ) ) { + // Like non-cannibal, but more strict! +@@ -851,8 +873,15 @@ } } + const bool food_is_human_blood = food.has_flag( flag_VAMPIRISM ); -+ if( food_is_human_blood && !has_trait_flag( STATIC( json_character_flag( "VAMPIRE" ) ) ) && -+ !has_trait_flag( STATIC( json_character_flag( "CANNIBAL" ) ) ) ) { ++ if( food_is_human_blood && !has_flag( STATIC( json_character_flag( "VAMPIRE" ) ) ) && ++ !has_flag( STATIC( json_character_flag( "CANNIBAL" ) ) ) ) { + add_consequence( _( "The thought of drinking human blood makes you feel sick." ), VAMPIRISM ); + } + const bool carnivore = has_trait( trait_CARNIVORE ); - const bool food_is_human_flesh = food.has_flag( flag_CANNIBALISM ) || +- const bool food_is_human_flesh = food.has_flag( flag_CANNIBALISM ) || ++ const bool food_is_human_flesh = ( food.has_flag( flag_CANNIBALISM ) && ++ !food.has_flag( flag_VAMPIRISM ) ) || ( food.has_flag( flag_STRICT_HUMANITARIANISM ) && - !has_trait_flag( json_flag_STRICT_HUMANITARIAN ) ); -- if( food_is_human_flesh && !has_trait_flag( STATIC( json_character_flag( "CANNIBAL" ) ) ) ) { -+ if( food_is_human_flesh && !has_trait_flag( STATIC( json_character_flag( "CANNIBAL" ) ) ) && -+ !food.has_flag( flag_VAMPIRISM ) ) { - add_consequence( _( "The thought of eating human flesh makes you feel sick." ), CANNIBALISM ); - } - -@@ -1136,10 +1160,54 @@ + !has_flag( json_flag_STRICT_HUMANITARIAN ) ); + if( food_is_human_flesh && !has_flag( STATIC( json_character_flag( "CANNIBAL" ) ) ) ) { +@@ -1216,10 +1245,58 @@ } } @@ -253,6 +276,7 @@ + const bool psycho = has_trait( trait_PSYCHOPATH ); + const bool sapiovore = has_trait( trait_SAPIOVORE ); + const bool spiritual = has_trait( trait_SPIRITUAL ); ++ const bool numb = has_trait( trait_NUMB ); + if( vamp ) { + add_msg_if_player( m_good, _( "You relish drinking the human blood." ) ); + add_morale( MORALE_CANNIBAL, 30, 200 ); @@ -276,30 +300,33 @@ + // Small bonus for violating a taboo. + add_morale( MORALE_CANNIBAL, 5, 50 ); + } else if( psycho || sapiovore ) { -+ add_msg_if_player( _( "Meh. You've eaten worse." ) ); ++ add_msg_if_player( _( "Meh. You've drank worse." ) ); + } else if( spiritual ) { + add_msg_if_player( m_bad, + _( "This is probably going to count against you if there's still an afterlife." ) ); + add_morale( MORALE_CANNIBAL, -60, -400, 60_minutes, 30_minutes ); ++ } else if( numb ) { ++ add_msg_if_player( m_bad, _( "You find this drink distasteful, but necessary." ) ); ++ add_morale( MORALE_CANNIBAL, -60, -400, 60_minutes, 30_minutes ); + } else { -+ add_msg_if_player( m_bad, _( "You feel horrible for eating a person." ) ); ++ add_msg_if_player( m_bad, _( "You feel horrible for drinking of a person." ) ); + add_morale( MORALE_CANNIBAL, -60, -400, 60_minutes, 30_minutes ); + } + } + const bool food_is_human_flesh = food.has_flag( flag_CANNIBALISM ) || ( food.has_flag( flag_STRICT_HUMANITARIANISM ) && - !has_trait_flag( json_flag_STRICT_HUMANITARIAN ) ); + !has_flag( json_flag_STRICT_HUMANITARIAN ) ); - if( food_is_human_flesh ) { + if( food_is_human_flesh && !food_is_human_blood ) { // 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 -@@ -1214,6 +1282,11 @@ - add_msg_if_player( m_bad, _( "Yuck! How can anybody eat this stuff?" ) ); +@@ -1303,6 +1380,11 @@ + add_msg_if_player( m_bad, _( "Your stomach begins gurgling and you feel bloated and ill." ) ); add_morale( allergy, -75, -400, 30_minutes, 24_minutes ); } -+ if( allergy != MORALE_NULL && has_trait_flag( STATIC( json_character_flag( "VAMPIRE" ) ) ) ) { ++ if( allergy != MORALE_NULL && has_flag( STATIC( json_character_flag( "VAMPIRE" ) ) ) ) { + add_msg_if_player( m_bad, _( "I can't stomach anything but blood!" ) ); + add_morale( allergy, -75, -400, 30_minutes, 24_minutes ); + vomit(); @@ -308,9 +335,35 @@ if( has_trait( trait_PROJUNK ) ) { add_msg_if_player( m_good, _( "Mmm, junk food." ) ); +--- a/src/debug_menu.cpp ++++ b/src/debug_menu.cpp +@@ -1728,6 +1728,7 @@ + btype.addentry( static_cast<int>( blood_type::blood_A ), true, '2', "A" ); + btype.addentry( static_cast<int>( blood_type::blood_B ), true, '3', "B" ); + btype.addentry( static_cast<int>( blood_type::blood_AB ), true, '4', "AB" ); ++ btype.addentry( static_cast<int>( blood_type::blood_AB ), true, '4', "V" ); + btype.query(); + if( btype.ret < 0 ) { + break; + +--- a/src/do_turn.cpp ++++ b/src/do_turn.cpp +@@ -95,8 +95,9 @@ + int iInfoLine = 0; + + if( u.has_amount( itype_holybook_bible1, 1 ) || u.has_amount( itype_holybook_bible2, 1 ) || +- u.has_amount( itype_holybook_bible3, 1 ) ) { +- if( !( u.has_trait( trait_CANNIBAL ) || u.has_trait( trait_PSYCHOPATH ) ) ) { ++ u.has_amount( itype_holybook_bible3, 1 ) || u.has_trait( trait_id( "THRESH_REAL_VAMP" ) ) ) { ++ if( !( u.has_trait( trait_id( "CANNIBAL" ) ) || u.has_trait( trait_id( "PSYCHOPATH" ) ) || ++ u.has_trait( trait_id( "THRESH_REAL_VAMP" ) ) ) ) { + vRip.emplace_back( " _______ ___" ); + vRip.emplace_back( " < `/ |" ); + vRip.emplace_back( " > _ _ (" ); + --- a/src/flag.cpp +++ b/src/flag.cpp -@@ -13,8 +13,11 @@ +@@ -15,13 +15,17 @@ const flag_id flag_ACT_IN_FIRE( "ACT_IN_FIRE" ); const flag_id flag_ACT_ON_RANGED_HIT( "ACT_ON_RANGED_HIT" ); const flag_id flag_ALARMCLOCK( "ALARMCLOCK" ); @@ -322,10 +375,17 @@ const flag_id flag_ALLERGEN_JUNK( "ALLERGEN_JUNK" ); const flag_id flag_ALLERGEN_MEAT( "ALLERGEN_MEAT" ); const flag_id flag_ALLERGEN_MILK( "ALLERGEN_MILK" ); -@@ -303,6 +306,8 @@ + const flag_id flag_ALLERGEN_NUT( "ALLERGEN_NUT" ); + const flag_id flag_ALLERGEN_VEGGY( "ALLERGEN_VEGGY" ); ++const flag_id flag_ALLERGEN_WATER( "ALLERGEN_WATER" ); + const flag_id flag_ALLERGEN_WHEAT( "ALLERGEN_WHEAT" ); + const flag_id flag_ALLERGEN_WOOL( "ALLERGEN_WOOL" ); + const flag_id flag_ALLOWS_NATURAL_ATTACKS( "ALLOWS_NATURAL_ATTACKS" ); +@@ -337,6 +341,9 @@ const flag_id flag_USE_EAT_VERB( "USE_EAT_VERB" ); const flag_id flag_USE_PLAYER_ENERGY( "USE_PLAYER_ENERGY" ); const flag_id flag_USE_UPS( "USE_UPS" ); ++const flag_id flag_VAMPIRE( "VAMPIRE" ); +const flag_id flag_VAMPIRISM( "VAMPIRISM" ); +const flag_id flag_VAMPIRISM_OK( "VAMPIRISM_OK" ); const flag_id flag_VARSIZE( "VARSIZE" ); @@ -334,84 +394,71 @@ --- a/src/flag.h +++ b/src/flag.h -@@ -20,8 +20,11 @@ +@@ -24,13 +24,17 @@ extern const flag_id flag_ACT_IN_FIRE; extern const flag_id flag_ACT_ON_RANGED_HIT; extern const flag_id flag_ALARMCLOCK; +extern const flag_id flag_ALLERGEN_ALCOHOL; extern const flag_id flag_ALLERGEN_EGG; -+extern const flag_id flag_ALLERGEN_FOODSTUFF; extern const flag_id flag_ALLERGEN_FRUIT; ++extern const flag_id flag_ALLERGEN_FOODSTUFF; +extern const flag_id flag_ALLERGEN_HONEY; extern const flag_id flag_ALLERGEN_JUNK; extern const flag_id flag_ALLERGEN_MEAT; extern const flag_id flag_ALLERGEN_MILK; -@@ -310,6 +313,8 @@ + extern const flag_id flag_ALLERGEN_NUT; + extern const flag_id flag_ALLERGEN_VEGGY; ++extern const flag_id flag_ALLERGEN_WATER; + extern const flag_id flag_ALLERGEN_WHEAT; + extern const flag_id flag_ALLERGEN_WOOL; + extern const flag_id flag_ALLOWS_NATURAL_ATTACKS; +@@ -342,6 +346,9 @@ extern const flag_id flag_USE_EAT_VERB; extern const flag_id flag_USE_PLAYER_ENERGY; extern const flag_id flag_USE_UPS; ++extern const flag_id flag_VAMPIRE; +extern const flag_id flag_VAMPIRISM; +extern const flag_id flag_VAMPIRISM_OK; extern const flag_id flag_VARSIZE; extern const flag_id flag_VEHICLE; extern const flag_id flag_WAIST; - ---- a/src/game.cpp -+++ b/src/game.cpp -@@ -1039,8 +1039,9 @@ - int iInfoLine = 0; - if( u.has_amount( itype_holybook_bible1, 1 ) || u.has_amount( itype_holybook_bible2, 1 ) || -- u.has_amount( itype_holybook_bible3, 1 ) ) { -- if( !( u.has_trait( trait_id( "CANNIBAL" ) ) || u.has_trait( trait_id( "PSYCHOPATH" ) ) ) ) { -+ u.has_amount( itype_holybook_bible3, 1 ) || u.has_trait( trait_id( "THRESH_VAMP" ) ) ) { -+ if( !( u.has_trait( trait_id( "CANNIBAL" ) ) || u.has_trait( trait_id( "PSYCHOPATH" ) ) || -+ u.has_trait( trait_id( "THRESH_VAMP" ) ) ) ) { - vRip.emplace_back( " _______ ___" ); - vRip.emplace_back( " < `/ |" ); - vRip.emplace_back( " > _ _ (" ); - --- a/src/item.cpp +++ b/src/item.cpp -@@ -155,6 +155,7 @@ +@@ -170,6 +170,7 @@ + static const itype_id itype_waterproof_gunmod( "waterproof_gunmod" ); static const json_character_flag json_flag_CANNIBAL( "CANNIBAL" ); - static const json_character_flag json_flag_IMMUNE_SPOIL( "IMMUNE_SPOIL" ); +static const json_character_flag json_flag_VAMPIRE( "VAMPIRE" ); + static const json_character_flag json_flag_IMMUNE_SPOIL( "IMMUNE_SPOIL" ); - static const bionic_id bio_digestion( "bio_digestion" ); - -@@ -1967,19 +1967,35 @@ - info.emplace_back( "DESCRIPTION", + static const matec_id RAPID( "RAPID" ); +@@ -2477,7 +2480,24 @@ _( "* This food will cause an <bad>allergic reaction</bad>." ) ); } + + if( food_item->has_flag( flag_VAMPIRISM ) && + parts->test( iteminfo_parts::FOOD_VAMPIRISM ) ) { -+ if( player_character.has_trait_flag( json_flag_VAMPIRE ) ) { ++ if( !player_character.has_flag( json_flag_CANNIBAL ) && ++ !player_character.has_flag( json_flag_VAMPIRE ) ) { + info.emplace_back( "DESCRIPTION", -+ _( "* This food contains <good>human blood</good>." ) ); -+ } else if( player_character.has_trait_flag( json_flag_CANNIBAL ) ) { ++ _( "* This food contains <bad>human flesh</bad>." ) ); ++ } else if( player_character.has_flag( json_flag_CANNIBAL ) && ++ !player_character.has_flag( json_flag_VAMPIRE ) ) { + info.emplace_back( "DESCRIPTION", + _( "* This food contains <good>human flesh</good>." ) ); + } else { + info.emplace_back( "DESCRIPTION", -+ _( "* This food contains <bad>human flesh</bad>." ) ); ++ _( "* This food contains <good>human blood</good>." ) ); + } + } - ++ if( food_item->has_flag( flag_CANNIBALISM ) && + !food_item->has_flag( flag_VAMPIRISM ) && parts->test( iteminfo_parts::FOOD_CANNIBALISM ) ) { -- if( !player_character.has_trait_flag( json_flag_CANNIBAL ) ) { -+ if( player_character.has_trait_flag( json_flag_CANNIBAL ) && -+ !player_character.has_trait_flag( json_flag_VAMPIRE ) ) { - info.emplace_back( "DESCRIPTION", -- _( "* This food contains <bad>human flesh</bad>." ) ); -+ _( "* This food contains <good>human flesh</good>." ) ); - } else { + if( !player_character.has_flag( json_flag_CANNIBAL ) ) { info.emplace_back( "DESCRIPTION", -- _( "* This food contains <good>human flesh</good>." ) ); -+ _( "* This food contains <bad>human flesh</bad>." ) ); +@@ -2488,7 +2508,8 @@ } } @@ -421,7 +468,7 @@ info.emplace_back( "DESCRIPTION", _( "* This food is <bad>tainted</bad> and will poison you." ) ); } -@@ -4374,6 +4390,7 @@ +@@ -5959,6 +5980,7 @@ case ALLERGY: case ALLERGY_WEAK: case CANNIBALISM: @@ -432,34 +479,62 @@ --- a/src/item_factory.cpp +++ b/src/item_factory.cpp -@@ -2505,6 +2505,7 @@ - // First allergens: - // An item is an allergen even if it has trace amounts of allergenic material - { material_id( "hflesh" ), flag_CANNIBALISM }, -+ { material_id( "blood" ), flag_VAMPIRISM }, - - { material_id( "hflesh" ), flag_ALLERGEN_MEAT }, - { material_id( "iflesh" ), flag_ALLERGEN_MEAT }, -@@ -2519,10 +2520,15 @@ - { material_id( "mushroom" ), flag_ALLERGEN_VEGGY }, - { material_id( "milk" ), flag_ALLERGEN_MILK }, - { material_id( "egg" ), flag_ALLERGEN_EGG }, -+ { material_id( "alcohol" ), flag_ALLERGEN_ALCOHOL }, -+ { material_id( "foodstuff" ), flag_ALLERGEN_FOODSTUFF }, -+ { material_id( "honey" ), flag_ALLERGEN_HONEY }, - { material_id( "junk" ), flag_ALLERGEN_JUNK }, - // Not food, but we can keep it here - { material_id( "wool" ), flag_ALLERGEN_WOOL }, - // Now "made of". Those flags should not be passed -+ { material_id( "blood" ), flag_VAMPIRISM_OK }, -+ { material_id( "blood" ), flag_CARNIVORE_OK }, - { material_id( "flesh" ), flag_CARNIVORE_OK }, - { material_id( "hflesh" ), flag_CARNIVORE_OK }, - { material_id( "iflesh" ), flag_CARNIVORE_OK }, +@@ -85,10 +85,13 @@ + + static const item_group_id Item_spawn_data_EMPTY_GROUP( "EMPTY_GROUP" ); + ++static const material_id material_alcohol( "alcohol" ); + static const material_id material_bean( "bean" ); ++static const material_id material_blood( "blood" ); + static const material_id material_egg( "egg" ); + static const material_id material_flesh( "flesh" ); + static const material_id material_fruit( "fruit" ); ++static const material_id material_foodplace_foodstuff( "foodplace_foodstuff" ); + static const material_id material_garlic( "garlic" ); + static const material_id material_hflesh( "hflesh" ); + static const material_id material_honey( "honey" ); +@@ -101,6 +104,7 @@ + static const material_id material_oil( "oil" ); + static const material_id material_tomato( "tomato" ); + static const material_id material_veggy( "veggy" ); ++static const material_id material_water( "water" ); + static const material_id material_wheat( "wheat" ); + static const material_id material_wool( "wool" ); + +@@ -3356,10 +3360,11 @@ + // Set for all items (not just food and clothing) to avoid edge cases + void Item_factory::set_allergy_flags( itype &item_template ) + { +- static const std::array<std::pair<material_id, flag_id>, 22> all_pairs = { { ++ static const std::array<std::pair<material_id, flag_id>, 29> all_pairs = { { + // First allergens: + // An item is an allergen even if it has trace amounts of allergenic material + { material_hflesh, flag_CANNIBALISM }, ++ { material_hflesh, flag_VAMPIRISM }, + + { material_hflesh, flag_ALLERGEN_MEAT }, + { material_iflesh, flag_ALLERGEN_MEAT }, +@@ -3374,10 +3379,16 @@ + { material_mushroom, flag_ALLERGEN_VEGGY }, + { material_milk, flag_ALLERGEN_MILK }, + { material_egg, flag_ALLERGEN_EGG }, ++ { material_alcohol, flag_ALLERGEN_ALCOHOL }, ++ { material_foodplace_foodstuff, flag_ALLERGEN_FOODSTUFF }, ++ { material_water, flag_ALLERGEN_WATER }, ++ { material_honey, flag_ALLERGEN_HONEY }, + { material_junk, flag_ALLERGEN_JUNK }, + // Not food, but we can keep it here + { material_wool, flag_ALLERGEN_WOOL }, + // Now "made of". Those flags should not be passed ++ { material_blood, flag_VAMPIRISM_OK }, ++ { material_blood, flag_CARNIVORE_OK }, + { material_flesh, flag_CARNIVORE_OK }, + { material_hflesh, flag_CARNIVORE_OK }, + { material_iflesh, flag_CARNIVORE_OK }, --- a/src/iteminfo_query.h +++ b/src/iteminfo_query.h -@@ -41,6 +41,7 @@ +@@ -44,6 +44,7 @@ FOOD_VITAMINS, FOOD_VIT_EFFECTS, FOOD_CANNIBALISM, @@ -471,74 +546,74 @@ --- a/src/iuse.cpp +++ b/src/iuse.cpp @@ -342,6 +342,7 @@ + static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); static const trait_id trait_THRESH_PLANT( "THRESH_PLANT" ); static const trait_id trait_TOLERANCE( "TOLERANCE" ); - static const trait_id trait_URSINE_EYE( "URSINE_EYE" ); +static const trait_id trait_VAMP_SKIN( "VAMP_SKIN" ); static const trait_id trait_WAYFARER( "WAYFARER" ); - static const quality_id qual_AXE( "AXE" ); + static const vitamin_id vitamin_blood( "blood" ); @@ -4547,6 +4549,9 @@ if( p->has_trait( trait_ILLITERATE ) ) { p->add_msg_if_player( m_info, _( "You don't know what you're looking at." ) ); return cata::nullopt; + } else if( p->has_trait( trait_VAMP_SKIN ) ) { -+ p->add_msg_if_player( _( "Your %s shows warning: 'No heartbeat detected. " ++ p->add_msg_if_player( _( "Your %s shows a warning: 'No heartbeat detected. " + "This device must be worn to provide fitness feedback.'" ), it->tname() ); } else { //What else should block using f-band? - const int bpm = p->heartrate_bpm(); + std::string msg; --- a/src/map_field.cpp +++ b/src/map_field.cpp -@@ -92,6 +92,7 @@ - static const trait_id trait_M_SKIN3( "M_SKIN3" ); +@@ -94,6 +94,7 @@ + static const trait_id trait_THRESH_INSECT( "THRESH_INSECT" ); static const trait_id trait_THRESH_MARLOSS( "THRESH_MARLOSS" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); +static const trait_id trait_VAMP_SKIN( "VAMP_SKIN" ); + static const trait_id trait_THRESH_SPIDER( "THRESH_SPIDER" ); using namespace map_field_processing; - -@@ -1558,7 +1559,8 @@ +@@ -1623,7 +1624,8 @@ if( ( cur.get_field_intensity() > 1 || !one_in( 3 ) ) && ( !inside || one_in( 3 ) ) ) { - u.add_env_effect( effect_teargas, bodypart_id( "mouth" ), 5, 20_seconds ); + you.add_env_effect( effect_teargas, bodypart_id( "mouth" ), 5, 20_seconds ); } - if( cur.get_field_intensity() > 1 && ( !inside || one_in( 3 ) ) ) { -+ if( !( u.has_trait( trait_VAMP_SKIN ) ) && cur.get_field_intensity() > 1 && ( !inside || ++ if( !( you.has_trait( trait_VAMP_SKIN ) ) && cur.get_field_intensity() > 1 && ( !inside || + one_in( 3 ) ) ) { - u.add_env_effect( effect_blind, bodypart_id( "eyes" ), cur.get_field_intensity() * 2, 10_seconds ); + you.add_env_effect( effect_blind, bodypart_id( "eyes" ), cur.get_field_intensity() * 2, + 10_seconds ); } - } -@@ -1685,7 +1687,8 @@ +@@ -1748,7 +1750,8 @@ // The gas won't harm you inside a vehicle. if( !inside ) { // Full body suits protect you from the effects of the gas. -- if( !( u.worn_with_flag( STATIC( flag_id( "GAS_PROOF" ) ) ) && -+ if( !( u.has_trait( trait_VAMP_SKIN ) ) && -+ !( u.worn_with_flag( STATIC( flag_id( "GAS_PROOF" ) ) ) && - u.get_env_resist( bodypart_id( "mouth" ) ) >= 15 && - u.get_env_resist( bodypart_id( "eyes" ) ) >= 15 ) ) { +- if( !( you.worn_with_flag( STATIC( flag_id( "GAS_PROOF" ) ) ) && ++ if( !( you.has_trait( trait_VAMP_SKIN ) ) && ++ !( you.worn_with_flag( STATIC( flag_id( "GAS_PROOF" ) ) ) && + you.get_env_resist( bodypart_id( "mouth" ) ) >= 15 && + you.get_env_resist( bodypart_id( "eyes" ) ) >= 15 ) ) { const int intensity = cur.get_field_intensity(); --- a/src/memorial_logger.cpp +++ b/src/memorial_logger.cpp -@@ -90,6 +90,7 @@ +@@ -60,6 +60,7 @@ + static const trait_id trait_CANNIBAL( "CANNIBAL" ); static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" ); ++static const trait_id trait_THRESH_REAL_VAMP( "THRESH_REAL_VAMP" ); static const trait_id trait_SAPIOVORE( "SAPIOVORE" ); -+static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" ); memorial_log_entry::memorial_log_entry( const std::string &preformatted_msg ) : - preformatted_( preformatted_msg ) -@@ -590,6 +591,7 @@ +@@ -560,6 +561,7 @@ character_id ch = e.get<character_id>( "killer" ); if( ch == avatar_id ) { std::string name = e.get<cata_variant_type::string>( "victim_name" ); -+ bool vampire = player_character.has_trait( trait_THRESH_VAMP ); ++ bool vampire = player_character.has_trait( trait_THRESH_REAL_VAMP ); bool cannibal = player_character.has_trait( trait_CANNIBAL ); bool psycho = player_character.has_trait( trait_PSYCHOPATH ); if( player_character.has_trait( trait_SAPIOVORE ) ) { -@@ -613,6 +615,10 @@ +@@ -583,6 +585,10 @@ add( pgettext( "memorial_male", "Killed an innocent, %s." ), pgettext( "memorial_female", "Killed an innocent, %s." ), name ); @@ -552,71 +627,72 @@ --- a/src/morale_types.cpp +++ b/src/morale_types.cpp -@@ -40,6 +40,7 @@ - - morale_type( "morale_food_bad" ), - morale_type( "morale_cannibal" ), -+ morale_type( "morale_vampire" ), - morale_type( "morale_vegetarian" ), - morale_type( "morale_meatarian" ), - morale_type( "morale_antifruit" ), -@@ -138,6 +139,7 @@ - const morale_type MORALE_CRAVING_MARLOSS( "morale_craving_marloss" ); - const morale_type MORALE_FOOD_BAD( "morale_food_bad" ); +@@ -101,6 +101,7 @@ + const morale_type MORALE_BOOK( "morale_book" ); + const morale_type MORALE_BUTCHER( "morale_butcher" ); const morale_type MORALE_CANNIBAL( "morale_cannibal" ); +const morale_type MORALE_VAMPIRE( "morale_vampire" ); - const morale_type MORALE_VEGETARIAN( "morale_vegetarian" ); - const morale_type MORALE_MEATARIAN( "morale_meatarian" ); - const morale_type MORALE_ANTIFRUIT( "morale_antifruit" ); + const morale_type MORALE_CHAT( "morale_chat" ); + const morale_type MORALE_COLD( "morale_cold" ); + const morale_type MORALE_COMFY( "morale_comfy" ); +@@ -138,6 +139,7 @@ + static const morale_type morale_book( "morale_book" ); + static const morale_type morale_butcher( "morale_butcher" ); + static const morale_type morale_cannibal( "morale_cannibal" ); ++static const morale_type morale_vampire( "morale_vampire" ); + static const morale_type morale_chat( "morale_chat" ); + static const morale_type morale_cold( "morale_cold" ); + static const morale_type morale_comfy( "morale_comfy" ); --- a/src/morale_types.h +++ b/src/morale_types.h -@@ -62,6 +62,7 @@ +@@ -64,6 +64,7 @@ extern const morale_type MORALE_CRAVING_MARLOSS; extern const morale_type MORALE_FOOD_BAD; extern const morale_type MORALE_CANNIBAL; +extern const morale_type MORALE_VAMPIRE; extern const morale_type MORALE_VEGETARIAN; + extern const morale_type MORALE_ANTIVEGGY; extern const morale_type MORALE_MEATARIAN; - extern const morale_type MORALE_ANTIFRUIT; --- a/src/mutation.cpp +++ b/src/mutation.cpp -@@ -67,6 +67,7 @@ +@@ -82,6 +82,7 @@ + static const trait_id trait_SNAIL_TRAIL( "SNAIL_TRAIL" ); static const trait_id trait_STR_ALPHA( "STR_ALPHA" ); - static const trait_id trait_THRESH_MARLOSS( "THRESH_MARLOSS" ); - static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); -+static const trait_id trait_VAMP_SKIN( "VAMP_SKIN" ); static const trait_id trait_TREE_COMMUNION( "TREE_COMMUNION" ); ++static const trait_id trait_VAMP_SKIN( "VAMP_SKIN" ); static const trait_id trait_VOMITOUS( "VOMITOUS" ); static const trait_id trait_WEB_WEAVER( "WEB_WEAVER" ); -@@ -877,6 +878,10 @@ - { - bool force_bad = one_in( 3 ); - bool force_good = false; + +@@ -1032,6 +1033,11 @@ + bool allow_bad = picked_bad; + bool allow_neutral = true; + + if( has_trait( trait_VAMP_SKIN ) ) { + add_msg_if_player( m_good, _( "Your Vampire blood quickly destroys the mutagenic contagion." ) ); + return; + } - if( has_trait( trait_ROBUST ) && force_bad ) { - // Robust Genetics gives you a 33% chance for a good mutation, - // instead of the 33% chance of a bad one. ++ + if( true_random_chance > 0 && one_in( true_random_chance ) ) { + cat = mutation_category_ANY; + allow_good = true; // because i'm WILD YEAH --- a/src/npc.cpp +++ b/src/npc.cpp -@@ -124,6 +124,7 @@ +@@ -156,6 +156,7 @@ static const trait_id trait_SAPIOVORE( "SAPIOVORE" ); - static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" ); + static const trait_id trait_SQUEAMISH( "SQUEAMISH" ); static const trait_id trait_TERRIFYING( "TERRIFYING" ); -+static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" ); ++static const trait_id trait_THRESH_REAL_VAMP( "THRESH_REAL_VAMP" ); class monfaction; -@@ -2600,12 +2601,15 @@ +@@ -3012,12 +3013,15 @@ Character &player_character = get_player_character(); if( killer == &player_character && ( !guaranteed_hostile() || hit_by_player ) ) { -+ bool vampire = player_character.has_trait( trait_THRESH_VAMP ); ++ bool vampire = player_character.has_trait( trait_THRESH_REAL_VAMP ); bool cannibal = player_character.has_trait( trait_CANNIBAL ); bool psycho = player_character.has_trait( trait_PSYCHOPATH ); if( player_character.has_trait( trait_SAPIOVORE ) || psycho ) { @@ -631,40 +707,30 @@ --- a/src/player_hardcoded_effects.cpp +++ b/src/player_hardcoded_effects.cpp -@@ -115,6 +115,8 @@ - static const trait_id trait_SEESLEEP( "SEESLEEP" ); +@@ -126,6 +126,8 @@ + static const trait_id trait_NOPAIN( "NOPAIN" ); static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" ); static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); -+static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" ); ++static const trait_id trait_THRESH_REAL_VAMP( "THRESH_REAL_VAMP" ); +static const trait_id trait_VAMP_SKIN( "VAMP_SKIN" ); static const trait_id trait_WATERSLEEP( "WATERSLEEP" ); - static const json_character_flag json_flag_ALARMCLOCK( "ALARMCLOCK" ); -@@ -882,7 +884,9 @@ - } + static const vitamin_id vitamin_blood( "blood" ); +@@ -721,7 +723,9 @@ + } - if( dur > 1800_minutes && one_in( 300 * 512 ) ) { -- if( !has_trait( trait_NOPAIN ) ) { -+ if( has_trait( trait_VAMP_SKIN ) ) { -+ return; -+ } else if( !has_trait( trait_NOPAIN ) ) { - add_msg_if_player( m_bad, - _( "Your heart spasms painfully and stops, dragging you back to reality as you die." ) ); - } else { -@@ -1337,6 +1341,9 @@ - // Determine the strength of effects or dreams based upon category strength - int strength = 0; // Category too weak for any effect or dream - if( crossed_threshold() ) { -+ if( has_trait( trait_THRESH_VAMP ) ) { -+ highcat = mutation_category_id( "VAMP" ); -+ } - strength = 4; // Post-human. - } else if( highest >= 20 && highest < 35 ) { - strength = 1; // Low strength + if( dur > 1800_minutes && one_in( 300 * 512 ) ) { +- if( !u.has_trait( trait_NOPAIN ) ) { ++ if( u.has_trait( trait_VAMP_SKIN ) ) { ++ return; ++ } else if( !u.has_trait( trait_NOPAIN ) ) { + u.add_msg_if_player( m_bad, + _( "Your heart spasms painfully and stops, dragging you back to reality as you die." ) ); + } else { --- a/src/suffer.cpp +++ b/src/suffer.cpp -@@ -151,6 +151,8 @@ +@@ -176,6 +176,8 @@ static const trait_id trait_TROGLO2( "TROGLO2" ); static const trait_id trait_TROGLO3( "TROGLO3" ); static const trait_id trait_UNSTABLE( "UNSTABLE" ); @@ -673,76 +739,69 @@ static const trait_id trait_VOMITOUS( "VOMITOUS" ); static const trait_id trait_WEB_SPINNER( "WEB_SPINNER" ); static const trait_id trait_WEB_WEAVER( "WEB_WEAVER" ); -@@ -243,7 +245,8 @@ +@@ -286,7 +288,7 @@ - void Character::suffer_while_underwater() + void suffer::while_underwater( Character &you ) { -- if( !has_trait( trait_GILLS ) && !has_trait( trait_GILLS_CEPH ) ) { -+ if( !has_trait( trait_GILLS ) && !has_trait( trait_GILLS_CEPH ) && -+ !has_trait( trait_VAMP_SKIN ) ) { - oxygen--; +- if( !you.has_flag( json_flag_GILLS ) ) { ++ if( !you.has_flag( json_flag_GILLS ) && !you.has_trait( trait_VAMP_SKIN ) ) { + you.oxygen--; } - if( oxygen < 12 && worn_with_flag( flag_REBREATHER ) ) { -@@ -746,7 +749,8 @@ - return; + if( you.oxygen < 12 && you.worn_with_flag( flag_REBREATHER ) ) { +@@ -862,12 +864,12 @@ + you.vitamin_mod( vitamin_vitC, 1 ); } -- if( has_trait( trait_ALBINO ) || has_effect( effect_datura ) || has_trait( trait_SUNBURN ) ) { -+ if( has_trait( trait_ALBINO ) || has_effect( effect_datura ) || has_trait( trait_SUNBURN ) || -+ has_trait( trait_VAMP_CURSE ) ) { - suffer_from_sunburn(); +- if( you.has_trait( trait_SUNBURN ) ) { ++ if( you.has_trait( trait_SUNBURN ) || you.has_trait( trait_VAMP_CURSE ) ) { + suffer::from_sunburn( you, true ); } -@@ -772,6 +776,13 @@ - mod_int_bonus( -4 ); - mod_per_bonus( -4 ); + // Albinism and datura have the same effects and do not stack with each other or sunburn. +- if( !you.has_trait( trait_SUNBURN ) && ++ if( ( !you.has_trait( trait_SUNBURN ) && !you.has_trait( trait_VAMP_CURSE ) ) && + ( you.has_trait( trait_ALBINO ) || you.has_effect( effect_datura ) ) ) { + suffer::from_sunburn( you, false ); } -+ if( has_trait( trait_VAMP_CURSE ) ) { -+ mod_str_bonus( -4 ); -+ mod_dex_bonus( -4 ); -+ add_miss_reason( _( "You can't tolerate the sunlight!" ), 4 ); -+ mod_int_bonus( -4 ); -+ mod_per_bonus( -4 ); +@@ -895,6 +897,13 @@ + you.mod_int_bonus( -4 ); + you.mod_per_bonus( -4 ); + } ++ if( you.has_trait( trait_VAMP_CURSE ) ) { ++ you.mod_str_bonus( -4 ); ++ you.mod_dex_bonus( -4 ); ++ you.add_miss_reason( _( "You can't tolerate the sunlight!" ), 4 ); ++ you.mod_int_bonus( -4 ); ++ you.mod_per_bonus( -4 ); + } } std::map<bodypart_id, float> Character::bodypart_exposure() -@@ -803,7 +814,8 @@ - - void Character::suffer_from_sunburn() +@@ -948,7 +957,10 @@ + void suffer::from_sunburn( Character &you, bool severe ) { -- if( !has_trait( trait_ALBINO ) && !has_effect( effect_datura ) && !has_trait( trait_SUNBURN ) ) { -+ if( !has_trait( trait_ALBINO ) && !has_effect( effect_datura ) && !has_trait( trait_SUNBURN ) && -+ !has_trait( trait_VAMP_CURSE ) ) { + // Sunburn effects and albinism/datura occur about once per minute +- if( !one_turn_in( 1_minutes ) ) { ++ // Vampirism is ten times per minute ++ if( !one_turn_in( 1_minutes ) && !you.has_trait( trait_VAMP_CURSE ) ) { ++ return; ++ } else if( !one_turn_in( 6_seconds ) && you.has_trait( trait_VAMP_CURSE ) ) { return; } -@@ -820,6 +832,12 @@ - return; - } - sunlight_effect = _( "The sunlight burns!" ); -+ } else if( has_trait( trait_VAMP_CURSE ) ) { -+ // Sunburn effects occur about 10 times per minute -+ if( !one_turn_in( 6_seconds ) ) { -+ return; -+ } -+ sunlight_effect = _( "The sunlight sears" ); - } +@@ -2034,7 +2046,7 @@ + + healing_factor *= mutation_value( "mending_modifier" ); - // Sunglasses can keep the sun off the eyes. -@@ -897,7 +915,7 @@ +- if( has_flag( json_flag_MEND_ALL ) ) { ++ if( has_flag( json_flag_MEND_ALL ) || has_trait( trait_VAMP_SKIN ) ) { + needs_splint = false; } - // Solar Sensitivity (SUNBURN) trait causes injury to exposed parts -- if( has_trait( trait_SUNBURN ) ) { -+ if( has_trait( trait_SUNBURN ) || has_trait( trait_VAMP_CURSE ) ) { - mod_pain( 1 ); - // Check exposure of all body parts - for( const std::pair<const bodypart_id, float> &bp_exp : bp_exposure ) { --- a/data/json/field_type.json +++ b/data/json/field_type.json -@@ -354,7 +354,7 @@ +@@ -376,7 +376,7 @@ "has_fume": true, "percent_spread": 90, "dirty_transparency_cache": true, @@ -751,7 +810,7 @@ }, { "id": "fd_rubble", -@@ -429,7 +429,7 @@ +@@ -467,7 +467,7 @@ "dirty_transparency_cache": true, "percent_spread": 10, "outdoor_age_speedup": "0 turns", @@ -760,7 +819,7 @@ "priority": 8, "half_life": "2 minutes", "phase": "gas", -@@ -515,7 +515,7 @@ +@@ -553,7 +553,7 @@ "outdoor_age_speedup": "3 minutes", "dirty_transparency_cache": true, "has_fume": true, @@ -769,16 +828,25 @@ "priority": 8, "half_life": "10 minutes", "phase": "gas", -@@ -544,7 +544,7 @@ - "outdoor_age_speedup": "0 turns", +@@ -609,7 +609,7 @@ + "outdoor_age_speedup": "3 minutes", "dirty_transparency_cache": true, "has_fume": true, - "immunity_data": { "body_part_env_resistance": [ [ "mouth", 15 ] ] }, + "immunity_data": { "body_part_env_resistance": [ [ "mouth", 15 ] ], "traits": [ "VAMP_SKIN" ] }, "priority": 8, + "half_life": "10 minutes", + "phase": "gas", +@@ -638,7 +638,7 @@ + "outdoor_age_speedup": "0 turns", + "dirty_transparency_cache": true, + "has_fume": true, +- "immunity_data": { "body_part_env_resistance": [ [ "mouth", 15 ] ] }, ++ "immunity_data": { "body_part_env_resistance": [ [ "mouth", 15 ], [ "eyes", 15 ] ], "traits": [ "VAMP_SKIN" ] }, + "priority": 8, "half_life": "5 minutes", "phase": "gas", -@@ -590,7 +590,7 @@ +@@ -684,7 +684,7 @@ "wandering_field": "fd_toxic_gas", "gas_absorption_factor": 15, "dirty_transparency_cache": true, @@ -787,7 +855,7 @@ "phase": "gas", "display_items": false, "display_field": true, -@@ -1138,7 +1138,7 @@ +@@ -1240,7 +1240,7 @@ "outdoor_age_speedup": "5 minutes", "dirty_transparency_cache": true, "has_fume": true, @@ -796,7 +864,7 @@ "priority": 8, "half_life": "50 minutes", "phase": "gas", -@@ -1160,7 +1160,7 @@ +@@ -1262,7 +1262,7 @@ "outdoor_age_speedup": "1 minutes", "dirty_transparency_cache": true, "has_fume": true, @@ -805,7 +873,20 @@ "priority": 8, "half_life": "15 minutes", "phase": "gas", -@@ -1407,7 +1407,7 @@ +@@ -1306,7 +1306,11 @@ + "outdoor_age_speedup": "5 turns", + "dirty_transparency_cache": true, + "has_fume": true, +- "immunity_data": { "flags": [ "MYCUS_IMMUNE" ], "body_part_env_resistance": [ [ "mouth", 15 ], [ "sensor", 15 ] ] }, ++ "immunity_data": { ++ "flags": [ "MYCUS_IMMUNE" ], ++ "body_part_env_resistance": [ [ "mouth", 15 ], [ "sensor", 15 ] ], ++ "traits": [ "VAMP_SKIN" ] ++ }, + "priority": 8, + "half_life": "4 minutes", + "phase": "gas", +@@ -1509,7 +1509,7 @@ "outdoor_age_speedup": "3 minutes", "dirty_transparency_cache": true, "has_fume": true, @@ -814,7 +895,7 @@ "priority": 8, "half_life": "10 minutes", "phase": "gas" -@@ -1427,7 +1427,7 @@ +@@ -1529,7 +1529,7 @@ "outdoor_age_speedup": "1 minutes", "dirty_transparency_cache": true, "has_fume": true, @@ -823,7 +904,7 @@ "priority": 8, "half_life": "30 minutes", "phase": "gas", -@@ -1449,7 +1449,7 @@ +@@ -1551,7 +1551,7 @@ "outdoor_age_speedup": "1 minutes", "dirty_transparency_cache": true, "has_fume": true, @@ -835,50 +916,49 @@ --- a/data/json/flags.json +++ b/data/json/flags.json -@@ -1120,6 +1120,21 @@ - "context": [ "COMESTIBLE" ] +@@ -1120,6 +1120,22 @@ + "type": "json_flag" }, { + "id": "ALLERGEN_HONEY", -+ "type": "json_flag", -+ "context": [ "COMESTIBLE" ] ++ "type": "json_flag" + }, + { + "id": "ALLERGEN_ALCOHOL", -+ "type": "json_flag", -+ "context": [ "COMESTIBLE" ] ++ "type": "json_flag" + }, + { + "id": "ALLERGEN_FOODSTUFF", -+ "type": "json_flag", -+ "context": [ "COMESTIBLE" ] ++ "type": "json_flag" ++ }, ++ { ++ "id": "ALLERGEN_WATER", ++ "type": "json_flag" + }, + { "id": "ALLERGEN_JUNK", - "type": "json_flag", - "context": [ "COMESTIBLE" ] -@@ -1199,6 +1214,16 @@ - "type": "json_flag", - "context": [ ] + "type": "json_flag" }, -+ { +@@ -1189,6 +1205,14 @@ + "type": "json_flag" + }, + { + "id": "VAMPIRISM", -+ "type": "json_flag", -+ "context": [ ] ++ "type": "json_flag" + }, + { + "id": "VAMPIRISM_OK", -+ "type": "json_flag", -+ "context": [ ] ++ "type": "json_flag" + }, - { ++ { "id": "CASING", - "type": "json_flag", + "type": "json_flag" + }, --- a/data/json/morale_types.json +++ b/data/json/morale_types.json @@ -130,6 +130,11 @@ - "text": "Ate Demihuman Flesh" + "text": "Ate demihuman flesh" }, { + "id": "morale_vampire", @@ -888,11 +968,11 @@ + { "id": "morale_vegetarian", "type": "morale_type", - "text": "Ate Vegetables" + "text": "Ate vegetables" --- a/data/json/mutations/mutation_ordering.json +++ b/data/json/mutations/mutation_ordering.json -@@ -75,6 +75,7 @@ +@@ -80,6 +80,7 @@ "TROGLO2", "TROGLO3", "URSINE_FUR", @@ -900,12 +980,12 @@ "VISCOUS" ], "order": 1500 -@@ -182,7 +183,7 @@ +@@ -189,7 +190,7 @@ { "id": [ "FLOWERS" ], "order": 5000 }, - { "id": [ "ELFA_EARS", "FELINE_EARS", "LUPINE_EARS", "URSINE_EARS" ], "order": 5500 }, - { "id": [ "ANTENNAE", "ANTLERS", "CURVED_HORNS", "HORNS", "POINTED_HORNS" ], "order": 6000 }, + { "id": [ "ELFA_EARS", "FELINE_EARS", "LUPINE_EARS", "RABBIT_EARS", "URSINE_EARS" ], "order": 5500 }, + { "id": [ "ANTENNAE", "ANTLERS", "HORNS_CURLED", "HORNS", "HORNS_POINTED" ], "order": 6000 }, - { "id": [ "COMPOUND_EYES", "ELFAEYES", "FEL_EYE", "LIZ_EYE" ], "order": 6500 }, -+ { "id": [ "COMPOUND_EYES", "ELFAEYES", "FEL_EYE", "LIZ_EYE", "VAMP_EYES" ], "order": 6500 }, ++ { "id": [ "COMPOUND_EYES", "ELFAEYES", "FEL_EYE", "LIZ_EYE", "REAL_VAMP_EYES" ], "order": 6500 }, { "id": [ "BEAK", |