--- a/src/activity_handlers.cpp
+++ b/src/activity_handlers.cpp
@@ -238,6 +238,7 @@3
 static const species_id HUMAN( "HUMAN" );
 static const species_id ZOMBIE( "ZOMBIE" );
 
+static const std::string trait_flag_VAMPIRE( "VAMPIRE" );
 static const std::string trait_flag_CANNIBAL( "CANNIBAL" );
 static const std::string trait_flag_PSYCHOPATH( "PSYCHOPATH" );
 static const std::string trait_flag_SAPIOVORE( "SAPIOVORE" );
@@ -278,6 +278,8 @@
 static const std::string flag_SUPPORTS_ROOF( "SUPPORTS_ROOF" );
 static const std::string flag_TREE( "TREE" );
 static const std::string flag_USE_UPS( "USE_UPS" );
+static const std::string flag_VAMPIRISM( "VAMPIRISM" );
+static const std::string flag_VAMPIRISM_OK( "VAMPIRISM_OK" );
 
 using namespace activity_handlers;
 
@@ -667,7 +667,8 @@
                           !corpse.in_species( ZOMBIE ) );
     if( is_human && !( u.has_trait_flag( trait_flag_CANNIBAL ) ||
                        u.has_trait_flag( trait_flag_PSYCHOPATH ) ||
-                       u.has_trait_flag( trait_flag_SAPIOVORE ) ) ) {
+                       u.has_trait_flag( trait_flag_SAPIOVORE ) ||
+                       u.has_trait_flag( trait_flag_VAMPIRE ) ) ) {
         need_confirm( _( "Would you dare desecrate the mortal remains of a fellow human being?" ),
                       butcherable_rating::warn_cannibalism );
     }

--- a/src/character.cpp
+++ b/src/character.cpp
@@ -280,6 +280,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_PACKMULE( "PACKMULE" );
 static const trait_id trait_PADDED_FEET( "PADDED_FEET" );
 static const trait_id trait_PAWS( "PAWS" );
@@ -311,6 +311,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_VISCOUS( "VISCOUS" );
 static const trait_id trait_WATERSLEEP( "WATERSLEEP" );
 static const trait_id trait_WEBBED( "WEBBED" );
@@ -4429,7 +4432,15 @@
 {
     int pain_ticks = rate_multiplier;
     while( get_pain() > 0 && pain_ticks-- > 0 ) {
-        mod_pain( -roll_remainder( 0.2f + get_pain() / 50.0f ) );
+        if( has_trait( trait_PAINREC1 ) ) {
+            mod_pain( -roll_remainder( 0.2f + get_pain() / 45.0f ) );
+        } else if( has_trait( trait_PAINREC2 ) ) {
+            mod_pain( -roll_remainder( 0.2f + get_pain() / 40.0f ) );
+        } else if( has_trait( trait_PAINREC3 ) ) {
+            mod_pain( -roll_remainder( 0.2f + get_pain() / 30.0f ) );
+        } else {
+            mod_pain( -roll_remainder( 0.2f + get_pain() / 50.0f ) );
+        }
     }
 
     float rest = rest_quality();
@@ -4631,6 +4631,7 @@
     const bool npc_no_food = is_npc() && get_option<bool>( "NO_NPC_FOOD" );
     const bool foodless = debug_ls || npc_no_food;
     const bool mouse = has_trait( trait_NO_THIRST );
+    const bool vamp = has_trait( trait_VAMP_HUNGER );
     const bool mycus = has_trait( trait_M_DEPENDENT );
     const float kcal_per_time = bmr() / ( 12.0f * 24.0f );
     const int five_mins = ticks_between( from, to, 5_minutes );
@@ -4661,7 +4661,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 || mouse ) {
+    if( mycus || mouse  || vamp ) {
         set_thirst( 0 );
     }
 }
