--- 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/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/suffer.cpp +++ b/src/suffer.cpp @@ -118,6 +118,8 @@ static const trait_id trait_FRESHWATEROSMOSIS( "FRESHWATEROSMOSIS" ); static const trait_id trait_GILLS( "GILLS" ); static const trait_id trait_GILLS_CEPH( "GILLS_CEPH" ); +static const trait_id trait_THRESH_GYNOID( "THRESH_GYNOID" ); +static const trait_id trait_THRESH_VAMP( "THRESH_VAMP" ); static const trait_id trait_JITTERY( "JITTERY" ); static const trait_id trait_KILLER( "KILLER" ); static const trait_id trait_LEAVES( "LEAVES" ); @@ -245,7 +247,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" ) ) { --- 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/src/monattack.cpp +++ b/src/monattack.cpp @@ -143,6 +143,7 @@ static const trait_id trait_TAIL_CATTLE( "TAIL_CATTLE" ); 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 mtype_id mon_ant_acid_larva( "mon_ant_acid_larva" ); static const mtype_id mon_ant_acid_queen( "mon_ant_acid_queen" ); @@ -2758,6 +2759,9 @@ damage_instance dam = damage_instance(); dam.add_damage( DT_STAB, 6, 10, 0.6, 1 ); bool hit = sting_shoot( z, target, dam, range ); + if( target->has_trait( trait_THRESH_VAMP ) ) { + return true; + } if( hit ) { //Add checks if previous NPC/player conditions are removed dynamic_cast( target )->mutate(); --- 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 --- 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