From db37efe49b2e97389617ed19e41c62fb0ac3d910 Mon Sep 17 00:00:00 2001 From: nexusmrsep <39925111+nexusmrsep@users.noreply.github.com> Date: Tue, 7 Dec 2021 20:07:45 +0100 Subject: [PATCH] First aid proficiencies (#53048) Co-authored-by: Kevin Granade --- data/json/hobbies.json | 3 +- data/json/items/book/firstaid.json | 8 +++ data/json/items/comestibles/med.json | 36 ++++++------- data/json/professions.json | 8 ++- data/json/proficiencies/health_care.json | 23 +++++++++ data/json/recipes/practice/health.json | 51 +++++++++++++++++++ .../bionic_professions.json | 4 +- doc/PROFICIENCY_LIST.md | 3 ++ src/character.cpp | 10 +++- src/game.cpp | 8 ++- src/iuse_actor.cpp | 42 +++++++++++---- src/player_hardcoded_effects.cpp | 9 +++- 12 files changed, 168 insertions(+), 37 deletions(-) create mode 100644 data/json/proficiencies/health_care.json create mode 100644 data/json/recipes/practice/health.json diff --git a/data/json/hobbies.json b/data/json/hobbies.json index bcea218930429..8555481144ccb 100644 --- a/data/json/hobbies.json +++ b/data/json/hobbies.json @@ -551,7 +551,8 @@ "id": "redcross", "description": "You've got training and some experience in dealing with urgent injuries. In the absence of any medical professionals, that'll have to do.", "points": 1, - "skills": [ { "level": 2, "name": "firstaid" } ] + "skills": [ { "level": 2, "name": "firstaid" } ], + "proficiencies": [ "prof_wound_care" ] }, { "type": "profession", diff --git a/data/json/items/book/firstaid.json b/data/json/items/book/firstaid.json index 4b2148aeb53c4..0b6acbcd74c31 100644 --- a/data/json/items/book/firstaid.json +++ b/data/json/items/book/firstaid.json @@ -16,6 +16,7 @@ "required_level": 5, "max_level": 8, "intelligence": 10, + "proficiencies": [ { "proficiency": "prof_wound_care_expert", "time_factor": 0.75, "fail_factor": 0.5 } ], "time": "55 m", "fun": -1 }, @@ -35,6 +36,7 @@ "skill": "firstaid", "max_level": 1, "intelligence": 6, + "proficiencies": [ { "proficiency": "prof_wound_care", "time_factor": 0.75, "fail_factor": 0.5 } ], "time": "8 m", "fun": 1 }, @@ -54,6 +56,10 @@ "skill": "firstaid", "max_level": 3, "intelligence": 8, + "proficiencies": [ + { "proficiency": "prof_wound_care", "time_factor": 0.75, "fail_factor": 0.5 }, + { "proficiency": "prof_wound_care_expert", "time_factor": 0.75, "fail_factor": 0.5 } + ], "time": "20 m" }, { @@ -71,6 +77,7 @@ "skill": "firstaid", "max_level": 2, "intelligence": 6, + "proficiencies": [ { "proficiency": "prof_wound_care", "time_factor": 0.75, "fail_factor": 0.5 } ], "time": "20 m" }, { @@ -91,6 +98,7 @@ "required_level": 3, "max_level": 6, "intelligence": 8, + "proficiencies": [ { "proficiency": "prof_wound_care_expert", "time_factor": 0.75, "fail_factor": 0.5 } ], "time": "30 m" }, { diff --git a/data/json/items/comestibles/med.json b/data/json/items/comestibles/med.json index 8e0e4c0ab343e..f8d8b5a6a168d 100644 --- a/data/json/items/comestibles/med.json +++ b/data/json/items/comestibles/med.json @@ -58,7 +58,7 @@ "color": "white", "charges": 10, "flags": [ "NO_INGEST", "EDIBLE_FROZEN" ], - "use_action": { "type": "heal", "bandages_power": 1, "bleed": 4, "move_cost": 200 } + "use_action": { "type": "heal", "bandages_power": 1, "bleed": 4, "move_cost": 750 } }, { "id": "adrenaline_injector", @@ -178,7 +178,7 @@ "charges": 3, "stack_size": 9, "flags": [ "NO_INGEST", "EDIBLE_FROZEN" ], - "use_action": { "type": "heal", "bandages_power": 4, "bleed": 15, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 4, "bleed": 15, "move_cost": 6000 } }, { "id": "bandages_makeshift", @@ -188,7 +188,7 @@ "description": "Simple cloth bandages. Better than nothing.", "price_postapoc": 100, "flags": [ "NO_INGEST", "EDIBLE_FROZEN" ], - "use_action": { "type": "heal", "bandages_power": 2, "bleed": 10, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 2, "bleed": 10, "move_cost": 6000 } }, { "id": "bandages_makeshift_bleached", @@ -198,7 +198,7 @@ "description": "Simple cloth bandages. It is white, as real bandages should be.", "price_postapoc": 150, "flags": [ "NO_INGEST", "EDIBLE_FROZEN" ], - "use_action": { "type": "heal", "bandages_power": 3, "bleed": 10, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 3, "bleed": 10, "move_cost": 6000 } }, { "id": "bandages_makeshift_boiled", @@ -208,7 +208,7 @@ "description": "Simple cloth bandages. It was boiled to make it more sterile.", "price_postapoc": 150, "flags": [ "NO_INGEST", "EDIBLE_FROZEN" ], - "use_action": { "type": "heal", "bandages_power": 3, "bleed": 10, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 3, "bleed": 10, "move_cost": 6000 } }, { "id": "bfipowder", @@ -219,7 +219,7 @@ "weight": "6 g", "volume": "250 ml", "price": 900, - "price_postapoc": 4000, + "price_postapoc": 2000, "charges": 4, "stack_size": 40, "material": [ "powder" ], @@ -227,7 +227,7 @@ "color": "white", "container": "bottle_plastic_small", "flags": [ "NO_INGEST", "IRREPLACEABLE_CONSUMABLE", "WATER_DISSOLVE", "EDIBLE_FROZEN" ], - "use_action": { "type": "heal", "disinfectant_power": 4, "bite": 0.95, "move_cost": 100 } + "use_action": { "type": "heal", "disinfectant_power": 4, "bite": 0.95, "move_cost": 2000 } }, { "id": "caff_gum", @@ -312,7 +312,7 @@ "phase": "liquid", "container": "bottle_plastic_small", "flags": [ "NO_INGEST", "WATER_DISSOLVE" ], - "use_action": { "type": "heal", "disinfectant_power": 4, "bite": 0.95, "move_cost": 100 } + "use_action": { "type": "heal", "disinfectant_power": 4, "bite": 0.95, "move_cost": 2000 } }, { "id": "cig", @@ -487,7 +487,7 @@ "color": "white", "container": "bag_plastic", "flags": [ "NO_INGEST", "EDIBLE_FROZEN" ], - "use_action": { "type": "heal", "bandages_power": 2, "bleed": 3, "move_cost": 300 } + "use_action": { "type": "heal", "bandages_power": 2, "bleed": 3, "move_cost": 3000 } }, { "id": "crack", @@ -555,7 +555,7 @@ "phase": "liquid", "container": "bottle_plastic_small", "flags": [ "NO_INGEST", "IRREPLACEABLE_CONSUMABLE", "WATER_DISSOLVE" ], - "use_action": { "type": "heal", "disinfectant_power": 4, "bite": 0.95, "move_cost": 100 } + "use_action": { "type": "heal", "disinfectant_power": 4, "bite": 0.95, "move_cost": 3000 } }, { "id": "disinfectant_makeshift", @@ -565,7 +565,7 @@ "copy-from": "disinfectant", "description": "Makeshift antiseptic made from ethanol. Can be used to disinfect a wound.", "flags": [ "NO_INGEST", "WATER_DISSOLVE" ], - "use_action": { "type": "heal", "disinfectant_power": 3, "bite": 0.95, "move_cost": 100 } + "use_action": { "type": "heal", "disinfectant_power": 3, "bite": 0.95, "move_cost": 3000 } }, { "id": "alcohol_wipes", @@ -1205,7 +1205,7 @@ "symbol": ",", "color": "white", "flags": [ "NO_INGEST", "EDIBLE_FROZEN" ], - "use_action": { "type": "heal", "bandages_power": 4, "bleed": 5, "move_cost": 200 } + "use_action": { "type": "heal", "bandages_power": 4, "bleed": 5, "move_cost": 6000 } }, { "id": "meth", @@ -1556,7 +1556,7 @@ "color": "light_gray", "container": "bag_plastic", "flags": [ "NO_INGEST", "IRREPLACEABLE_CONSUMABLE", "WATER_DISSOLVE", "EDIBLE_FROZEN" ], - "use_action": { "type": "heal", "bleed": 20, "move_cost": 100 } + "use_action": { "type": "heal", "bleed": 20, "move_cost": 2000 } }, { "id": "saline", @@ -1611,7 +1611,7 @@ "phase": "liquid", "spoils_in": "28 days", "flags": [ "NO_INGEST" ], - "use_action": { "type": "heal", "disinfectant_power": 3, "bite": 0.95, "move_cost": 100 } + "use_action": { "type": "heal", "disinfectant_power": 3, "bite": 0.95, "move_cost": 3000 } }, { "id": "tobacco", @@ -1942,7 +1942,7 @@ "type": "heal", "disinfectant_power": 2, "bite": 0.5, - "move_cost": 200, + "move_cost": 6000, "used_up_item": { "id": "rag", "quantity": 1, "flags": [ "FILTHY" ] } } }, @@ -1966,7 +1966,7 @@ "type": "heal", "disinfectant_power": 3, "bite": 0.66, - "move_cost": 300, + "move_cost": 6000, "used_up_item": { "id": "cotton_ball", "quantity": 1, "charges": 1, "flags": [ "FILTHY" ] } } }, @@ -2056,7 +2056,7 @@ "type": "heal", "disinfectant_power": 3, "bite": 0.75, - "move_cost": 100, + "move_cost": 3000, "effects": [ { "id": "pkill1", "duration": 720 } ] } }, @@ -2098,6 +2098,6 @@ "addiction_potential": 5, "addiction_type": "cocaine", "flags": [ "NO_INGEST", "WATER_DISSOLVE" ], - "use_action": { "type": "heal", "bleed": 20, "move_cost": 100, "effects": [ { "id": "pkill1", "duration": 720 } ] } + "use_action": { "type": "heal", "bleed": 20, "move_cost": 3000, "effects": [ { "id": "pkill1", "duration": 720 } ] } } ] diff --git a/data/json/professions.json b/data/json/professions.json index ae1caabbc148e..35814740f7496 100644 --- a/data/json/professions.json +++ b/data/json/professions.json @@ -1149,6 +1149,7 @@ "description": "Fresh out of med school, you've got little in the way of practical experience and just a handful of first-aid supplies. You just hope it will be enough if 'physician, heal thyself' turns out to be more literal than you expected.", "points": 2, "skills": [ { "level": 4, "name": "firstaid" } ], + "proficiencies": [ "prof_wound_care", "prof_wound_care_expert" ], "traits": [ "PROF_MED" ], "items": { "both": { @@ -1258,6 +1259,7 @@ "description": "You went on providing in-home care for the elderly even as the whole world fell apart around you. You can only pray that you don't see your former clients among the walking dead…", "points": 1, "skills": [ { "level": 2, "name": "firstaid" }, { "level": 1, "name": "cooking" } ], + "proficiencies": [ "prof_wound_care" ], "items": { "both": [ "pants", @@ -1839,6 +1841,7 @@ "description": "On your way to respond to an emergency call, you nearly drove straight into a riot in the city. Turning off of the burning, debris-covered streets, you took a long detour only to find yourself lost. That call will have to wait - you're in an emergency of your own now.", "points": 5, "skills": [ { "level": 3, "name": "firstaid" }, { "level": 3, "name": "driving" }, { "level": 1, "name": "electronics" } ], + "proficiencies": [ "prof_wound_care" ], "vehicle": "fire_engine", "items": { "both": { @@ -3795,6 +3798,7 @@ { "level": 1, "name": "electronics" }, { "level": 3, "name": "firstaid" } ], + "proficiencies": [ "prof_wound_care", "prof_wound_care_expert" ], "traits": [ "PROF_MED" ], "vehicle": "ambulance", "items": { @@ -3813,6 +3817,7 @@ "description": "You were separated from your partner while out on a call. You managed to hang onto some medical supplies, but it's looking like the only life that needs saving now is yours.", "points": 3, "skills": [ { "level": 2, "name": "driving" }, { "level": 1, "name": "mechanics" }, { "level": 5, "name": "firstaid" } ], + "proficiencies": [ "prof_wound_care", "prof_wound_care_expert" ], "traits": [ "PROF_MED" ], "items": { "both": { @@ -3852,7 +3857,7 @@ { "level": 4, "name": "firstaid" } ], "traits": [ "PROF_MED" ], - "proficiencies": [ "prof_spotting" ], + "proficiencies": [ "prof_spotting", "prof_wound_care", "prof_wound_care_expert" ], "items": { "both": { "items": [ @@ -4005,6 +4010,7 @@ "description": "You were deployed to autopsy one of the rioters showing feral behavior before being put down. When they got back up, you knew this was out of your job description.", "points": 5, "skills": [ { "level": 5, "name": "firstaid" } ], + "proficiencies": [ "prof_wound_care", "prof_wound_care_expert" ], "traits": [ "PROF_MED" ], "items": { "both": { diff --git a/data/json/proficiencies/health_care.json b/data/json/proficiencies/health_care.json new file mode 100644 index 0000000000000..e774e6260aa3f --- /dev/null +++ b/data/json/proficiencies/health_care.json @@ -0,0 +1,23 @@ +[ + { + "type": "proficiency", + "id": "prof_wound_care", + "name": { "str": "Wound Care" }, + "description": "You know how to bandage wounds and understand basic principles of wound care.", + "can_learn": true, + "default_time_multiplier": 2, + "default_fail_multiplier": 1.5, + "time_to_learn": "2 h" + }, + { + "type": "proficiency", + "id": "prof_wound_care_expert", + "name": { "str": "Wound Care Expert" }, + "description": "Your extensive field experience in bandaging and wound care is on par with that of a paramedic.", + "can_learn": true, + "default_time_multiplier": 2, + "default_fail_multiplier": 1.25, + "time_to_learn": "14 h", + "required_proficiencies": [ "prof_firstaid" ] + } +] diff --git a/data/json/recipes/practice/health.json b/data/json/recipes/practice/health.json new file mode 100644 index 0000000000000..c7268fcbeacb7 --- /dev/null +++ b/data/json/recipes/practice/health.json @@ -0,0 +1,51 @@ +[ + { + "id": "prac_health_care_beg", + "type": "practice", + "activity_level": "NO_EXERCISE", + "category": "CC_PRACTICE", + "subcategory": "CSC_PRACTICE_HEALTH", + "name": "bandaging (beginner)", + "description": "Practice bandaging imaginary wounds while making sure your bandage won't fall off during activities.", + "skill_used": "firstaid", + "time": "1 h", + "practice_data": { "min_difficulty": 0, "max_difficulty": 1, "skill_limit": 1 }, + "proficiencies": [ { "proficiency": "prof_wound_care", "fail_multiplier": 1, "time_multiplier": 1 } ], + "autolearn": [ [ "firstaid", 0 ] ], + "flags": [ "BLIND_HARD" ], + "components": [ + [ + [ "bandages", 1 ], + [ "bandages_makeshift", 1 ], + [ "bandages_makeshift_bleached", 1 ], + [ "bandages_makeshift_boiled", 1 ] + ] + ], + "byproducts": [ [ "rag", 1 ] ] + }, + { + "id": "prac_health_care_int", + "type": "practice", + "activity_level": "NO_EXERCISE", + "category": "CC_PRACTICE", + "subcategory": "CSC_PRACTICE_HEALTH", + "name": "bandaging (advanced)", + "description": "Practice bandaging different limbs and less accessible parts of your body using both hands and each of your hands alone.", + "skill_used": "firstaid", + "time": "1 h", + "practice_data": { "min_difficulty": 1, "max_difficulty": 2, "skill_limit": 3 }, + "proficiencies": [ { "proficiency": "prof_wound_care_expert", "fail_multiplier": 1, "time_multiplier": 1 } ], + "autolearn": [ [ "firstaid", 1 ] ], + "flags": [ "BLIND_HARD" ], + "book_learn": [ [ "booklet_firstaid", 0 ], [ "mag_firstaid", 0 ], [ "pocket_firstaid", 0 ], [ "manual_first_aid", 0 ] ], + "components": [ + [ + [ "bandages", 2 ], + [ "bandages_makeshift", 2 ], + [ "bandages_makeshift_bleached", 2 ], + [ "bandages_makeshift_boiled", 2 ] + ] + ], + "byproducts": [ [ "rag", 2 ] ] + } +] diff --git a/data/mods/package_bionic_professions/bionic_professions.json b/data/mods/package_bionic_professions/bionic_professions.json index 645c2521d6d06..2a8008b3327b9 100644 --- a/data/mods/package_bionic_professions/bionic_professions.json +++ b/data/mods/package_bionic_professions/bionic_professions.json @@ -243,7 +243,7 @@ "description": "When bionics first emerged, you were quick to make them into your career, and spent your days overseeing their installation. That makes you one of the few non-zombies in the world that can calibrate an Autodoc, which might come in handy.", "points": 4, "skills": [ { "level": 4, "name": "firstaid" }, { "level": 4, "name": "electronics" } ], - "proficiencies": [ "prof_intro_biology", "prof_physiology" ], + "proficiencies": [ "prof_intro_biology", "prof_physiology", "prof_wound_care" ], "traits": [ "PROF_AUTODOC" ], "items": { "both": { @@ -274,7 +274,7 @@ "points": 6, "CBMs": [ "bio_surgical_razor", "bio_flashlight", "bio_batteries", "bio_power_storage_mkII" ], "skills": [ { "level": 8, "name": "firstaid" } ], - "proficiencies": [ "prof_intro_biology", "prof_physiology" ], + "proficiencies": [ "prof_intro_biology", "prof_physiology", "prof_wound_care", "prof_wound_care_expert" ], "traits": [ "PROF_MED" ], "items": { "both": { diff --git a/doc/PROFICIENCY_LIST.md b/doc/PROFICIENCY_LIST.md index 0dc06e3a82f13..c499006cb92d0 100644 --- a/doc/PROFICIENCY_LIST.md +++ b/doc/PROFICIENCY_LIST.md @@ -124,6 +124,9 @@ | prof_spotting | Spotting and Awareness | You are skilled at spotting things out of the ordinary, like traps or ambushes. | None | | | prof_parkour | Parkour Expert | You're skilled at clearing obstacles; terrain like railings or counters are as easy for you to move on as solid ground. | None +| | +| prof_wound_care | Wound Care | You know how to bandage wounds and understand basic principles of wound care. | None +| prof_wound_care_expert | Wound Care Expert | Your extensive field experience in bandaging and wound care is on par with that of a paramedic. | prof_wound_care ## Magiclysm proficiencies diff --git a/src/character.cpp b/src/character.cpp index 3443cd76f1c4c..4fa00058b558c 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -340,6 +340,8 @@ static const proficiency_id proficiency_prof_parkour( "prof_parkour" ); static const proficiency_id proficiency_prof_spotting( "prof_spotting" ); static const proficiency_id proficiency_prof_traps( "prof_traps" ); static const proficiency_id proficiency_prof_trapsetting( "prof_trapsetting" ); +static const proficiency_id proficiency_prof_wound_care( "prof_wound_care" ); +static const proficiency_id proficiency_prof_wound_care_expert( "prof_wound_care_expert" ); static const quality_id qual_HAMMER( "HAMMER" ); static const quality_id qual_LIFT( "LIFT" ); @@ -11169,8 +11171,12 @@ void Character::pause() for( const bodypart_id &part : get_all_body_parts_of_type( body_part_type::type::hand ) ) { total_hand_encumb += encumb( part ); } + // proficiency bonus is equal to having extra levels of firstaid skill (up to +3) + int prof_bonus = get_skill_level( skill_firstaid ); + prof_bonus = has_proficiency( proficiency_prof_wound_care ) ? prof_bonus + 1 : prof_bonus; + prof_bonus = has_proficiency( proficiency_prof_wound_care_expert ) ? prof_bonus + 2 : prof_bonus; time_duration penalty = 1_turns * total_hand_encumb; - time_duration benefit = 5_turns + 10_turns * get_skill_level( skill_firstaid ); + time_duration benefit = 5_turns + 10_turns * prof_bonus; bool broken_arm = false; for( const bodypart_id &part : get_all_body_parts_of_type( body_part_type::type::arm ) ) { @@ -11195,6 +11201,8 @@ void Character::pause() _( "You attempt to put pressure on the bleeding wound!" ), _( " attempts to put pressure on the bleeding wound!" ) ); practice( skill_firstaid, 1 ); + practice_proficiency( proficiency_prof_wound_care, 1_turns ); + practice_proficiency( proficiency_prof_wound_care_expert, 1_turns ); } } // on-pause effects for martial arts diff --git a/src/game.cpp b/src/game.cpp index b652e8cfbf353..fb45bbf44efaa 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -252,6 +252,8 @@ static const mtype_id mon_manhack( "mon_manhack" ); static const overmap_special_id overmap_special_world( "world" ); static const proficiency_id proficiency_prof_parkour( "prof_parkour" ); +static const proficiency_id proficiency_prof_wound_care( "prof_wound_care" ); +static const proficiency_id proficiency_prof_wound_care_expert( "prof_wound_care_expert" ); static const quality_id qual_BUTCHER( "BUTCHER" ); static const quality_id qual_CUT_FINE( "CUT_FINE" ); @@ -5099,9 +5101,11 @@ bool game::npc_menu( npc &who ) } } else if( choice == examine_wounds ) { ///\EFFECT_PER slightly increases precision when examining NPCs' wounds - ///\EFFECT_FIRSTAID increases precision when examining NPCs' wounds - const bool precise = u.get_skill_level( skill_firstaid ) * 4 + u.per_cur >= 20; + int prof_bonus = u.get_skill_level( skill_firstaid ); + prof_bonus = u.has_proficiency( proficiency_prof_wound_care ) ? prof_bonus + 1 : prof_bonus; + prof_bonus = u.has_proficiency( proficiency_prof_wound_care_expert ) ? prof_bonus + 2 : prof_bonus; + const bool precise = prof_bonus * 4 + u.per_cur >= 20; who.body_window( _( "Limbs of: " ) + who.disp_name(), true, precise, 0, 0, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f ); } else if( choice == use_item ) { diff --git a/src/iuse_actor.cpp b/src/iuse_actor.cpp index 045e8c48e7273..474c39ad32f1b 100644 --- a/src/iuse_actor.cpp +++ b/src/iuse_actor.cpp @@ -126,6 +126,8 @@ static const mutation_category_id mutation_category_ELFA( "ELFA" ); static const proficiency_id proficiency_prof_traps( "prof_traps" ); static const proficiency_id proficiency_prof_trapsetting( "prof_trapsetting" ); +static const proficiency_id proficiency_prof_wound_care( "prof_wound_care" ); +static const proficiency_id proficiency_prof_wound_care_expert( "prof_wound_care_expert" ); static const quality_id qual_DIG( "DIG" ); @@ -3339,17 +3341,14 @@ cata::optional heal_actor::use( Character &p, item &it, bool, const tripoin return cata::nullopt; } + // each tier of proficiency cuts requred time by half int cost = move_cost; - if( long_action ) { - // A hack: long action healing on NPCs isn't done yet. - // So just heal at start and paralyze the player for 5 minutes. - cost /= std::min( 10, p.get_skill_level( skill_firstaid ) + 1 ); - } + cost = p.has_proficiency( proficiency_prof_wound_care_expert ) ? cost / 2 : cost; + cost = p.has_proficiency( proficiency_prof_wound_care ) ? cost / 2 : cost; // NPCs can use first aid now, but they can't perform long actions if( long_action && &patient == &p && !p.is_npc() ) { // Assign first aid long action. - /** @EFFECT_FIRSTAID speeds up firstaid activity */ p.assign_activity( ACT_FIRSTAID, cost, 0, 0, it.tname() ); p.activity.targets.emplace_back( p, &it ); p.activity.str_values.emplace_back( hpp.c_str() ); @@ -3393,8 +3392,13 @@ int heal_actor::get_heal_value( const Character &healer, bodypart_id healed ) co int heal_actor::get_bandaged_level( const Character &healer ) const { if( bandages_power > 0 ) { + int prof_bonus = healer.get_skill_level( skill_firstaid ); + prof_bonus = healer.has_proficiency( proficiency_prof_wound_care ) ? + prof_bonus + 1 : prof_bonus; + prof_bonus = healer.has_proficiency( proficiency_prof_wound_care_expert ) ? + prof_bonus + 2 : prof_bonus; /** @EFFECT_FIRSTAID increases healing item effects */ - return bandages_power + bandages_scaling * healer.get_skill_level( skill_firstaid ); + return bandages_power + bandages_scaling * prof_bonus; } return bandages_power; @@ -3404,7 +3408,12 @@ int heal_actor::get_disinfected_level( const Character &healer ) const { if( disinfectant_power > 0 ) { /** @EFFECT_FIRSTAID increases healing item effects */ - return disinfectant_power + disinfectant_scaling * healer.get_skill_level( skill_firstaid ); + int prof_bonus = healer.get_skill_level( skill_firstaid ); + prof_bonus = healer.has_proficiency( proficiency_prof_wound_care ) ? + prof_bonus + 1 : prof_bonus; + prof_bonus = healer.has_proficiency( proficiency_prof_wound_care_expert ) ? + prof_bonus + 2 : prof_bonus; + return disinfectant_power + disinfectant_scaling * prof_bonus; } return disinfectant_power; @@ -3414,7 +3423,12 @@ int heal_actor::get_stopbleed_level( const Character &healer ) const { if( bleed > 0 ) { /** @EFFECT_FIRSTAID increases healing item effects */ - return bleed + healer.get_skill_level( skill_firstaid ) / 2; + int prof_bonus = healer.get_skill_level( skill_firstaid ) / 2; + prof_bonus = healer.has_proficiency( proficiency_prof_wound_care ) ? + prof_bonus + 1 : prof_bonus; + prof_bonus = healer.has_proficiency( proficiency_prof_wound_care_expert ) ? + prof_bonus + 2 : prof_bonus; + return bleed + prof_bonus; } return bleed; @@ -3547,6 +3561,10 @@ int heal_actor::finish_using( Character &healer, Character &patient, item &it, practice_amount = std::max( 9.0f, practice_amount ); healer.practice( skill_firstaid, static_cast( practice_amount ) ); + healer.practice_proficiency( proficiency_prof_wound_care, + time_duration::from_turns( practice_amount ) ); + healer.practice_proficiency( proficiency_prof_wound_care_expert, + time_duration::from_turns( practice_amount ) ); return it.type->charges_to_use(); } @@ -3563,9 +3581,11 @@ static bodypart_id pick_part_to_heal( const bool precise = &healer == &patient ? patient.has_trait( trait_SELFAWARE ) : /** @EFFECT_PER slightly increases precision when using first aid on someone else */ - /** @EFFECT_FIRSTAID increases precision when using first aid on someone else */ - ( healer.get_skill_level( skill_firstaid ) * 4 + healer.per_cur >= 20 ); + ( ( healer.get_skill_level( skill_firstaid ) + + ( healer.has_proficiency( proficiency_prof_wound_care ) ? 0 : 1 ) + + ( healer.has_proficiency( proficiency_prof_wound_care ) ? 0 : 2 ) ) * 4 + + healer.per_cur >= 20 ); while( true ) { bodypart_id healed_part = patient.body_window( menu_header, force, precise, limb_power, head_bonus, torso_bonus, diff --git a/src/player_hardcoded_effects.cpp b/src/player_hardcoded_effects.cpp index d83b8f0fb9538..3135f044f09cc 100644 --- a/src/player_hardcoded_effects.cpp +++ b/src/player_hardcoded_effects.cpp @@ -108,6 +108,9 @@ static const mutation_category_id mutation_category_MYCUS( "MYCUS" ); static const mutation_category_id mutation_category_RAT( "RAT" ); static const mutation_category_id mutation_category_TROGLOBITE( "TROGLOBITE" ); +static const proficiency_id proficiency_prof_wound_care( "prof_wound_care" ); +static const proficiency_id proficiency_prof_wound_care_expert( "prof_wound_care_expert" ); + static const trait_id trait_CHLOROMORPH( "CHLOROMORPH" ); static const trait_id trait_HEAVYSLEEPER( "HEAVYSLEEPER" ); static const trait_id trait_HEAVYSLEEPER2( "HEAVYSLEEPER2" ); @@ -266,8 +269,12 @@ static void eff_fun_bleed( Character &u, effect &it ) // QuikClot or bandages per the recipe.) const int intense = it.get_intensity(); // tourniquet reduces effective bleeding by 2/3 but doesn't modify the effect's intensity + // proficiency improves that factor to 3/4 and 4/5 respectively bool tourniquet = u.worn_with_flag( STATIC( flag_id( "TOURNIQUET" ) ), it.get_bp() ); - if( !( tourniquet && one_in( 3 ) ) && u.activity.id() != ACT_FIRSTAID ) { + int prof_bonus = 3; + prof_bonus = u.has_proficiency( proficiency_prof_wound_care ) ? prof_bonus + 1 : prof_bonus; + prof_bonus = u.has_proficiency( proficiency_prof_wound_care_expert ) ? prof_bonus + 1 : prof_bonus; + if( !( tourniquet && one_in( prof_bonus ) ) && u.activity.id() != ACT_FIRSTAID ) { // Prolonged hemorrhage is a significant risk for developing anemia u.vitamin_mod( vitamin_redcells, -intense ); u.vitamin_mod( vitamin_blood, -intense );