@@ -4861,15 +4861,17 @@
 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 ) ) ) {
         add_msg_if_player( m_bad, _( "You have a sudden heart attack!" ) );
         g->events().send<event_type::dies_from_drug_overdose>( getID(), efftype_id() );
         set_part_hp_cur( bodypart_id( "torso" ), 0 );
-    } else if( get_stim() < -200 || get_painkiller() > 240 ) {
+    } else if( ( get_stim() < -200 || get_painkiller() > 240 ) && !( has_trait( trait_VAMP_SKIN ) ) ) {
         add_msg_if_player( m_bad, _( "Your breathing stops completely." ) );
         g->events().send<event_type::dies_from_drug_overdose>( getID(), efftype_id() );
         set_part_hp_cur( bodypart_id( "torso" ), 0 );
-    } else if( has_effect( effect_jetinjector ) && get_effect_dur( effect_jetinjector ) > 40_minutes ) {
+    } else if( ( has_effect( effect_jetinjector ) &&
+                 get_effect_dur( effect_jetinjector ) > 40_minutes ) &&
+               !( has_trait( trait_VAMP_SKIN ) ) ) {
         if( !( has_trait( trait_NOPAIN ) ) ) {
             add_msg_if_player( m_bad, _( "Your heart spasms painfully and stops." ) );
         } else {
@@ -4879,11 +4879,12 @@
         }
         g->events().send<event_type::dies_from_drug_overdose>( getID(), effect_jetinjector );
         set_part_hp_cur( bodypart_id( "torso" ), 0 );
-    } else if( get_effect_dur( effect_adrenaline ) > 50_minutes ) {
+    } else if( ( get_effect_dur( effect_adrenaline ) > 50_minutes ) &&
+               !( has_trait( trait_VAMP_SKIN ) ) ) {
         add_msg_if_player( m_bad, _( "Your heart spasms and stops." ) );
         g->events().send<event_type::dies_from_drug_overdose>( getID(), effect_adrenaline );
         set_part_hp_cur( bodypart_id( "torso" ), 0 );
-    } else if( get_effect_int( effect_drunk ) > 4 ) {
+    } else if( ( get_effect_int( effect_drunk ) > 4 ) && !( has_trait( trait_VAMP_SKIN ) ) ) {
         add_msg_if_player( m_bad, _( "Your breathing slows down to a stop." ) );
         g->events().send<event_type::dies_from_drug_overdose>( getID(), effect_drunk );
         set_part_hp_cur( bodypart_id( "torso" ), 0 );
@@ -4985,7 +4988,7 @@
 
 void Character::update_bodytemp( const map &m, const weather_manager &weather )
 {
-    if( has_trait( trait_DEBUG_NOTEMP ) ) {
+    if( has_trait( trait_DEBUG_NOTEMP ) || has_trait( trait_VAMP_SKIN ) ) {
         temp_cur.fill( BODYTEMP_NORM );
         temp_conv.fill( BODYTEMP_NORM );
         return;

--- a/src/character.h
+++ b/src/character.h
@@ -162,6 +162,8 @@
     allergy_weak,
     // Cannibalism (unless psycho/cannibal)
     cannibalism,
+    // Vampirism (unless psycho/cannibal)
+    vampirism,
     // Rotten or not rotten enough (for saprophages)
     rotten,
     // Can provoke vomiting if you already feel nauseous.

--- a/src/consumption.cpp
+++ b/src/consumption.cpp
@@ -108,6 +108,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" );
+static const trait_id trait_VAMP_HUNGER( "VAMP_HUNGER" );
 static const trait_id trait_VEGETARIAN( "VEGETARIAN" );
 static const trait_id trait_WATERSLEEP( "WATERSLEEP" );
 
@@ -114,6 +114,9 @@
 static const std::string flag_HIDDEN_HALLU( "HIDDEN_HALLU" );
+static const std::string flag_ALLERGEN_ALCOHOL( "ALLERGEN_ALCOHOL" );
 static const std::string flag_ALLERGEN_EGG( "ALLERGEN_EGG" );
+static const std::string flag_ALLERGEN_FOODSTUFF( "ALLERGEN_FOODSTUFF" );
 static const std::string flag_ALLERGEN_FRUIT( "ALLERGEN_FRUIT" );
+static const std::string flag_ALLERGEN_HONEY( "ALLERGEN_HONEY" );
 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" );
@@ -148,11 +148,17 @@
 static const std::string flag_RAW( "RAW" );
 static const std::string flag_URSINE_HONEY( "URSINE_HONEY" );
 static const std::string flag_USE_EAT_VERB( "USE_EAT_VERB" );
+static const std::string flag_VAMPIRISM( "VAMPIRISM" );
+static const std::string flag_VAMPIRISM_OK( "VAMPIRISM_OK" );
 
 const std::vector<std::string> carnivore_blacklist {{
         flag_ALLERGEN_VEGGY, flag_ALLERGEN_FRUIT, flag_ALLERGEN_WHEAT, flag_ALLERGEN_NUT,
     }
 };
+const std::vector<std::string> vamp_blacklist {{
+        flag_ALLERGEN_VEGGY, flag_ALLERGEN_FRUIT, flag_ALLERGEN_WHEAT, flag_ALLERGEN_NUT, flag_ALLERGEN_MEAT, flag_ALLERGEN_EGG, flag_ALLERGEN_JUNK, flag_ALLERGEN_MILK, flag_ALLERGEN_HONEY, flag_ALLERGEN_FOODSTUFF, flag_ALLERGEN_ALCOHOL,
+    }
+};
 // This ugly temp array is here because otherwise it goes
 // std::vector(char*, char*)->vector(InputIterator,InputIterator) or some such
 const std::array<std::string, 2> temparray {{flag_ALLERGEN_MEAT, flag_ALLERGEN_EGG}};
@@ -712,6 +712,12 @@
                 _( "Eww.  Inedible plant stuff!" ) );
     }
 
+    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( edible_rating::inedible_mutation,
+                _( "Bleh. This isn't blood!" ) );
+    }
+
     if( ( has_trait( trait_HERBIVORE ) || has_trait( trait_RUMINANT ) ) &&
         food.has_any_flag( herbivore_blacklist ) ) {
         // Like non-cannibal, but more strict!
@@ -744,8 +744,15 @@
         }
     }
 
