summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjc_gargma <jc_gargma@iserlohn-fortress.net>2021-09-05 22:00:26 -0700
committerjc_gargma <jc_gargma@iserlohn-fortress.net>2021-09-05 22:00:26 -0700
commitfdf0605b2ebea447c0277fe2c171e70bd93ddfac (patch)
tree81b82c6b34dfeb5d912e6f7239034bd6dc62acbd
parentUpdated to 2021-09-04-1536 (diff)
downloadcataclysm-bn-fdf0605b2ebea447c0277fe2c171e70bd93ddfac.tar.xz
Merge custom and custom 2 patches
-rw-r--r--custom-2.patch331
-rw-r--r--custom.patch422
2 files changed, 379 insertions, 374 deletions
diff --git a/custom-2.patch b/custom-2.patch
deleted file mode 100644
index a54377b..0000000
--- a/custom-2.patch
+++ /dev/null
@@ -1,331 +0,0 @@
---- a/data/json/flags.json
-+++ b/data/json/flags.json
-@@ -1093,6 +1093,11 @@
- "context": [ "COMESTIBLE" ]
- },
- {
-+ "id": "ALLERGEN_HONEY",
-+ "type": "json_flag",
-+ "context": [ "COMESTIBLE" ]
-+ },
-+ {
- "id": "ALLERGEN_JUNK",
- "type": "json_flag",
- "context": [ "COMESTIBLE" ]
-@@ -1173,6 +1173,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/src/activity_handlers.cpp
-+++ b/src/activity_handlers.cpp
-@@ -220,6 +220,7 @@
- static const species_id HUMAN( "HUMAN" );
- static const species_id ZOMBIE( "ZOMBIE" );
-
-+static const std::string trait_flag_VAMPIRE( "CANNIBAL" );
- static const std::string trait_flag_CANNIBAL( "CANNIBAL" );
- static const std::string trait_flag_PSYCHOPATH( "PSYCHOPATH" );
- static const std::string trait_flag_SAPIOVORE( "SAPIOVORE" );
-@@ -259,6 +260,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( "VAMPIRE" );
-+static const std::string flag_VAMPIRISM_OK( "VAMPIRISM_OK" );
-
- using namespace activity_handlers;
-
-@@ -651,7 +654,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.h
-+++ b/src/character.h
-@@ -163,6 +163,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,7 @@
- static const std::string flag_HIDDEN_HALLU( "HIDDEN_HALLU" );
- static const std::string flag_ALLERGEN_EGG( "ALLERGEN_EGG" );
- 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" );
-@@ -143,11 +144,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,
-+ }
-+};
- // 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}};
-@@ -719,6 +726,12 @@
- _( "Eww. Inedible plant stuff!" ) );
- }
-
-+ if( has_trait( trait_VAMP_HUNGER ) && nutrition_for( food ) > 0 &&
-+ 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!
-@@ -767,6 +780,12 @@
- edible_rating::cannibalism );
- }
-
-+ 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 edible = comest->comesttype == comesttype_FOOD || food.has_flag( flag_USE_EAT_VERB );
-
- int food_kcal = compute_effective_nutrients( food ).kcal;
-@@ -1116,6 +1135,25 @@
- }
- }
-
-+ 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 );
-+ }
-+ }
-+
- // Allergy check for food that is ingested (not gum)
- if( !food.has_flag( "NO_INGEST" ) ) {
- const auto allergy = allergy_type( food );
-@@ -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
-@@ -1008,8 +1008,9 @@
- int iInfoLine = 0;
-
- if( u.has_amount( "holybook_bible1", 1 ) || u.has_amount( "holybook_bible2", 1 ) ||
-- u.has_amount( "holybook_bible3", 1 ) ) {
-- if( !( u.has_trait( trait_id( "CANNIBAL" ) ) || u.has_trait( trait_id( "PSYCHOPATH" ) ) ) ) {
-+ u.has_amount( "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
-@@ -3947,6 +3947,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
-@@ -2219,6 +2219,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" ),
-@@ -2233,10 +2234,13 @@
- 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( "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/memorial_logger.cpp
-+++ b/src/memorial_logger.cpp
-@@ -80,6 +80,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" );
-@@ -486,6 +487,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 ) ) {
-@@ -509,6 +511,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
-@@ -138,6 +139,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/npc.cpp
-+++ b/src/npc.cpp
-@@ -116,6 +116,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" );
-
-@@ -2486,12 +2487,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/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;
diff --git a/custom.patch b/custom.patch
index 25cc30d..6046066 100644
--- a/custom.patch
+++ b/custom.patch
@@ -1,3 +1,33 @@
+--- a/src/activity_handlers.cpp
++++ b/src/activity_handlers.cpp
+@@ -220,6 +220,7 @@
+ static const species_id HUMAN( "HUMAN" );
+ static const species_id ZOMBIE( "ZOMBIE" );
+
++static const std::string trait_flag_VAMPIRE( "CANNIBAL" );
+ static const std::string trait_flag_CANNIBAL( "CANNIBAL" );
+ static const std::string trait_flag_PSYCHOPATH( "PSYCHOPATH" );
+ static const std::string trait_flag_SAPIOVORE( "SAPIOVORE" );
+@@ -259,6 +260,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( "VAMPIRE" );
++static const std::string flag_VAMPIRISM_OK( "VAMPIRISM_OK" );
+
+ using namespace activity_handlers;
+
+@@ -651,7 +654,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
@@ -288,9 +288,11 @@
@@ -39,6 +69,181 @@
temp_conv.fill( BODYTEMP_NORM );
return;
+--- a/src/character.h
++++ b/src/character.h
+@@ -163,6 +163,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,7 @@
+ static const std::string flag_HIDDEN_HALLU( "HIDDEN_HALLU" );
+ static const std::string flag_ALLERGEN_EGG( "ALLERGEN_EGG" );
+ 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" );
+@@ -143,11 +144,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,
++ }
++};
+ // 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}};
+@@ -719,6 +726,12 @@
+ _( "Eww. Inedible plant stuff!" ) );
+ }
+
++ if( has_trait( trait_VAMP_HUNGER ) && nutrition_for( food ) > 0 &&
++ 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!
+@@ -767,6 +780,12 @@
+ edible_rating::cannibalism );
+ }
+
++ 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 edible = comest->comesttype == comesttype_FOOD || food.has_flag( flag_USE_EAT_VERB );
+
+ int food_kcal = compute_effective_nutrients( food ).kcal;
+@@ -1116,6 +1135,25 @@
+ }
+ }
+
++ 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 );
++ }
++ }
++
+ // Allergy check for food that is ingested (not gum)
+ if( !food.has_flag( "NO_INGEST" ) ) {
+ const auto allergy = allergy_type( food );
+@@ -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
+@@ -1008,8 +1008,9 @@
+ int iInfoLine = 0;
+
+ if( u.has_amount( "holybook_bible1", 1 ) || u.has_amount( "holybook_bible2", 1 ) ||
+- u.has_amount( "holybook_bible3", 1 ) ) {
+- if( !( u.has_trait( trait_id( "CANNIBAL" ) ) || u.has_trait( trait_id( "PSYCHOPATH" ) ) ) ) {
++ u.has_amount( "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
+@@ -3947,6 +3947,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
+@@ -2219,6 +2219,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" ),
+@@ -2233,10 +2234,13 @@
+ 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( "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
@@ -88,6 +88,7 @@
@@ -71,50 +276,37 @@
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/suffer.cpp
-+++ b/src/suffer.cpp
-@@ -143,10 +143,13 @@
- static const trait_id trait_SHOUT3( "SHOUT3" );
- static const trait_id trait_SORES( "SORES" );
- static const trait_id trait_SUNBURN( "SUNBURN" );
-+static const trait_id trait_THRESH_GYNOID( "THRESH_GYNOID" );
-+static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" );
- static const trait_id trait_TROGLO( "TROGLO" );
- 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_VOMITOUS( "VOMITOUS" );
- static const trait_id trait_WEB_SPINNER( "WEB_SPINNER" );
- static const trait_id trait_WEB_WEAVER( "WEB_WEAVER" );
-@@ -243,7 +246,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_THRESH_GYNOID ) && !has_trait( trait_THRESH_VAMP ) ) {
- oxygen--;
- }
- if( oxygen < 12 && worn_with_flag( "REBREATHER" ) ) {
-@@ -759,6 +763,17 @@
- }
- }
+
+--- a/src/memorial_logger.cpp
++++ b/src/memorial_logger.cpp
+@@ -80,6 +80,7 @@
+ static const trap_str_id tr_snake( "tr_snake" );
+ static const trap_str_id tr_glass_pit( "tr_glass_pit" );
-+ if( has_trait( trait_VAMP_CURSE ) && one_in( 10 ) ) {
-+ if( !( weapon.has_flag( "RAIN_PROTECT" ) ) ) {
-+ add_msg_if_player( m_bad, _( "The sunlight sears your skin!" ) );
-+ if( has_effect( effect_sleep ) && !has_effect( effect_narcosis ) ) {
-+ wake_up();
-+ }
-+ mod_pain( 5 );
-+ hurtall( 5, nullptr );
-+ }
-+ }
-+
- if( ( has_trait( trait_TROGLO ) || has_trait( trait_TROGLO2 ) ) &&
- g->weather.weather == WEATHER_SUNNY ) {
- mod_str_bonus( -1 );
++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" );
+@@ -486,6 +487,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 ) ) {
+@@ -509,6 +511,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/monattack.cpp
+++ b/src/monattack.cpp
@@ -143,6 +143,7 @@
@@ -135,6 +327,56 @@
if( hit ) {
//Add checks if previous NPC/player conditions are removed
dynamic_cast<player *>( target )->mutate();
+
+--- a/src/morale_types.cpp
++++ b/src/morale_types.cpp
+@@ -138,6 +139,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/npc.cpp
++++ b/src/npc.cpp
+@@ -116,6 +116,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" );
+
+@@ -2486,12 +2487,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
@@ -114,7 +114,9 @@
@@ -159,6 +401,52 @@
strength = 4; // Post-human.
} else if( highest >= 20 && highest < 35 ) {
strength = 1; // Low strength
+
+--- a/src/suffer.cpp
++++ b/src/suffer.cpp
+@@ -143,10 +143,13 @@
+ static const trait_id trait_SHOUT3( "SHOUT3" );
+ static const trait_id trait_SORES( "SORES" );
+ static const trait_id trait_SUNBURN( "SUNBURN" );
++static const trait_id trait_THRESH_GYNOID( "THRESH_GYNOID" );
++static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" );
+ static const trait_id trait_TROGLO( "TROGLO" );
+ 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_VOMITOUS( "VOMITOUS" );
+ static const trait_id trait_WEB_SPINNER( "WEB_SPINNER" );
+ static const trait_id trait_WEB_WEAVER( "WEB_WEAVER" );
+@@ -243,7 +246,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_THRESH_GYNOID ) && !has_trait( trait_THRESH_VAMP ) ) {
+ oxygen--;
+ }
+ if( oxygen < 12 && worn_with_flag( "REBREATHER" ) ) {
+@@ -759,6 +763,17 @@
+ }
+ }
+
++ if( has_trait( trait_VAMP_CURSE ) && one_in( 10 ) ) {
++ if( !( weapon.has_flag( "RAIN_PROTECT" ) ) ) {
++ add_msg_if_player( m_bad, _( "The sunlight sears your skin!" ) );
++ if( has_effect( effect_sleep ) && !has_effect( effect_narcosis ) ) {
++ wake_up();
++ }
++ mod_pain( 5 );
++ hurtall( 5, nullptr );
++ }
++ }
++
+ if( ( has_trait( trait_TROGLO ) || has_trait( trait_TROGLO2 ) ) &&
+ g->weather.weather == WEATHER_SUNNY ) {
+ mod_str_bonus( -1 );
+
--- a/data/json/field_type.json
+++ b/data/json/field_type.json
@@ -303,7 +303,7 @@
@@ -242,6 +530,54 @@
"priority": 8,
"half_life": "30 minutes",
"phase": "gas",
+
+--- a/data/json/flags.json
++++ b/data/json/flags.json
+@@ -1093,6 +1093,11 @@
+ "context": [ "COMESTIBLE" ]
+ },
+ {
++ "id": "ALLERGEN_HONEY",
++ "type": "json_flag",
++ "context": [ "COMESTIBLE" ]
++ },
++ {
+ "id": "ALLERGEN_JUNK",
+ "type": "json_flag",
+ "context": [ "COMESTIBLE" ]
+@@ -1173,6 +1173,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 @@