From f062a829b661fed17d860cb3b167dad254244a00 Mon Sep 17 00:00:00 2001 From: jc_gargma Date: Sat, 15 Jan 2022 17:39:54 -0800 Subject: Updated to 2022-01-14-1901 Fix drone volume patch. Remove obsolete quiverfull stairs fix. Fix dialogue typos. Fix duplicate Isherwood Farm mission. Rename custom patch to actually describe the purpose. Implement faster pain recovery traits. --- PKGBUILD | 48 +- custom.patch | 655 ---------------------- npc-01_dialogue-fixes.patch | 23 + npc-02_isherwood-duplicate-mission.patch | 35 ++ terrain-01_quiverfull-house-correct-stairs.patch | 11 - tools-04_normalize-drone-volume.patch | 32 +- vampirism.patch | 677 +++++++++++++++++++++++ 7 files changed, 780 insertions(+), 701 deletions(-) delete mode 100644 custom.patch create mode 100644 npc-01_dialogue-fixes.patch create mode 100644 npc-02_isherwood-duplicate-mission.patch delete mode 100644 terrain-01_quiverfull-house-correct-stairs.patch create mode 100644 vampirism.patch diff --git a/PKGBUILD b/PKGBUILD index da01634..3ed7907 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -13,9 +13,9 @@ pkgbase=cataclysm-bn pkgname=(cataclysm-bn cataclysm-bn-tiles) pkgname=cataclysm-bn _pkgname=Cataclysm-BN-cbn-experimental -pkgver=202201070536 -_pkgver=2022-01-07-0536 -pkgrel=8 +pkgver=202201141901 +_pkgver=2022-01-14-1901 +pkgrel=5 pkgdesc="A post-apocalyptic roguelike." #url="http://cataclysmrl.blogspot.com/" #url="http://www.cataclysm.glyphgryph.com/" @@ -55,9 +55,11 @@ source=("$pkgname-$_pkgver.tar.gz::https://github.com/cataclysmbnteam/Cataclysm- "mutations-01_nerf-lightstep.patch" "mutations-02_fix-evac3-background-visible.patch" + "npc-01_dialogue-fixes.patch" + "npc-02_isherwood-duplicate-mission.patch" + "recipes-01_4570-dragon-can-be-dismantled.patch" - "terrain-01_quiverfull-house-correct-stairs.patch" "terrain-02_tacoma-barn-door-position.patch" "terrain-03_tacoma-clinic-add-missing-floor.patch" "terrain-04_lumbermill-gasoline-not-spilled.patch" @@ -89,14 +91,14 @@ source=("$pkgname-$_pkgver.tar.gz::https://github.com/cataclysmbnteam/Cataclysm- "jc_more-military-base-overmap.patch" "jc_npc-eat-from-further-camp.patch" - "custom.patch" + "vampirism.patch" "cataclysm-dda-tileset_undeadpeople.tar.xz::https://library.iserlohn-fortress.net/cataclysm-dda-tileset_undeadpeople.git/snapshot/cataclysm-dda-tileset_undeadpeople-master.tar.xz" "cataclysm-dda-mod_battle-maid-redone-tileset.tar.xz::https://library.iserlohn-fortress.net/cataclysm-dda-mod_battle-maid-redone-tileset.git/snapshot/cataclysm-dda-mod_battle-maid-redone-tileset-master.tar.xz" "cataclysm-dda-soundpack_jcsoundpack.tar.xz::https://library.iserlohn-fortress.net/cataclysm-dda-soundpack_jcsoundpack.git/snapshot/cataclysm-dda-soundpack_jcsoundpack-master.tar.xz" "cataclysm-dda-musicpack_coag-musicpack.tar.xz::https://library.iserlohn-fortress.net/cataclysm-dda-musicpack_coag-musicpack.git/snapshot/cataclysm-dda-musicpack_coag-musicpack-master.tar.xz" ) -b2sums=('5c0fa1f88e5695147cf7950ef0dd314504e996976afc6e7b1fae06b8b455f2e9e1cb644d08e11f61102df8733d71c2ff9a29da1c3251c5ad11a2b9381928ee95' +b2sums=('7433781fb70afc6af6e8cdee190db516d74858053fd770dc564a99f856c1fe85f2f84beb65f9e23289c77ac06dc94efb636a9265462be62fbb2045355499b5cc' '069ecde58859b3d44cd687c4b6e718610cefb693ff86e66f199ebfb1b3072023ad2b6f0c28e27ef9c1ce4997f6a5b2ca0d45046996b3ff35a4aeaeb1a7cf9421' 'ad88bc6c1e3c8183a313b5eec42f98d6956afea349feff34a86e4536c9921fa99d2594282caf27de8ebb7ffb56376ed2e76d572227bfd6d8173c7bb1f01e23b8' '6f70e90359a14e4839d9a2683debb88850e5dd387add911ad68fd87e5512cfcdd435da63e1e370358153673fd5a72a9b1e9c94f1979edb7948b4da8c82407bad' @@ -117,8 +119,9 @@ b2sums=('5c0fa1f88e5695147cf7950ef0dd314504e996976afc6e7b1fae06b8b455f2e9e1cb644 '8bb71fbec3deece7bd0f9084e20ef5853812e71e2ebcd43011f7779499cbb99c7a8bc5c618d8ef9f55e5ce54c9fc4a5f4d3167bb63f9821a68889f9f3e1386f5' '08f4746882b927bdff6b728630cf1e04a2b79924f694ca2d841e3115c3399feb87a8d363e4d2a0f59179c109cb6be6e840f912aadd44abb0bdb35afd2838cc4d' 'ab35d6663b864449d46da4a9e1c51e11956ff4c38e16db58c831b71f7b964fc25b0283122dbc8aa0549f240f01c4a910fb5c6c82937258c6b736c05b54bcf768' + '5e902df8e6af1d17a4fc9733b485982ce413cb30b751d7c437c6a25b55a1b857e67f16c31e7006a863feec21b78ab4eccb933b16de7e628db57a46af8543cf68' + '339e48c2ce8d98852445839a71217a62af47af541c9e7573f21112c8b0bd5409b676774d2efd8665fe7f4cb5e6251467f77b9d9fad43a4c1fd61b405ae5e9831' '71768899e631c5293d5fb8bcb237ca54f880913b6400d445c8a0322cb69801fe85b94b1293306e2f33fac6067cbd892c4665b9563bdc9ff4df5be245c7e7108f' - '8232c6a10fd1f608304982ae7f03eb8afc663be76cdc00aee46ecb58de838e21fdc8673841266ccd00153263f7b15b59dcd1fc6ece86834509d7ccb2cacf08fa' 'ce0dd5121e814e0fcd79d68362c80a83bfe70f970be9d5d6f6fe5f6a56ed3f041be4d560aaf02225c3ce7c457dc63bc3adf0709d4b89a81c18184ff5341eb5d3' 'b8a64accada87ee5be989c5307805610c9b5c0327bc107aab237ac3225dd9e4c51b6c79a2a7de15fe187d3c32d7cbe1c462f9b0e9fb5d5a55a74236c7061e96e' '85aeb5920ee5879848be4057324153a077fe907bed527ed8f9b80a3c5ee1ef64786f63ee2999f5ba74e80a43e99ded3280ce27759c1f7b73259a6e2b5e584aa8' @@ -130,7 +133,7 @@ b2sums=('5c0fa1f88e5695147cf7950ef0dd314504e996976afc6e7b1fae06b8b455f2e9e1cb644 '7cae5e42b6e16f3c4bf64dca3c7573c1b552424ff70bb6da0a21f121b53b2546b239c87953a090cd90f46a1c3c124e2fe19c560b1830b11334f8e64c92fb614d' 'a45b2a53b6725dfd4780049a7522befe49c2a0c4efa4fb1dcb5cf53c7af18d329d2ba02aa6ac150342a3e66a46fd17f5e6e76a8db15c677a237edbb5cf4f5af7' '4c178d330117886848d232372a25ecf5cac46ad48a6fed580957d295eb1c4266836f4f807593d381f9089b2078c4185ba972f697ab353a850ebf35b6f140a4ac' - '8203bb062d72559da908a5020963503303c0aaa4a2ab61e57cfb713f58de40f1cb50b8b6dfbeec3a9addc41cbec5ae17fbf57230c3614f9b69fe6b0c55bf3fad' + '77bfba77f3548d267dc8142125bf26608c723bbdb2834317b3ea031ac64d9ff49bb4d75e29e2c759c03a662955697576d1c93153e9fb3e5dee86466bc29c78e1' '74a51f04237fba3caa25b2e0d49659f2e8330ce82288de866943d06b53690f31d48a77a4dd2e57db1f435b715fbca792268f2e191ffb59e57170d327ed41ac0a' 'e1d03f68918d03f980f4c2dd966e3788afe63f14e2d18dbd4dab2cdbfa1253e4823c0f5daa3a579e47319a3c2af35bc5af0a390e2ba91fe7621f6db8b1a60994' '5a5a61ccb7e2e343fb6de2e3426688485a2f4ad65d4b001d8bd542907fd8ceb9315da7fd9e5f89a5aa6210edcd5f334c73657fc16349000d6f6a394303e22000' @@ -145,10 +148,10 @@ b2sums=('5c0fa1f88e5695147cf7950ef0dd314504e996976afc6e7b1fae06b8b455f2e9e1cb644 '1919a87a97a1cc625a8a0f5f6a3affb45b0c9630768b42718c5a3df563127cc0436845d01a354b24a16080a89f53df0515a9b62dc14f5292a951057386e9d5d6' 'e3302d903d053f25aa666d572f74a8bbd3b65dde40eedcbf46e537ceb2294ac22b3772087fce04c4a780c2f18e855179c6ddc8af12d72a89b82957ce09deb52f' '4bd44cbe85c53902b8a360509703e3d38e8a5da75dd2c534a77f03ce6440632f6c83c92939069c60473c88ffb3abab0fbf11e39271f44f813b9f6432ea5f9a6b' - 'bbfeb77f087acae08b1980d8efe9ac5919b31d5bcf83ff2644c9ae27fa78a06da463a9c400dbea61112f11a4361e2cbd724fa7e73c049b8233cb5c9dbd3943ca' - '88a37f9ea10ec840453547621b24ecda7a9bc429a6427cd1b9cb651ef7ace2d002d67d240b1a26cc2fea1385cbc4fba389b0b2eaa503d0cbbd93c92d8983f450' + '5948f8f328176aa51cb9e41c018231db5307d41ae69e1e4515be03ff6b5b2c368c9962f0f683184983cccca239acedc9a4d1f06c42d6140415a134ea0268a8ff' + '63f1ba6a8a31212f129bd6c87a7f8b3debb6e2976c7dd95a748c9b8a62a06dece8dd6cc0adb55a852d3aea8e1f83c9fccaffdbef4057935638aed51c74937c39' 'a56efdaae0344726debf5b74846edce8df7aa2357fbc7a05a3d369d1f457b02934a0d0ce2330072e03f1ac901e06e333c9393f795c761f8440307e7649ed5596' - '2bd6322b06a17e2dc51ba5db110b65d25d97a39db1656f04a35a117954c1b8db98ca1599d87d82610ca97580aaedf91e70db84608946cb31007cb28793060628' + '9d0e17552338c9d92ff696f1834a5d99c29d5dfbab6903b620410f62527a0ba60720c9ceec8e203b737f784ade8a53dbaca428ac7cc439f3f4f765aac7f1170f' 'b9309da09b165fb57e83f84e3584d2479bd3336ed86e181e5df2d27daa92bd55d03d7f3fc226f03696af5f0f32d8e0e7ecd26ae7e50eed0200d0b0feaad07efb') prepare() { @@ -166,7 +169,7 @@ prepare() { sed -i 's|cataclysm-dda|cataclysm-bn|' src/path_info.cpp # Fix version - sed -i 's|VERSION = unstable|VERSION = 2022-01-07-0536|' Makefile + sed -i 's|VERSION = unstable|VERSION = 2022-01-14-1901|' Makefile # # # Hotfixes @@ -262,6 +265,17 @@ prepare() { patch -Np1 -i "$srcdir"/mutations-02_fix-evac3-background-visible.patch + # # npc fixes + echo "Applying NPC fixes" + # Assorted typos in NPC dialogue. + patch -Np1 -i "$srcdir"/npc-01_dialogue-fixes.patch + + echo "Applying NPC fixes" + # Jesse Isherwood's second mission is defined twice for some reason. + # Remove the version that is just a mashup of mission one and two. + patch -Np1 -i "$srcdir"/npc-02_isherwood-duplicate-mission.patch + + # # recipe fixes echo "Applying recipe fixes" # Fix reloaded 45-70 rounds and reloaded dragon shot not allowing dismantling when every other non-caseless round does. @@ -270,10 +284,6 @@ prepare() { # # terrain and overmap fixes echo "Applying terrain and overmap fixes" - # Fix Quiverfull house to have the correct stairwell direction: - # It was set to < for up, and not > for down. - patch -Np1 -i "$srcdir"/terrain-01_quiverfull-house-correct-stairs.patch - # Fix tacoma barn doors being placed in the same spot twice: # This enables the southeast barn door to be placed properly. patch -Np1 -i "$srcdir"/terrain-02_tacoma-barn-door-position.patch @@ -380,9 +390,9 @@ prepare() { # # # Additional changes - echo "Applying gynoid and vampire patch" - # Add gynoid and vampire mutation lines. might require vampire stuff redone mod. - patch -Np1 -i "$srcdir"/custom.patch + echo "Applying vampirism patch" + # Add vampire mutation lines and modify a number of functions to facilitate these traits. + patch -Np1 -i "$srcdir"/vampirism.patch } build() { diff --git a/custom.patch b/custom.patch deleted file mode 100644 index 7ed870d..0000000 --- a/custom.patch +++ /dev/null @@ -1,655 +0,0 @@ ---- 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 @@ - static const trait_id trait_THRESH_INSECT( "THRESH_INSECT" ); - static const trait_id trait_THRESH_PLANT( "THRESH_PLANT" ); - static const trait_id trait_THRESH_SPIDER( "THRESH_SPIDER" ); -+static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" ); - 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_VISCOUS( "VISCOUS" ); - static const trait_id trait_WATERSLEEP( "WATERSLEEP" ); - static const trait_id trait_WEBBED( "WEBBED" ); -@@ -4545,6 +4547,7 @@ - const bool npc_no_food = is_npc() && get_option( "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 ); -@@ -4568,7 +4571,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 ); - } - } -@@ -4985,7 +4988,7 @@ - - void Character::update_bodytemp( const map &m, weather_manager &weather ) - { -- if( has_trait( trait_DEBUG_NOTEMP ) ) { -+ if( has_trait( trait_DEBUG_NOTEMP ) || has_trait( trait_THRESH_VAMP ) ) { - temp_cur.fill( BODYTEMP_NORM ); - 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,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" ); -@@ -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 carnivore_blacklist {{ - flag_ALLERGEN_VEGGY, flag_ALLERGEN_FRUIT, flag_ALLERGEN_WHEAT, flag_ALLERGEN_NUT, - } - }; -+const std::vector 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 temparray {{flag_ALLERGEN_MEAT, flag_ALLERGEN_EGG}}; -@@ -719,6 +726,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::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( 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 -@@ -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,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 -@@ -88,6 +88,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_THRESH_VAMP( "THRESH_VAMP" ); - static const trait_id trait_WEB_WALKER( "WEB_WALKER" ); - - void map::create_burnproducts( const tripoint &p, const item &fuel, const units::mass &burned_mass ) -@@ -1395,7 +1396,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_THRESH_VAMP ) ) && cur.get_field_intensity() > 1 && ( !inside || -+ one_in( 3 ) ) ) { - u.add_env_effect( effect_blind, bp_eyes, cur.get_field_intensity() * 2, 10_seconds ); - } - } -@@ -1526,8 +1528,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_THRESH_VAMP ) ) && !( 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 -@@ -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( "killer" ); - if( ch == g->u.getID() ) { - std::string name = e.get( "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/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_THRESH_VAMP( "THRESH_VAMP" ); - 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" ); -@@ -887,6 +888,11 @@ - if( !mutagen ) { - return; - } -+ if( has_trait( trait_THRESH_VAMP ) ) { -+ 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( mutagen.get_duration() ) / to_turns - ( mutagen.get_int_dur_factor() ); - add_msg_if_player( m_debug, "Mutation accumulation: %.1f", mut_power ); -@@ -926,6 +932,10 @@ - { - bool force_bad = one_in( 3 ); - bool force_good = false; -+ if( has_trait( trait_THRESH_VAMP ) ) { -+ 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 -@@ -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 @@ - static const trait_id trait_NOPAIN( "NOPAIN" ); - static const trait_id trait_SEESLEEP( "SEESLEEP" ); - static const trait_id trait_SCHIZOPHRENIC( "SCHIZOPHRENIC" ); -+static const trait_id trait_THRESH_GYNOID( "THRESH_GYNOID" ); - static const trait_id trait_THRESH_MYCUS( "THRESH_MYCUS" ); -+static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" ); - static const trait_id trait_WATERSLEEP( "WATERSLEEP" ); - - static void eff_fun_onfire( player &u, effect &it ) -@@ -1095,6 +1097,11 @@ - // 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"; -+ } else if( has_trait( trait_THRESH_GYNOID ) ) { -+ highcat = "GYNOID"; -+ } - 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" ) ) { -@@ -742,7 +746,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(); - } - -@@ -768,6 +773,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 Character::bodypart_exposure() -@@ -799,7 +811,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; - } - -@@ -816,6 +829,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. -@@ -893,7 +912,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 &bp_exp : bp_exposure ) { - ---- a/data/json/field_type.json -+++ b/data/json/field_type.json -@@ -303,7 +303,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": [ "THRESH_VAMP" ] }, - "priority": 8, - "half_life": "2 minutes", - "phase": "gas", -@@ -389,7 +389,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": [ "THRESH_VAMP" ] }, - "priority": 8, - "half_life": "10 minutes", - "phase": "gas", -@@ -418,7 +418,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": [ "THRESH_VAMP" ] }, - "priority": 8, - "half_life": "5 minutes", - "phase": "gas", -@@ -464,7 +464,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": [ "THRESH_VAMP" ] }, - "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": [ "THRESH_VAMP" ] }, - "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": [ "THRESH_VAMP" ] }, - "priority": 8, - "half_life": "15 minutes", - "phase": "gas", -@@ -1233,7 +1233,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": [ "THRESH_VAMP" ] }, - "priority": 8, - "half_life": "10 minutes", - "phase": "gas" -@@ -1253,7 +1253,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": [ "THRESH_VAMP" ] }, - "priority": 8, - "half_life": "30 minutes", - "phase": "gas", -@@ -1275,7 +1275,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": [ "THRESH_VAMP" ] }, - "priority": 8, - "half_life": "30 minutes", - "phase": "gas", - ---- a/data/json/flags.json -+++ b/data/json/flags.json -@@ -1093,6 +1093,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" ] -@@ -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 @@ - "TROGLO2", - "TROGLO3", - "URSINE_FUR", -+ "VAMP_SKIN", - "VISCOUS" - ], - "order": 1500 diff --git a/npc-01_dialogue-fixes.patch b/npc-01_dialogue-fixes.patch new file mode 100644 index 0000000..a7aaaa2 --- /dev/null +++ b/npc-01_dialogue-fixes.patch @@ -0,0 +1,23 @@ +--- a/data/json/npcs/isherwood_farm/NPC_Lisa_Isherwood.json ++++ b/data/json/npcs/isherwood_farm/NPC_Lisa_Isherwood.json +@@ -84,7 +84,7 @@ + { + "type": "talk_topic", + "id": "TALK_ISHERWOOD_LISA_TALK1", +- "dynamic_line": "My family owns all the land around here, my parents are out in the barn and my other family is down he road.", ++ "dynamic_line": "My family owns all the land around here, my parents are out in the barn and my other family is down the road.", + "responses": [ + { "text": "Ok, I'll go find them.", "topic": "TALK_DONE" }, + { "text": "Let's talk about something else.", "topic": "TALK_ISHERWOOD_LISA_TOPICS" }, + +--- a/data/json/npcs/isherwood_farm/NPC_Jack_Isherwood.json ++++ b/data/json/npcs/isherwood_farm/NPC_Jack_Isherwood.json +@@ -179,7 +179,7 @@ + { + "type": "talk_topic", + "id": "TALK_ISHERWOOD_JACK_TALK1", +- "dynamic_line": "I live here with my wife, this is our family's land. My daughter's family and son live down the road.", ++ "dynamic_line": "I live here with my wife, this is our family's land. My daughter's family live down the road, and my brother-in-law with his son just past them.", + "responses": [ + { "text": "Your whole family survived?", "topic": "TALK_ISHERWOOD_JACK2" }, + { "text": "Let's talk about something else.", "topic": "TALK_ISHERWOOD_JACK_TOPICS" }, diff --git a/npc-02_isherwood-duplicate-mission.patch b/npc-02_isherwood-duplicate-mission.patch new file mode 100644 index 0000000..982aa7e --- /dev/null +++ b/npc-02_isherwood-duplicate-mission.patch @@ -0,0 +1,35 @@ +--- a/data/json/npcs/isherwood_farm/NPC_Jesse_Isherwood.json ++++ b/data/json/npcs/isherwood_farm/NPC_Jesse_Isherwood.json +@@ -222,32 +222,6 @@ + "origins": [ "ORIGIN_SECONDARY" ], + "has_generic_rewards": false, + "dialogue": { +- "describe": "We could use some help killing some wolves.", +- "offer": "There's been some wolves that keep scaring our chickens and horses, I'd be grateful if you can kill them.", +- "accepted": "Wonderful, let me know when it is done.", +- "rejected": "Thanks anyway, we will try some traps.", +- "advice": "A gun will probably help.", +- "inquire": "Did you kill it?", +- "success": "I appreciate it, I've got this old saddle I want you to have. I'll be happy to put a horse under it if you want to do some more heroics.", +- "success_lie": "Show me the bodies.", +- "failure": "It was a lost cause anyways…" +- }, +- "end": { "opinion": { "trust": 1, "value": 1 }, "effect": [ { "u_buy_item": "horse_tack", "count": 1 } ] } +- }, +- { +- "id": "MISSION_ISHERWOOD_JESSE_2", +- "type": "mission_definition", +- "name": { "str": "Kill monster" }, +- "goal": "MGOAL_KILL_MONSTER", +- "difficulty": 8, +- "value": 80000, +- "start": { +- "assign_mission_target": { "om_terrain": "forest_thick", "reveal_radius": 1, "random": true, "search_range": 20, "min_distance": 15 }, +- "update_mapgen": { "place_monster": [ { "monster": "mon_flying_polyp", "pack_size": [ 3, 6 ], "x": 11, "y": 11, "target": true } ] } +- }, +- "origins": [ "ORIGIN_SECONDARY" ], +- "has_generic_rewards": false, +- "dialogue": { + "describe": "We could use some help killing some monsters.", + "offer": "We could use some help killing a pack of monsters. I don't know what they are, but they're very fast, I'm willing to outfit you with a horse if you succeed.", + "accepted": "Be ready for anything.", diff --git a/terrain-01_quiverfull-house-correct-stairs.patch b/terrain-01_quiverfull-house-correct-stairs.patch deleted file mode 100644 index ad40706..0000000 --- a/terrain-01_quiverfull-house-correct-stairs.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/data/json/mapgen/house/house_quiverfull.json -+++ b/data/json/mapgen/house/house_quiverfull.json -@@ -29,7 +29,7 @@ - "%or E|R y| h F#.", - "%# + + O#.", - ".# |||R R|J 5o.", -- ".#HHsHH|< R|n 4o.", -+ ".#HHsHH|> R|n 4o.", - ".#|||||| |R R|JJ 123#.", - ".#q+ ||||+|||#.", - ".#q+ + d#.", diff --git a/tools-04_normalize-drone-volume.patch b/tools-04_normalize-drone-volume.patch index a45ebf0..6e3eb14 100644 --- a/tools-04_normalize-drone-volume.patch +++ b/tools-04_normalize-drone-volume.patch @@ -3,54 +3,54 @@ @@ -5,7 +5,7 @@ "name": { "str": "inactive EMP hack" }, "description": "This is an inactive EMP hack. EMP hacks are fist-sized robots that fly through the air. This one contains an EMP grenade and attacks by flying at its target and detonating. Use this item to reprogram and release the EMP hack. Electronics and computer skill determines if the targeting matrix is reprogrammed successfully.", - "weight": "4700 g", + "weight": "3750 g", - "volume": "750 ml", + "volume": "250 ml", "price": 64500, + "price_postapoc": 3000, "to_hit": -3, - "bashing": 6, @@ -31,7 +31,7 @@ "name": { "str": "inactive C-4 hack" }, "description": "This is an inactive C-4 hack. C-4 hacks are fist-sized robots that fly through the air. This one contains some C-4 and attacks by flying at its target and detonating. Use this item to reprogram and activate the C-4 hack. Electronics and computer skill determines if the targeting matrix is reprogrammed successfully.", - "weight": "5870 g", + "weight": "4920 g", - "volume": "250 ml", -+ "volume": "1000 ml", ++ "volume": "1 L", "price": 67500, + "price_postapoc": 3000, "to_hit": -3, - "bashing": 6, @@ -57,7 +57,7 @@ "name": { "str": "inactive flashbang hack" }, "description": "This is an inactive flashbang hack. Flashbang hacks are fist-sized robots that fly through the air. This one contains a flashbang and attacks by flying at its target and detonating. Use this item to reprogram and activate the flashbang hack. Electronics and computer skill determines if the targeting matrix is reprogrammed successfully.", - "weight": "4536 g", + "weight": "3590 g", - "volume": "750 ml", + "volume": "250 ml", "price": 59500, + "price_postapoc": 500, "to_hit": -3, - "bashing": 6, @@ -83,7 +83,7 @@ "name": { "str": "inactive tear gas hack" }, "description": "This is an inactive tear gas hack. Tear gas hacks are fist-sized robots that fly through the air. This one contains a tear gas canister and attacks by flying at its target and releasing tear gas. Use this item to reprogram and activate the tear gas hack. Electronics and computer skill determines if the targeting matrix is reprogrammed successfully.", - "weight": "5360 g", + "weight": "4410 g", - "volume": "750 ml", + "volume": "250 ml", "price": 60500, + "price_postapoc": 500, "to_hit": -3, - "bashing": 6, -@@ -179,7 +179,7 @@ +@@ -157,7 +157,7 @@ "name": { "str": "inactive manhack" }, "description": "This is an inactive manhack. Manhacks are fist-sized robots that fly through the air. They are covered with whirring blades and attack by throwing themselves against their target. Use this item to reprogram and activate the manhack. Electronics and computer skill determines if the targeting matrix is reprogrammed successfully.", - "weight": "5400 g", + "weight": "4450 g", - "volume": "750 ml", + "volume": "250 ml", "price": 60000, + "price_postapoc": 500, "to_hit": -3, - "bashing": 6, -@@ -205,7 +205,7 @@ +@@ -183,7 +183,7 @@ "name": { "str": "inactive mininuke hack" }, "description": "This is an inactive mininuke hack. Many times as large as a normal manhack, a mininuke hack contains a mininuke and attack by flying at their target and detonating. Use this item to reprogram and activate the mininuke hack. Electronics and computer skill determines if the targeting matrix is reprogrammed successfully.", - "weight": "25000 g", + "weight": "26370 g", - "volume": "18750 ml", -+ "volume": "16000 ml", ++ "volume": "16 L", "price": 2677500, + "price_postapoc": 10000, "to_hit": -3, - "bashing": 6, diff --git a/vampirism.patch b/vampirism.patch new file mode 100644 index 0000000..c7230eb --- /dev/null +++ b/vampirism.patch @@ -0,0 +1,677 @@ +--- 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 +@@ -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" ); +@@ -288,9 +288,11 @@ + static const trait_id trait_THRESH_INSECT( "THRESH_INSECT" ); + static const trait_id trait_THRESH_PLANT( "THRESH_PLANT" ); + static const trait_id trait_THRESH_SPIDER( "THRESH_SPIDER" ); ++static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" ); + 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_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(); +@@ -4545,6 +4547,7 @@ + const bool npc_no_food = is_npc() && get_option( "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 ); +@@ -4568,7 +4571,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 ); + } + } +@@ -4985,7 +4988,7 @@ + + void Character::update_bodytemp( const map &m, weather_manager &weather ) + { +- if( has_trait( trait_DEBUG_NOTEMP ) ) { ++ if( has_trait( trait_DEBUG_NOTEMP ) || has_trait( trait_THRESH_VAMP ) ) { + temp_cur.fill( BODYTEMP_NORM ); + 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,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" ); +@@ -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 carnivore_blacklist {{ + flag_ALLERGEN_VEGGY, flag_ALLERGEN_FRUIT, flag_ALLERGEN_WHEAT, flag_ALLERGEN_NUT, + } + }; ++const std::vector 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 temparray {{flag_ALLERGEN_MEAT, flag_ALLERGEN_EGG}}; +@@ -719,6 +726,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::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( 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 +@@ -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,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 +@@ -88,6 +88,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_THRESH_VAMP( "THRESH_VAMP" ); + static const trait_id trait_WEB_WALKER( "WEB_WALKER" ); + + void map::create_burnproducts( const tripoint &p, const item &fuel, const units::mass &burned_mass ) +@@ -1395,7 +1396,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_THRESH_VAMP ) ) && cur.get_field_intensity() > 1 && ( !inside || ++ one_in( 3 ) ) ) { + u.add_env_effect( effect_blind, bp_eyes, cur.get_field_intensity() * 2, 10_seconds ); + } + } +@@ -1526,8 +1528,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_THRESH_VAMP ) ) && !( 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 +@@ -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( "killer" ); + if( ch == g->u.getID() ) { + std::string name = e.get( "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/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_THRESH_VAMP( "THRESH_VAMP" ); + 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" ); +@@ -887,6 +888,11 @@ + if( !mutagen ) { + return; + } ++ if( has_trait( trait_THRESH_VAMP ) ) { ++ 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( mutagen.get_duration() ) / to_turns + ( mutagen.get_int_dur_factor() ); + add_msg_if_player( m_debug, "Mutation accumulation: %.1f", mut_power ); +@@ -926,6 +932,10 @@ + { + bool force_bad = one_in( 3 ); + bool force_good = false; ++ if( has_trait( trait_THRESH_VAMP ) ) { ++ 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 +@@ -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,6 +114,7 @@ + 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_WATERSLEEP( "WATERSLEEP" ); + + static void eff_fun_onfire( player &u, effect &it ) +@@ -1095,6 +1097,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 +@@ -143,10 +143,12 @@ + 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_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_VAMP ) ) { + oxygen--; + } + if( oxygen < 12 && worn_with_flag( "REBREATHER" ) ) { +@@ -742,7 +746,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(); + } + +@@ -768,6 +773,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 Character::bodypart_exposure() +@@ -799,7 +811,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; + } + +@@ -816,6 +829,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. +@@ -893,7 +912,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 &bp_exp : bp_exposure ) { + +--- a/data/json/field_type.json ++++ b/data/json/field_type.json +@@ -303,7 +303,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": [ "THRESH_VAMP" ] }, + "priority": 8, + "half_life": "2 minutes", + "phase": "gas", +@@ -389,7 +389,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": [ "THRESH_VAMP" ] }, + "priority": 8, + "half_life": "10 minutes", + "phase": "gas", +@@ -418,7 +418,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": [ "THRESH_VAMP" ] }, + "priority": 8, + "half_life": "5 minutes", + "phase": "gas", +@@ -464,7 +464,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": [ "THRESH_VAMP" ] }, + "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": [ "THRESH_VAMP" ] }, + "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": [ "THRESH_VAMP" ] }, + "priority": 8, + "half_life": "15 minutes", + "phase": "gas", +@@ -1233,7 +1233,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": [ "THRESH_VAMP" ] }, + "priority": 8, + "half_life": "10 minutes", + "phase": "gas" +@@ -1253,7 +1253,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": [ "THRESH_VAMP" ] }, + "priority": 8, + "half_life": "30 minutes", + "phase": "gas", +@@ -1275,7 +1275,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": [ "THRESH_VAMP" ] }, + "priority": 8, + "half_life": "30 minutes", + "phase": "gas", + +--- a/data/json/flags.json ++++ b/data/json/flags.json +@@ -1093,6 +1093,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" ] +@@ -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 @@ + "TROGLO2", + "TROGLO3", + "URSINE_FUR", ++ "VAMP_SKIN", + "VISCOUS" + ], + "order": 1500 -- cgit v1.2.1