+    if( food.has_flag( flag_VAMPIRISM ) && ( !has_trait_flag( "VAMPIRE" ) &&
+            !has_trait_flag( "CANNIBAL" ) ) ) {
+        add_consequence( _( "The thought of drinking human blood makes you feel sick." ),
+                         edible_rating::vampirism );
+    }
+
     const bool carnivore = has_trait( trait_CARNIVORE );
-    if( food.has_flag( flag_CANNIBALISM ) && !has_trait_flag( "CANNIBAL" ) ) {
+    if( ( food.has_flag( flag_CANNIBALISM ) && !food.has_flag( flag_VAMPIRISM ) ) &&
+        !has_trait_flag( "CANNIBAL" ) ) {
         add_consequence( _( "The thought of eating human flesh makes you feel sick." ),
                          edible_rating::cannibalism );
     }
@@ -1084,13 +1091,36 @@
         }
     }
 
+    if( food.has_flag( flag_VAMPIRISM ) ) {
+        const bool cannibal = has_trait( trait_CANNIBAL );
+        const bool psycho = has_trait( trait_PSYCHOPATH );
+        const bool sapiovore = has_trait( trait_SAPIOVORE );
+        const bool vamp = has_trait( trait_VAMP_HUNGER );
+        if( cannibal ) {
+            add_msg_if_player( m_good, _( "You indulge your shameful hunger." ) );
+            add_morale( MORALE_CANNIBAL, 20, 200 );
+        } else if( vamp ) {
+            add_msg_if_player( m_good, _( "You relish drinking the human blood." ) );
+            add_morale( MORALE_VAMPIRE, 30, 300 );
+        } else if( psycho || sapiovore ) {
+            // Nothing - doesn't care enough to print a message
+        } else {
+            add_msg_if_player( m_bad, _( "You feel horrible for drinking the blood of a person." ) );
+            add_morale( MORALE_CANNIBAL, -60, -400, 60_minutes, 30_minutes );
+        }
+    }
+
     if( food.has_flag( flag_CANNIBALISM ) ) {
         const bool cannibal = has_trait( trait_CANNIBAL );
         const bool psycho = has_trait( trait_PSYCHOPATH );
         const bool sapiovore = has_trait( trait_SAPIOVORE );
+        const bool vamp = has_trait( trait_VAMP_HUNGER );
         if( cannibal ) {
             add_msg_if_player( m_good, _( "You indulge your shameful hunger." ) );
             add_morale( MORALE_CANNIBAL, 20, 200 );
+        } else if( vamp && !food.has_flag( flag_VAMPIRISM ) ) {
+            add_msg_if_player( m_bad, _( "You feel horrible for eating a person." ) );
+            add_morale( MORALE_CANNIBAL, -60, -400, 60_minutes, 30_minutes );
         } else if( psycho || sapiovore ) {
             // Nothing - doesn't care enough to print a message
         } else {
@@ -1123,6 +1161,11 @@
             add_msg_if_player( m_bad, _( "Yuck!  How can anybody eat this stuff?" ) );
             add_morale( allergy, -75, -400, 30_minutes, 24_minutes );
         }
+        if( allergy != MORALE_NULL && has_trait( trait_VAMP_HUNGER ) ) {
+            add_msg_if_player( m_bad, _( "I can't stomach anything but blood!" ) );
+            add_morale( allergy, -75, -400, 30_minutes, 24_minutes );
+            vomit();
+        }
         if( food.has_flag( flag_ALLERGEN_JUNK ) ) {
             if( has_trait( trait_PROJUNK ) ) {
                 add_msg_if_player( m_good, _( "Mmm, junk food." ) );

--- a/src/game.cpp
+++ b/src/game.cpp
@@ -1040,8 +1040,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
@@ -148,6 +148,7 @@
 static const species_id ROBOT( "ROBOT" );
 
 static const std::string trait_flag_CANNIBAL( "CANNIBAL" );
+static const std::string trait_flag_VAMPIRE( "VAMPIRE" );
 
 static const bionic_id bio_digestion( "bio_digestion" );
 
@@ -256,6 +257,7 @@
 static const std::string flag_USES_BIONIC_POWER( "USES_BIONIC_POWER" );
 static const std::string flag_USE_UPS( "USE_UPS" );
 static const std::string flag_VARSIZE( "VARSIZE" );
+static const std::string flag_VAMPIRISM( "VAMPIRISM" );
 static const std::string flag_VEHICLE( "VEHICLE" );
 static const std::string flag_WAIST( "WAIST" );
 static const std::string flag_WATERPROOF_GUN( "WATERPROOF_GUN" );
@@ -1722,12 +1722,15 @@
 
     if( food_item->has_flag( flag_CANNIBALISM ) &&
         parts->test( iteminfo_parts::FOOD_CANNIBALISM ) ) {
-        if( !g->u.has_trait_flag( trait_flag_CANNIBAL ) ) {
+        if( g->u.has_trait_flag( trait_flag_CANNIBAL ) && !g->u.has_trait_flag( trait_flag_VAMPIRE ) ) {
             info.emplace_back( "DESCRIPTION",
-                               _( "* This food contains <bad>human flesh</bad>." ) );
+                               _( "* This food contains <good>human flesh</good>." ) );
+        } else if( g->u.has_trait_flag( trait_flag_VAMPIRE ) && food_item->has_flag( flag_VAMPIRISM ) ) {
+            info.emplace_back( "DESCRIPTION",
+                               _( "* This food contains <good>human blood</good>." ) );
         } else {
             info.emplace_back( "DESCRIPTION",
-                               _( "* This food contains <good>human flesh</good>." ) );
+                               _( "* This food contains <bad>human flesh</bad>." ) );
         }
     }
 
@@ -4046,6 +4046,7 @@
             case edible_rating::allergy:
             case edible_rating::allergy_weak:
             case edible_rating::cannibalism:
+            case edible_rating::vampirism:
                 ret = c_red;
                 break;
             case edible_rating::rotten:

--- a/src/item_factory.cpp
+++ b/src/item_factory.cpp
@@ -2251,6 +2251,7 @@
             // First allergens:
             // An item is an allergen even if it has trace amounts of allergenic material
             std::make_pair( material_id( "hflesh" ), "CANNIBALISM" ),
+            std::make_pair( material_id( "blood" ), "VAMPIRISM" ),
 
             std::make_pair( material_id( "hflesh" ), "ALLERGEN_MEAT" ),
             std::make_pair( material_id( "iflesh" ), "ALLERGEN_MEAT" ),
@@ -2266,10 +2266,15 @@
             std::make_pair( material_id( "mushroom" ), "ALLERGEN_VEGGY" ),
             std::make_pair( material_id( "milk" ), "ALLERGEN_MILK" ),
             std::make_pair( material_id( "egg" ), "ALLERGEN_EGG" ),
+            std::make_pair( material_id( "alcohol" ), "ALLERGEN_ALCOHOL" ),
+            std::make_pair( material_id( "foodplace_foodstuff" ), "ALLERGEN_FOODSTUFF" ),
+            std::make_pair( material_id( "honey" ), "ALLERGEN_HONEY" ),
             std::make_pair( material_id( "junk" ), "ALLERGEN_JUNK" ),
             // Not food, but we can keep it here
             std::make_pair( material_id( "wool" ), "ALLERGEN_WOOL" ),
             // Now "made of". Those flags should not be passed
+            std::make_pair( material_id( "blood" ), "VAMPIRISM_OK" ),
+            std::make_pair( material_id( "blood" ), "CARNIVORE_OK" ),
             std::make_pair( material_id( "flesh" ), "CARNIVORE_OK" ),
             std::make_pair( material_id( "hflesh" ), "CARNIVORE_OK" ),
             std::make_pair( material_id( "iflesh" ), "CARNIVORE_OK" ),

--- a/src/iteminfo_query.h
+++ b/src/iteminfo_query.h
@@ -36,6 +36,7 @@
     FOOD_VITAMINS,
     FOOD_VIT_EFFECTS,
     FOOD_CANNIBALISM,
+    FOOD_VAMPIRISM,
     FOOD_TAINT,
     FOOD_POISON,
     FOOD_HALLUCINOGENIC,

--- a/src/map_field.cpp
+++ b/src/map_field.cpp
@@ -91,6 +91,7 @@
 static const trait_id trait_M_SKIN3( "M_SKIN3" );
 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_WEB_WALKER( "WEB_WALKER" );
 
 void map::create_burnproducts( const tripoint &p, const item &fuel, const units::mass &burned_mass )
@@ -1405,7 +1405,8 @@
             if( ( cur.get_field_intensity() > 1 || !one_in( 3 ) ) && ( !inside || one_in( 3 ) ) ) {
                 u.add_env_effect( effect_teargas, bp_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 ||
+                    one_in( 3 ) ) ) {
                 u.add_env_effect( effect_blind, bp_eyes, cur.get_field_intensity() * 2, 10_seconds );
             }
         }
@@ -1537,8 +1537,9 @@
             // 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( flag_GAS_PROOF ) && u.get_env_resist( bodypart_id( "mouth" ) ) >= 15 &&
-                       u.get_env_resist( bodypart_id( "eyes" ) ) >= 15 ) ) {
+                if( !( u.has_trait( trait_VAMP_SKIN ) ) && !( u.worn_with_flag( flag_GAS_PROOF ) &&
+                        u.get_env_resist( bodypart_id( "mouth" ) ) >= 15 &&
+                        u.get_env_resist( bodypart_id( "eyes" ) ) >= 15 ) ) {
                     const int intensity = cur.get_field_intensity();
                     bool inhaled = u.add_env_effect( effect_poison, bp_mouth, 5, intensity * 1_minutes );
                     if( u.has_trait( trait_THRESH_MYCUS ) || u.has_trait( trait_THRESH_MARLOSS ) ||

--- a/src/memorial_logger.cpp
+++ b/src/memorial_logger.cpp
@@ -79,6 +79,7 @@
 static const trap_str_id tr_snake( "tr_snake" );
 static const trap_str_id tr_glass_pit( "tr_glass_pit" );
 
+static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" );
 static const trait_id trait_CANNIBAL( "CANNIBAL" );
 static const trait_id trait_PSYCHOPATH( "PSYCHOPATH" );
 static const trait_id trait_SAPIOVORE( "SAPIOVORE" );
@@ -488,6 +488,7 @@
             character_id ch = e.get<character_id>( "killer" );
             if( ch == g->u.getID() ) {
                 std::string name = e.get<cata_variant_type::string>( "victim_name" );
+                bool vampire = g->u.has_trait( trait_THRESH_VAMP );
                 bool cannibal = g->u.has_trait( trait_CANNIBAL );
                 bool psycho = g->u.has_trait( trait_PSYCHOPATH );
                 if( g->u.has_trait( trait_SAPIOVORE ) ) {
@@ -512,6 +512,10 @@
                     add( pgettext( "memorial_male", "Killed an innocent, %s." ),
                          pgettext( "memorial_female", "Killed an innocent, %s." ),
                          name );
+                } else if( vampire ) {
+                    add( pgettext( "memorial_male", "Killed an innocent human, %s." ),
+                         pgettext( "memorial_female", "Killed an innocent human, %s." ),
+                         name );
                 } else {
                     add( pgettext( "memorial_male",
                                    "Killed an innocent person, %s, in cold blood and "

--- a/src/morale_types.cpp
+++ b/src/morale_types.cpp
@@ -36,6 +36,7 @@
 const morale_type MORALE_CRAVING_MARLOSS( "morale_craving_marloss" );
 const morale_type MORALE_FOOD_BAD( "morale_food_bad" );
 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" );

--- a/src/morale_types.h
+++ b/src/morale_types.h
@@ -62,6 +62,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_MEATARIAN;
 extern const morale_type MORALE_ANTIFRUIT;

--- a/src/mutation.cpp
+++ b/src/mutation.cpp
@@ -80,6 +80,7 @@
 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_VOMITOUS( "VOMITOUS" );
 static const trait_id trait_WEB_WEAVER( "WEB_WEAVER" );
@@ -860,6 +860,11 @@
         if( !mutagen ) {
             return;
         }
+        if( has_trait( trait_VAMP_SKIN ) ) {
+            add_msg_if_player( m_good, _( "Your Vampire blood quickly destroys the mutagenic contagion." ) );
+            remove_effect( effect_accumulated_mutagen );
+            return;
+        }
         float mut_power = to_turns<float>( mutagen.get_duration() ) / to_turns<float>
                           ( mutagen.get_int_dur_factor() );
         add_msg_if_player( m_debug, "Mutation accumulation: %.1f", mut_power );
@@ -904,6 +904,10 @@
 {
     bool force_bad = one_in( 3 );
     bool force_good = false;
+    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.

--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -118,6 +118,7 @@
 static const trait_id trait_SAPIOVORE( "SAPIOVORE" );
 static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" );
 static const trait_id trait_TERRIFYING( "TERRIFYING" );
+static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" );
 
 static const std::string flag_NPC_SAFE( "NPC_SAFE" );
 
@@ -2492,12 +2492,15 @@
     }
 
     if( killer == &g->u && ( !guaranteed_hostile() || hit_by_player ) ) {
+        bool vampire = g->u.has_trait( trait_THRESH_VAMP );
         bool cannibal = g->u.has_trait( trait_CANNIBAL );
         bool psycho = g->u.has_trait( trait_PSYCHOPATH );
         if( g->u.has_trait( trait_SAPIOVORE ) || psycho ) {
             // No morale effect
         } else if( cannibal ) {
             g->u.add_morale( MORALE_KILLED_INNOCENT, -5, 0, 2_days, 3_hours );
+        } else if( vampire ) {
+            g->u.add_morale( MORALE_KILLED_INNOCENT, -5, 0, 2_days, 3_hours );
         } else {
             g->u.add_morale( MORALE_KILLED_INNOCENT, -100, 0, 2_days, 3_hours );
         }

--- a/src/player_hardcoded_effects.cpp
+++ b/src/player_hardcoded_effects.cpp
@@ -105,6 +105,8 @@
 static const trait_id trait_SEESLEEP( "SEESLEEP" );
 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_VAMP_SKIN( "VAMP_SKIN" );
 static const trait_id trait_WATERSLEEP( "WATERSLEEP" );
 
 static void eff_fun_onfire( player &u, effect &it )
@@ -841,7 +841,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 {
@@ -1065,6 +1065,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 = "VAMP";
+            }
             strength = 4; // Post-human.
         } else if( highest >= 20 && highest < 35 ) {
             strength = 1; // Low strength

--- a/src/suffer.cpp
+++ b/src/suffer.cpp
@@ -153,6 +153,8 @@
 static const trait_id trait_TROGLO2( "TROGLO2" );
 static const trait_id trait_TROGLO3( "TROGLO3" );
 static const trait_id trait_UNSTABLE( "UNSTABLE" );
+static const trait_id trait_VAMP_CURSE( "VAMP_CURSE" );
+static const trait_id trait_VAMP_SKIN( "VAMP_SKIN" );
 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" );
@@ -251,7 +251,8 @@
 
 void Character::suffer_while_underwater()
 {
-    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( oxygen < 12 && worn_with_flag( "REBREATHER" ) ) {
@@ -751,7 +751,8 @@
         return;
     }
 
-    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();
     }
 
@@ -778,6 +778,13 @@
         mod_int_bonus( -4 );
         mod_per_bonus( -4 );
     }
+    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 );
+    }
 }
 
 std::map<bodypart_id, float> Character::bodypart_exposure()
@@ -816,7 +816,8 @@
 
 void Character::suffer_from_sunburn()
 {
-    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 ) ) {
         return;
     }
 
@@ -834,6 +834,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" );
     }
 
     // Sunglasses can keep the sun off the eyes.
@@ -917,7 +917,7 @@
     }
 
     // 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
@@ -299,7 +299,7 @@
     "dirty_transparency_cache": true,
     "percent_spread": 10,
     "outdoor_age_speedup": "0 turns",
-    "immunity_data": { "body_part_env_resistance": [ [ "mouth", 7 ] ] },
+    "immunity_data": { "body_part_env_resistance": [ [ "mouth", 7 ] ], "traits": [ "VAMP_SKIN" ] },
     "priority": 8,
     "half_life": "2 minutes",
     "phase": "gas",
@@ -385,7 +385,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",
@@ -414,7 +414,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",
@@ -460,7 +460,7 @@
     "wandering_field": "fd_toxic_gas",
     "gas_absorption_factor": 15,
     "dirty_transparency_cache": true,
-    "immunity_data": { "body_part_env_resistance": [ [ "mouth", 15 ] ] },
+    "immunity_data": { "body_part_env_resistance": [ [ "mouth", 15 ] ], "traits": [ "VAMP_SKIN" ] },
     "phase": "gas",
     "display_items": false,
     "display_field": true,
@@ -956,7 +956,7 @@
     "outdoor_age_speedup": "5 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": "50 minutes",
     "phase": "gas",
@@ -978,7 +978,7 @@
     "outdoor_age_speedup": "1 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": "15 minutes",
     "phase": "gas",
@@ -1225,7 +1225,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"
@@ -1245,7 +1245,7 @@
     "outdoor_age_speedup": "1 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": "30 minutes",
     "phase": "gas",
@@ -1267,7 +1267,7 @@
     "outdoor_age_speedup": "1 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": "30 minutes",
     "phase": "gas",

--- a/data/json/flags.json
+++ b/data/json/flags.json
@@ -1117,6 +1117,21 @@
     "context": [ "COMESTIBLE" ]
   },
   {
+    "id": "ALLERGEN_HONEY",
+    "type": "json_flag",
+    "context": [ "COMESTIBLE" ]
+  },
+  {
+    "id": "ALLERGEN_ALCOHOL",
+    "type": "json_flag",
+    "context": [ "COMESTIBLE" ]
+  },
+  {
+    "id": "ALLERGEN_FOODSTUFF",
+    "type": "json_flag",
+    "context": [ "COMESTIBLE" ]
+  },
+  {
     "id": "ALLERGEN_JUNK",
     "type": "json_flag",
     "context": [ "COMESTIBLE" ]
@@ -1197,6 +1197,16 @@
     "context": [  ]
   },
   {
+    "id": "VAMPIRISM",
+    "type": "json_flag",
+    "context": [  ]
+  },
+  {
+    "id": "VAMPIRISM_OK",
+    "type": "json_flag",
+    "context": [  ]
+  },
+  {
     "id": "CASING",
     "type": "json_flag",
     "context": [  ]

--- a/data/json/morale_types.json
+++ b/data/json/morale_types.json
@@ -125,6 +125,11 @@
     "text": "Ate Human Flesh"
   },
   {
+    "id": "morale_vampire",
+    "type": "morale_type",
+    "text": "Drank Human Blood"
+  },
+  {
     "id": "morale_vegetarian",
     "type": "morale_type",
     "text": "Ate Meat"

--- a/data/json/mutations/mutation_ordering.json
+++ b/data/json/mutations/mutation_ordering.json
@@ -73,6 +73,7 @@
           "TROGLO2",
           "TROGLO3",
           "URSINE_FUR",
+          "VAMP_SKIN",
           "VISCOUS"
         ],
         "order": 1500
@@ -180,7 +181,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": [ "COMPOUND_EYES", "ELFAEYES", "FEL_EYE", "LIZ_EYE" ], "order": 6500 },
+      { "id": [ "COMPOUND_EYES", "ELFAEYES", "FEL_EYE", "LIZ_EYE", "VAMP_EYES" ], "order": 6500 },
       {
         "id": [
           "BEAK",