From fcc0290236fff75b396b583c7e6dfccb19819a64 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 15 Jan 2025 00:32:06 -0600 Subject: [PATCH 01/28] Update monster_drops.json --- data/mods/Xedra_Evolved/itemgroups/monster_drops.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/data/mods/Xedra_Evolved/itemgroups/monster_drops.json b/data/mods/Xedra_Evolved/itemgroups/monster_drops.json index a49f5bc2f8300..22f56ff555b86 100644 --- a/data/mods/Xedra_Evolved/itemgroups/monster_drops.json +++ b/data/mods/Xedra_Evolved/itemgroups/monster_drops.json @@ -303,7 +303,7 @@ "id": "renfield_9mm_death_drops", "entries": [ { - "distribution": [ + "collection": [ { "item": "glock17_17", "prob": 100, "damage": [ 1, 3 ] }, { "group": "renfield_glock_mags", "prob": 40 }, { "item": "scrap_dreamdross", "prob": 75, "count": [ 1, 4 ] } @@ -319,7 +319,7 @@ "id": "renfield_shotgun_death_drops", "entries": [ { - "distribution": [ + "collection": [ { "item": "mossberg_500", "prob": 100, "damage": [ 1, 3 ] }, { "item": "shot_00", "prob": 40, "count": [ 1, 6 ] }, { "item": "scrap_dreamdross", "prob": 75, "count": [ 1, 4 ] } @@ -334,7 +334,7 @@ "id": "renfield_flamethrower_death_drops", "entries": [ { - "distribution": [ + "collection": [ { "item": "rm451_flamethrower", "prob": 100, "damage": [ 1, 3 ] }, { "item": "scrap_dreamdross", "prob": 75, "count": [ 1, 4 ] } ] From d21c70380a18b85736dc429d1879a1bdcc9346cc Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sat, 7 Jun 2025 12:36:23 -0500 Subject: [PATCH 02/28] Quick and dirty craft failure explosions code changes --- data/json/recipes/weapon/explosive.json | 20 ++++++++++ src/crafting.cpp | 51 +++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/data/json/recipes/weapon/explosive.json b/data/json/recipes/weapon/explosive.json index b7c49f44308fe..804c23fa1b20e 100644 --- a/data/json/recipes/weapon/explosive.json +++ b/data/json/recipes/weapon/explosive.json @@ -20,6 +20,7 @@ ], "qualities": [ { "id": "CHEM", "level": 2 } ], "tools": [ [ [ "surface_heat", 25, "LIST" ] ] ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "paper", 5 ], [ "rolling_paper", 32 ] ], [ [ "chem_sulphuric_acid", 2 ] ], @@ -64,6 +65,7 @@ "autolearn": true, "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 2 } ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "thread", 10 ] ], [ [ "paper", 1 ], [ "rolling_paper", 6 ] ], @@ -78,6 +80,7 @@ "subcategory": "CSC_WEAPON_EXPLOSIVE", "skill_used": "fabrication", "time": "3 m", + "flags": [ "EXPLOSIVE" ], "reversible": true, "autolearn": true, "qualities": [ { "id": "CUT", "level": 2 } ], @@ -184,6 +187,7 @@ "time": "12 m", "reversible": true, "autolearn": true, + "flags": [ "EXPLOSIVE" ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "SAW_M", "level": 1 }, { "id": "GLARE", "level": 1 } ], "tools": [ @@ -219,6 +223,7 @@ [ "adv_chemistry", 3 ], [ "textbook_anarch", 3 ] ], + "flags": [ "EXPLOSIVE" ], "proficiencies": [ { "proficiency": "prof_intro_chemistry" }, { "proficiency": "prof_inorganic_chemistry" } ], "time": "7 m 30 s", "qualities": [ { "id": "SCREW", "level": 1 } ], @@ -243,6 +248,7 @@ "book_learn": [ [ "textbook_gaswarfare", 2 ], [ "textbook_chemistry", 3 ], [ "adv_chemistry", 3 ], [ "textbook_anarch", 3 ] ], "proficiencies": [ { "proficiency": "prof_intro_chemistry" }, { "proficiency": "prof_inorganic_chemistry" } ], "time": "7 m 30 s", + "flags": [ "EXPLOSIVE" ], "qualities": [ { "id": "SCREW", "level": 1 } ], "using": [ [ "small_gas_canister_case", 1 ] ], "components": [ @@ -265,6 +271,7 @@ "book_learn": [ [ "manual_launcher", 4 ], [ "textbook_anarch", 5 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "SAW_M", "level": 1 } ], + "flags": [ "EXPLOSIVE" ], "using": [ [ "military_explosive", 46 ], [ "explosives_casting_standard", 1 ], [ "small_grenade_case", 1 ] ], "components": [ [ [ "delay_fuze", 1 ] ], @@ -287,6 +294,7 @@ "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "SAW_M", "level": 1 } ], "using": [ [ "military_explosive", 92 ], [ "explosives_casting_standard", 1 ] ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "delay_fuze", 1 ] ], [ [ "super_glue", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -308,6 +316,7 @@ "book_learn": [ [ "manual_launcher", 4 ], [ "textbook_anarch", 5 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "military_explosive", 92 ], [ "explosives_casting_standard", 1 ] ], + "flags": [ "EXPLOSIVE" ], "qualities": [ { "id": "SAW_M", "level": 1 } ], "components": [ [ [ "pipe", 1 ] ], [ [ "delay_fuze", 1 ] ] ] }, @@ -325,6 +334,7 @@ "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "military_explosive", 697 ], [ "explosives_casting_standard", 1 ] ], "qualities": [ { "id": "SAW_M", "level": 1 } ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "delay_fuze", 1 ] ], [ [ "super_glue", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -345,6 +355,7 @@ "book_learn": [ [ "manual_launcher", 7 ], [ "textbook_anarch", 8 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "explosives_casting_standard", 5 ], [ "military_explosive", 10000 ] ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "delay_fuze", 1 ] ], [ [ "super_glue", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -364,6 +375,7 @@ "book_learn": [ [ "manual_launcher", 7 ], [ "textbook_anarch", 8 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "explosives_casting_standard", 10 ], [ "military_explosive", 20000 ] ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "delay_fuze", 1 ] ], [ [ "super_glue", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -384,6 +396,7 @@ "autolearn": true, "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "SAW_M", "level": 1 } ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "small_grenade_case", 1, "LIST" ] ], [ [ "stable_explosive", 15, "LIST" ], [ "volatile_explosive", 15, "LIST" ] ], @@ -406,6 +419,7 @@ "autolearn": true, "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "SAW_M", "level": 1 } ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "can_medium", 1 ] ], [ [ "stable_explosive", 30, "LIST" ], [ "volatile_explosive", 30, "LIST" ] ], @@ -427,6 +441,7 @@ "autolearn": true, "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "SAW_M", "level": 1 } ], + "flags": [ "EXPLOSIVE" ], "using": [ [ "stable_explosive", 29 ], [ "volatile_explosive", 1 ] ], "components": [ [ [ "pipe", 1 ] ], [ [ "fuse", 1 ] ] ] }, @@ -456,6 +471,7 @@ "allowing it on smaller explosives, but not on the largest like ", "the barrel bombs." ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "pipe", 1 ] ], [ [ "fuse", 1 ] ] ] }, { @@ -473,6 +489,7 @@ "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "stable_explosive", 226 ], [ "volatile_explosive", 6 ] ], "qualities": [ { "id": "SAW_M", "level": 1 } ], + "flags": [ "EXPLOSIVE" ], "components": [ [ [ "fuse", 1 ] ], [ [ "super_glue", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -494,6 +511,7 @@ "book_learn": [ [ "manual_launcher", 4 ], [ "textbook_anarch", 5 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "stable_explosive", 253 ], [ "volatile_explosive", 6 ] ], + "flags": [ "EXPLOSIVE" ], "qualities": [ { "id": "SAW_M", "level": 1 } ], "components": [ [ [ "fuse", 1 ] ], [ [ "super_glue", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], [ [ "jug_plastic", 1 ] ] ] }, @@ -507,6 +525,7 @@ "difficulty": 3, "time": "30 m", "reversible": true, + "flags": [ "EXPLOSIVE" ], "book_learn": [ [ "manual_launcher", 7 ], [ "textbook_anarch", 8 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "volatile_explosive", 86 ], [ "stable_explosive", 3354 ] ], @@ -524,6 +543,7 @@ "reversible": true, "book_learn": [ [ "manual_launcher", 7 ], [ "textbook_anarch", 8 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], + "flags": [ "EXPLOSIVE" ], "using": [ [ "volatile_explosive", 173 ], [ "stable_explosive", 6747 ] ], "components": [ [ [ "fuse", 1 ] ], [ [ "super_glue", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], [ [ "30gal_drum", 1 ] ] ] } diff --git a/src/crafting.cpp b/src/crafting.cpp index 1d370db0b0070..2cebea685e7c1 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -34,6 +34,7 @@ #include "effect_on_condition.h" #include "enum_traits.h" #include "enums.h" +#include "explosion.h" #include "faction.h" #include "flag.h" #include "game.h" @@ -119,6 +120,7 @@ static const trait_id trait_INT_ALPHA( "INT_ALPHA" ); static const std::string flag_AFFECTED_BY_PAIN( "AFFECTED_BY_PAIN" ); static const std::string flag_BLIND_EASY( "BLIND_EASY" ); static const std::string flag_BLIND_HARD( "BLIND_HARD" ); +static const std::string flag_EXPLOSIVE( "EXPLOSIVE" ); static const std::string flag_FULL_MAGAZINE( "FULL_MAGAZINE" ); static const std::string flag_NO_BENCH( "NO_BENCH" ); static const std::string flag_NO_ENCHANTMENT( "NO_ENCHANTMENT" ); @@ -1351,6 +1353,55 @@ static void destroy_random_component( item &craft, const Character &crafter ) crafter.add_msg_player_or_npc( game_message_params( game_message_type::m_bad ), _( "You mess up and destroy the %s." ), _( " messes up and destroys the %s" ), destroyed.tname() ); + + // Explosive failure chance reduced by proficiency ratio + if( craft.has_flag( flag_EXPLOSIVE ) ) { + const recipe &rec = craft.get_making(); + const std::vector &profs = rec.proficiencies; + int num_required = 0; + int num_known = 0; + + for( const recipe_proficiency &prof : profs ) { + if( prof.required ) { + num_required++; + if( crafter.has_proficiency( prof.id ) ) { + num_known++; + } + } + } + double reduction = ( num_required > 0 ) ? ( static_cast( num_known ) / num_required ) : 0.0; + const double base_explosion_chance = 0.4; // 40% + double explosion_chance = base_explosion_chance * ( 1.0 - reduction ); + + int missing = num_required - num_known; + if( missing <= 0 ) { + missing = 1; + } + + int batch_size = craft.get_making_batch_size(); + if( batch_size <= 0 ) { + batch_size = 1; + } + + if( x_in_y( explosion_chance * 100, 100 ) ) { + const int weight_grams = craft.weight() / units::gram; + const int explosion_power = 2 * weight_grams * missing * batch_size; + const double casing_mass = static_cast(weight_grams * missing * batch_size); + const double fragment_mass = 0.1; + + explosion_data exp; + exp.power = explosion_power; + exp.shrapnel = cata::make_value(); + exp.shrapnel->casing_mass = casing_mass; + exp.shrapnel->fragment_mass = fragment_mass; + + crafter.add_msg_player_or_npc( m_bad, + _( "The explosive craft explodes violently!" ), + _( "The explosive craft explodes violently near !" ) + ); + get_map().explosion( crafter.pos(), exp ); + } + } } bool item::handle_craft_failure( Character &crafter ) From 1d8df852bfd6a983e3930cd3561dc62fedb7911e Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sat, 7 Jun 2025 15:36:07 -0500 Subject: [PATCH 03/28] Update crafting.cpp --- src/crafting.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crafting.cpp b/src/crafting.cpp index 2cebea685e7c1..37c31608ddac5 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -1384,7 +1384,7 @@ static void destroy_random_component( item &craft, const Character &crafter ) } if( x_in_y( explosion_chance * 100, 100 ) ) { - const int weight_grams = craft.weight() / units::gram; + const int weight_grams = units::to_gram(craft.weight()); const int explosion_power = 2 * weight_grams * missing * batch_size; const double casing_mass = static_cast(weight_grams * missing * batch_size); const double fragment_mass = 0.1; @@ -1399,7 +1399,7 @@ static void destroy_random_component( item &craft, const Character &crafter ) _( "The explosive craft explodes violently!" ), _( "The explosive craft explodes violently near !" ) ); - get_map().explosion( crafter.pos(), exp ); + explosion( crafter.pos(), exp ); } } } From 558cbcbc447576c4d6117651cf643b1d56262cf7 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 27 Aug 2025 19:19:02 -0500 Subject: [PATCH 04/28] Update mutation.cpp --- src/mutation.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mutation.cpp b/src/mutation.cpp index 9bcd942325637..cd9824faffe0d 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1363,8 +1363,6 @@ void Character::mutate( const int &true_random_chance, bool use_vitamins ) return; } } - } while( valid.empty() ); -} void Character::mutate( ) { From ba5a3d5cad56717907d4e56702370f1c586d0458 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 27 Aug 2025 20:00:14 -0500 Subject: [PATCH 05/28] Update src/mutation.cpp --- src/mutation.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mutation.cpp b/src/mutation.cpp index cd9824faffe0d..f21df3d6945ce 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1363,6 +1363,8 @@ void Character::mutate( const int &true_random_chance, bool use_vitamins ) return; } } + } while( valid.empty() ); +} void Character::mutate( ) { From 025c4382c3bd9b3512e055682dd2a680a1d25996 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 27 Aug 2025 20:07:29 -0500 Subject: [PATCH 06/28] Update src/mutation.cpp Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/mutation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mutation.cpp b/src/mutation.cpp index f21df3d6945ce..9bcd942325637 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1363,7 +1363,7 @@ void Character::mutate( const int &true_random_chance, bool use_vitamins ) return; } } - } while( valid.empty() ); + } while( valid.empty() ); } void Character::mutate( ) From 3fc92a0f6c454a7273b2dd9544e9a45f25386e81 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 27 Aug 2025 21:21:00 -0500 Subject: [PATCH 07/28] Update mutation.cpp --- src/mutation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mutation.cpp b/src/mutation.cpp index 9bcd942325637..db9e0a5301f0a 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1389,6 +1389,9 @@ void Character::mutate_category( const mutation_category_id &cat, const bool use bool allow_bad = false; bool allow_neutral = true; + if (has_trait(trait_id("CHAOTIC")) || has_trait(trait_id("CHAOTIC_BAD"))) { + add_msg_if_player(m_bad, _("Your genetic degeneration prevent you from selecting a mutation directly!")); + return; if( select_mutation || true_random ) { // Mutation selector and true_random overrides good / bad mutation rolls allow_good = true; From 1d2df46be09116f0f3d49d06cdad95a78062fb18 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 27 Aug 2025 22:00:32 -0500 Subject: [PATCH 08/28] Update mutation.cpp --- src/mutation.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mutation.cpp b/src/mutation.cpp index db9e0a5301f0a..9bcd942325637 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1389,9 +1389,6 @@ void Character::mutate_category( const mutation_category_id &cat, const bool use bool allow_bad = false; bool allow_neutral = true; - if (has_trait(trait_id("CHAOTIC")) || has_trait(trait_id("CHAOTIC_BAD"))) { - add_msg_if_player(m_bad, _("Your genetic degeneration prevent you from selecting a mutation directly!")); - return; if( select_mutation || true_random ) { // Mutation selector and true_random overrides good / bad mutation rolls allow_good = true; From cec7d3094c4abe0d9e1152805de062ad265aa2d9 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 27 Aug 2025 21:55:27 -0500 Subject: [PATCH 09/28] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/mutation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mutation.cpp b/src/mutation.cpp index 9bcd942325637..f43698afaf258 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1388,7 +1388,6 @@ void Character::mutate_category( const mutation_category_id &cat, const bool use bool allow_good = false; bool allow_bad = false; bool allow_neutral = true; - if( select_mutation || true_random ) { // Mutation selector and true_random overrides good / bad mutation rolls allow_good = true; From 027dbf90f26c57591c3d41015d21a593e8921588 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 27 Aug 2025 23:53:52 -0500 Subject: [PATCH 10/28] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/mutation.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/mutation.cpp b/src/mutation.cpp index f43698afaf258..44a7dd823d684 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1430,13 +1430,8 @@ void Character::mutate_category( const mutation_category_id &cat ) mutate_category( cat, !mutation_category_trait::get_category( cat ).vitamin.is_null() ); } -bool Character::mutation_selector( const std::vector &prospective_traits, - const mutation_category_id &cat, const bool &use_vitamins ) -{ - if( has_trait( trait_CHAOTIC ) || has_trait( trait_CHAOTIC_BAD ) ) { - add_msg_if_player( m_bad, - _( "Your genetic degeneration prevents you from selecting a mutation directly!" ) ); - return false; + void Character::mutate_category( const mutation_category_id & cat ) { + mutate_category( cat, !mutation_category_trait::get_category( cat ).vitamin.is_null() ); } // Setup menu From 093204484c7ef55f6a6a3cf269afa887186dcb97 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 29 Aug 2025 22:23:08 -0500 Subject: [PATCH 11/28] Update src/mutation.cpp --- src/mutation.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/mutation.cpp b/src/mutation.cpp index 44a7dd823d684..995e2fa7a9f9e 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1430,6 +1430,15 @@ void Character::mutate_category( const mutation_category_id &cat ) mutate_category( cat, !mutation_category_trait::get_category( cat ).vitamin.is_null() ); } + bool Character::mutation_selector( const std::vector &prospective_traits, + const mutation_category_id &cat, const bool &use_vitamins ) +{ + if( has_trait( trait_CHAOTIC ) || has_trait( trait_CHAOTIC_BAD ) ) { + add_msg_if_player( m_bad, + _( "Your genetic degeneration prevents you from selecting a mutation directly!" ) ); + return false; + } + void Character::mutate_category( const mutation_category_id & cat ) { mutate_category( cat, !mutation_category_trait::get_category( cat ).vitamin.is_null() ); } From 1a4253a8379edf32d7e31fbf14f120ce68d4183b Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 29 Aug 2025 22:38:46 -0500 Subject: [PATCH 12/28] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/mutation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mutation.cpp b/src/mutation.cpp index 995e2fa7a9f9e..a1afe4147fe75 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1430,15 +1430,15 @@ void Character::mutate_category( const mutation_category_id &cat ) mutate_category( cat, !mutation_category_trait::get_category( cat ).vitamin.is_null() ); } - bool Character::mutation_selector( const std::vector &prospective_traits, +bool Character::mutation_selector( const std::vector &prospective_traits, const mutation_category_id &cat, const bool &use_vitamins ) { if( has_trait( trait_CHAOTIC ) || has_trait( trait_CHAOTIC_BAD ) ) { add_msg_if_player( m_bad, _( "Your genetic degeneration prevents you from selecting a mutation directly!" ) ); return false; - } - + } + void Character::mutate_category( const mutation_category_id & cat ) { mutate_category( cat, !mutation_category_trait::get_category( cat ).vitamin.is_null() ); } From d1e3493ca6f8df5c25e8317a6596dd753c7da15b Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 31 Aug 2025 15:13:05 -0500 Subject: [PATCH 13/28] items work again --- .../items/gracken_trait_improvements.json | 113 +++++++++++++----- 1 file changed, 86 insertions(+), 27 deletions(-) diff --git a/data/mods/Xedra_Evolved/items/gracken_trait_improvements.json b/data/mods/Xedra_Evolved/items/gracken_trait_improvements.json index 76287715cd543..b0d6ca600c9b4 100644 --- a/data/mods/Xedra_Evolved/items/gracken_trait_improvements.json +++ b/data/mods/Xedra_Evolved/items/gracken_trait_improvements.json @@ -2,8 +2,7 @@ { "abstract": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], - "comestible_type": "INVALID", + "subtypes": [ "TOOL" ], "category": "MED", "name": { "str": "abstract gracken improvement", "//~": "NO_I18N" }, "weight": "2041 g", @@ -12,17 +11,22 @@ "symbol": "!", "color": "light_gray", "price_postapoc": "10 USD", - "flags": [ "NO_INGEST", "EDIBLE_FROZEN" ] + "flags": [ "SINGLE_USE" ] }, { "id": "gracken_shade_arms", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Shade Arms" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their arms back to a base state.", - "consumption_effect_on_conditions": [ "shade_arms" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "shade_arms" ] + } }, { "type": "effect_on_condition", @@ -35,11 +39,16 @@ "id": "gracken_strong_arms", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Strong Arms" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their arms to a stronger form.", - "consumption_effect_on_conditions": [ "strong_arms" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "strong_arms" ] + } }, { "type": "effect_on_condition", @@ -52,11 +61,16 @@ "id": "gracken_long_arms", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Long Arms" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their arms to a longer form.", - "consumption_effect_on_conditions": [ "long_arms" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "long_arms" ] + } }, { "type": "effect_on_condition", @@ -69,11 +83,16 @@ "id": "gracken_shade_hands", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Shade Hands" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their hands back to a base state.", - "consumption_effect_on_conditions": [ "shade_hands" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "shade_hands" ] + } }, { "type": "effect_on_condition", @@ -86,11 +105,16 @@ "id": "gracken_sharp_nails", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Sharp Nails" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their hands to a sharper form.", - "consumption_effect_on_conditions": [ "sharp_nails" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "sharp_nails" ] + } }, { "type": "effect_on_condition", @@ -103,11 +127,16 @@ "id": "gracken_dextrous_hands", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Dextrous Hands" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their hands to a more agile form.", - "consumption_effect_on_conditions": [ "dextrous_hands" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "dextrous_hands" ] + } }, { "type": "effect_on_condition", @@ -120,11 +149,16 @@ "id": "gracken_herbivorous_stomach", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Herbivorous Stomach" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their diet to an herbivorous one.", - "consumption_effect_on_conditions": [ "herbivorous_stomach" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "herbivorous_stomach" ] + } }, { "type": "effect_on_condition", @@ -137,11 +171,16 @@ "id": "gracken_omnivorous_stomach", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Dextrous Hands" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their diet to an omnivorous one.", - "consumption_effect_on_conditions": [ "omnivorous_stomach" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "omnivorous_stomach" ] + } }, { "type": "effect_on_condition", @@ -154,11 +193,16 @@ "id": "gracken_carnivorous_stomach", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Dextrous Hands" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their diet to an carnivorous one.", - "consumption_effect_on_conditions": [ "carnivorous_stomach" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "carnivorous_stomach" ] + } }, { "type": "effect_on_condition", @@ -171,11 +215,16 @@ "id": "gracken_shade_legs", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Shade Legs" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their legs back to a base state.", - "consumption_effect_on_conditions": [ "shade_legs" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "shade_legs" ] + } }, { "type": "effect_on_condition", @@ -188,11 +237,16 @@ "id": "gracken_short_legs", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Short Legs" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their legs to a shorter form.", - "consumption_effect_on_conditions": [ "short_legs" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "short_legs" ] + } }, { "type": "effect_on_condition", @@ -205,11 +259,16 @@ "id": "gracken_long_legs", "copy-from": "gracken_improvement_general", "type": "ITEM", - "subtypes": [ "COMESTIBLE" ], + "subtypes": [ "TOOL" ], "name": { "str_sp": "Gracken Long Legs" }, "looks_like": "offal", "description": "An organ that allows a mature Gracken to convert their legs to a longer form.", - "consumption_effect_on_conditions": [ "long_legs" ] + "use_action": { + "type": "effect_on_conditions", + "consume": true, + "description": "You graft this organ onto your body replacing whatever was there before.", + "effect_on_conditions": [ "long_legs" ] + } }, { "type": "effect_on_condition", From a0503f04777e9e424d532d38099e386defc53d07 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 31 Aug 2025 16:50:33 -0500 Subject: [PATCH 14/28] Fix EOC not respecting mutation type --- src/npctalk.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 977a27823e031..1419014fb2fc1 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -3491,6 +3491,33 @@ talk_effect_fun_t::func f_add_trait( const JsonObject &jo, std::string_view memb const trait_id trait = trait_id( new_trait.evaluate( d ) ); const mutation_variant *variant = trait->variant( new_variant.evaluate( d ) ); + Character *guy = d.actor( is_npc )->get_character(); + if( !guy ) { + debugmsg( "f_add_trait: No valid character." ); + return; + } + + const auto &new_types = trait->types; + + for( const trait_id &existing : guy->get_mutations() ) { + if( existing == trait ) { + continue; + } + const auto &existing_types = existing->types; + for( const std::string &t : existing_types ) { + bool match = false; + if constexpr( std::is_same &>::value ) { + match = new_types.count( t ) > 0; + } else { + match = std::find( new_types.begin(), new_types.end(), t ) != new_types.end(); + } + if( match ) { + guy->unset_mutation( existing ); + break; + } + } + } + d.actor( is_npc )->set_mutation( trait, variant ); }; } From 99c4d0eeba406f5e64e5d9be255a7d86ee43136f Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:09:46 -0500 Subject: [PATCH 15/28] Test --- tests/iuse_test.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index 1aca1598bb399..6c385ef0ec0b4 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -8,9 +8,11 @@ #include "bodypart.h" #include "calendar.h" #include "cata_catch.h" +#include "character_id.h" #include "character_attire.h" #include "coordinates.h" #include "flag.h" +#include "game.h" #include "inventory.h" #include "item.h" #include "item_location.h" @@ -19,10 +21,13 @@ #include "map.h" #include "map_helpers.h" #include "map_selector.h" +#include "mod_manager.h" #include "player_helpers.h" #include "pocket_type.h" #include "point.h" +#include "profession.h" #include "ret_val.h" +#include "trait_group.h" #include "type_id.h" #include "value_ptr.h" @@ -1077,3 +1082,38 @@ TEST_CASE( "water_tablet_purification_test", "[iuse][pur_tablets]" ) } } + +static void use_item_by_type( avatar &you, const itype_id &id ) { + for( item &it : you.inv_dump() ) { + if( it.typeId() == id ) { + you.use( you.get_item_position( &it ) ); + break; + } + } +} + +TEST_CASE( "gracken_strong_arms_trait_change", "[gracken][traits][mutation][item_use]" ) +{ + set_game_mods({ "dda", "Xedra_Evolved" }); + + clear_avatar(); + + const profession *prof = profession::prof("xe_gracken_hunter"); + REQUIRE( prof != nullptr ); + avatar &you = get_avatar(); + prof->apply( you ); + + REQUIRE( you.has_trait( trait_id( "SHADE_ARMS" ) ) ); + + item strong_arms( "gracken_strong_arms" ); + you.i_add( strong_arms ); + REQUIRE( you.has_amount( "gracken_strong_arms", 1 ) ); + + use_item_by_type( you, itype_id( "gracken_strong_arms" ) ); + + REQUIRE_FALSE( you.has_amount( "gracken_strong_arms", 1 ) ); + + REQUIRE_FALSE( you.has_trait( trait_id( "SHADE_ARMS" ) ) ); + + REQUIRE( you.has_trait( trait_id( "SHADE_STRONG_ARMS" ) ) ); +} From b3549bb9c95f3b265b84f8b3b31cdeb610025b3a Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 31 Aug 2025 16:56:15 -0500 Subject: [PATCH 16/28] Update src/npctalk.cpp Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/npctalk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 1419014fb2fc1..f4cd0a9762b04 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -3506,7 +3506,7 @@ talk_effect_fun_t::func f_add_trait( const JsonObject &jo, std::string_view memb const auto &existing_types = existing->types; for( const std::string &t : existing_types ) { bool match = false; - if constexpr( std::is_same &>::value ) { + if constexpr( std::is_same &>::value ) { match = new_types.count( t ) > 0; } else { match = std::find( new_types.begin(), new_types.end(), t ) != new_types.end(); From 4b83970e8c41ca55fb93838ba248025f567af97c Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:44:51 -0500 Subject: [PATCH 17/28] Update npctalk.cpp --- src/npctalk.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index f4cd0a9762b04..bc9123e493f0b 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -3499,24 +3499,18 @@ talk_effect_fun_t::func f_add_trait( const JsonObject &jo, std::string_view memb const auto &new_types = trait->types; - for( const trait_id &existing : guy->get_mutations() ) { - if( existing == trait ) { - continue; - } - const auto &existing_types = existing->types; - for( const std::string &t : existing_types ) { - bool match = false; - if constexpr( std::is_same &>::value ) { - match = new_types.count( t ) > 0; - } else { - match = std::find( new_types.begin(), new_types.end(), t ) != new_types.end(); - } - if( match ) { - guy->unset_mutation( existing ); - break; - } + for( const std::string &t : existing_types ) { + bool match = false; + if constexpr( std::is_same_v & > ) { + match = new_types.count( t ) > 0; + } else { + match = new_types.count( t ) > 0; } - } + if( match ) { + guy->unset_mutation( existing ); + break; + } +} d.actor( is_npc )->set_mutation( trait, variant ); }; From dd9274f903599b7a3700d0fdfd3363dc1230748e Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 31 Aug 2025 17:48:40 -0500 Subject: [PATCH 18/28] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/npctalk.cpp | 12 ++++++------ tests/iuse_test.cpp | 7 ++++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index bc9123e493f0b..07a895c8a886d 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -3502,15 +3502,15 @@ talk_effect_fun_t::func f_add_trait( const JsonObject &jo, std::string_view memb for( const std::string &t : existing_types ) { bool match = false; if constexpr( std::is_same_v & > ) { - match = new_types.count( t ) > 0; + match = new_types.count( t ) > 0; } else { - match = new_types.count( t ) > 0; + match = new_types.count( t ) > 0; } if( match ) { - guy->unset_mutation( existing ); - break; - } -} + guy->unset_mutation( existing ); + break; + } + } d.actor( is_npc )->set_mutation( trait, variant ); }; diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index 6c385ef0ec0b4..52aa37a0d2e4f 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -1083,7 +1083,8 @@ TEST_CASE( "water_tablet_purification_test", "[iuse][pur_tablets]" ) } } -static void use_item_by_type( avatar &you, const itype_id &id ) { +static void use_item_by_type( avatar &you, const itype_id &id ) +{ for( item &it : you.inv_dump() ) { if( it.typeId() == id ) { you.use( you.get_item_position( &it ) ); @@ -1094,11 +1095,11 @@ static void use_item_by_type( avatar &you, const itype_id &id ) { TEST_CASE( "gracken_strong_arms_trait_change", "[gracken][traits][mutation][item_use]" ) { - set_game_mods({ "dda", "Xedra_Evolved" }); + set_game_mods( { "dda", "Xedra_Evolved" } ); clear_avatar(); - const profession *prof = profession::prof("xe_gracken_hunter"); + const profession *prof = profession::prof( "xe_gracken_hunter" ); REQUIRE( prof != nullptr ); avatar &you = get_avatar(); prof->apply( you ); From d4810f37d13b20299eb01bc9d6db375d42b0863c Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 31 Aug 2025 18:54:06 -0500 Subject: [PATCH 19/28] Update src/npctalk.cpp --- src/npctalk.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 07a895c8a886d..d70d0a604abe4 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -3499,18 +3499,22 @@ talk_effect_fun_t::func f_add_trait( const JsonObject &jo, std::string_view memb const auto &new_types = trait->types; - for( const std::string &t : existing_types ) { - bool match = false; - if constexpr( std::is_same_v & > ) { - match = new_types.count( t ) > 0; - } else { - match = new_types.count( t ) > 0; - } - if( match ) { - guy->unset_mutation( existing ); - break; + for( const trait_id &existing : guy->get_mutations() ) { + if( existing == trait ) { + continue; } - } + const auto &existing_types = existing->types; + for( const std::string &t : existing_types ) { + bool match = false; + if constexpr( std::is_same &>::value ) { + match = new_types.count( t ) > 0; + } else { + match = std::find( new_types.begin(), new_types.end(), t ) != new_types.end(); + } + if( match ) { + guy->unset_mutation( existing ); + break; + } d.actor( is_npc )->set_mutation( trait, variant ); }; From be1c0065e1a6064669e028566dc9d7eabe743c0d Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 31 Aug 2025 18:54:53 -0500 Subject: [PATCH 20/28] Update src/npctalk.cpp --- src/npctalk.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index d70d0a604abe4..1419014fb2fc1 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -3506,7 +3506,7 @@ talk_effect_fun_t::func f_add_trait( const JsonObject &jo, std::string_view memb const auto &existing_types = existing->types; for( const std::string &t : existing_types ) { bool match = false; - if constexpr( std::is_same &>::value ) { + if constexpr( std::is_same &>::value ) { match = new_types.count( t ) > 0; } else { match = std::find( new_types.begin(), new_types.end(), t ) != new_types.end(); @@ -3515,6 +3515,8 @@ talk_effect_fun_t::func f_add_trait( const JsonObject &jo, std::string_view memb guy->unset_mutation( existing ); break; } + } + } d.actor( is_npc )->set_mutation( trait, variant ); }; From 7334df38681fa6ff7c0239f03bd12b2b3aad6a44 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sun, 31 Aug 2025 22:57:13 -0500 Subject: [PATCH 21/28] Update src/npctalk.cpp Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/npctalk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index 1419014fb2fc1..f4cd0a9762b04 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -3506,7 +3506,7 @@ talk_effect_fun_t::func f_add_trait( const JsonObject &jo, std::string_view memb const auto &existing_types = existing->types; for( const std::string &t : existing_types ) { bool match = false; - if constexpr( std::is_same &>::value ) { + if constexpr( std::is_same &>::value ) { match = new_types.count( t ) > 0; } else { match = std::find( new_types.begin(), new_types.end(), t ) != new_types.end(); From 5a261e16da270b5ef361db70ef8e1af873d462e6 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Mon, 1 Sep 2025 00:15:54 -0500 Subject: [PATCH 22/28] Update iuse_test.cpp --- tests/iuse_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index 52aa37a0d2e4f..7ef9e7f423eb4 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -71,6 +71,7 @@ static const itype_id itype_atomic_coffee( "atomic_coffee" ); static const itype_id itype_backpack( "backpack" ); static const itype_id itype_coffee( "coffee" ); static const itype_id itype_diazepam( "diazepam" ); +static const itype_id itype_gracken_strong_arms( "gracken_strong_arms" ); static const itype_id itype_inhaler( "inhaler" ); static const itype_id itype_oxygen( "oxygen" ); static const itype_id itype_oxygen_tank( "oxygen_tank" ); From 994421c8d1d9f4179089ec70ab471f77d422dc73 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Tue, 2 Sep 2025 23:13:22 -0500 Subject: [PATCH 23/28] Apply suggestions from code review --- data/json/recipes/weapon/explosive.json | 17 --------- src/crafting.cpp | 51 ------------------------- src/mutation.cpp | 1 + 3 files changed, 1 insertion(+), 68 deletions(-) diff --git a/data/json/recipes/weapon/explosive.json b/data/json/recipes/weapon/explosive.json index 8dfa626e7e937..a1d187d8faf61 100644 --- a/data/json/recipes/weapon/explosive.json +++ b/data/json/recipes/weapon/explosive.json @@ -20,7 +20,6 @@ ], "qualities": [ { "id": "CHEM", "level": 2 } ], "tools": [ [ [ "surface_heat", 25, "LIST" ] ] ], - "flags": [ "EXPLOSIVE" ], "components": [ [ [ "paper", 5 ], [ "rolling_paper", 32 ] ], [ [ "chem_sulphuric_acid", 2 ] ], @@ -65,7 +64,6 @@ "autolearn": true, "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "CUT", "level": 2 } ], - "flags": [ "EXPLOSIVE" ], "components": [ [ [ "thread", 10 ] ], [ [ "paper", 1 ], [ "rolling_paper", 6 ] ], @@ -80,7 +78,6 @@ "subcategory": "CSC_WEAPON_EXPLOSIVE", "skill_used": "fabrication", "time": "3 m", - "flags": [ "EXPLOSIVE" ], "reversible": true, "autolearn": true, "qualities": [ { "id": "CUT", "level": 2 } ], @@ -180,7 +177,6 @@ "time": "12 m", "reversible": true, "autolearn": true, - "flags": [ "EXPLOSIVE" ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "SAW_M", "level": 1 }, { "id": "GLARE", "level": 1 } ], "tools": [ @@ -216,7 +212,6 @@ [ "adv_chemistry", 3 ], [ "textbook_anarch", 3 ] ], - "flags": [ "EXPLOSIVE" ], "proficiencies": [ { "proficiency": "prof_intro_chemistry" }, { "proficiency": "prof_inorganic_chemistry" } ], "time": "7 m 30 s", "qualities": [ { "id": "SCREW", "level": 1 } ], @@ -241,7 +236,6 @@ "book_learn": [ [ "textbook_gaswarfare", 2 ], [ "textbook_chemistry", 3 ], [ "adv_chemistry", 3 ], [ "textbook_anarch", 3 ] ], "proficiencies": [ { "proficiency": "prof_intro_chemistry" }, { "proficiency": "prof_inorganic_chemistry" } ], "time": "7 m 30 s", - "flags": [ "EXPLOSIVE" ], "qualities": [ { "id": "SCREW", "level": 1 } ], "using": [ [ "small_gas_canister_case", 1 ] ], "components": [ @@ -286,7 +280,6 @@ "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "SAW_M", "level": 1 } ], "using": [ [ "military_explosive", 92 ], [ "explosives_casting_standard", 1 ] ], - "flags": [ "EXPLOSIVE" ], "components": [ [ [ "delay_fuze", 1 ] ], [ [ "glue_strong", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -308,7 +301,6 @@ "book_learn": [ [ "manual_launcher", 4 ], [ "textbook_anarch", 5 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "military_explosive", 92 ], [ "explosives_casting_standard", 1 ] ], - "flags": [ "EXPLOSIVE" ], "qualities": [ { "id": "SAW_M", "level": 1 } ], "components": [ [ [ "pipe", 1 ] ], [ [ "delay_fuze", 1 ] ] ] }, @@ -326,7 +318,6 @@ "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "military_explosive", 697 ], [ "explosives_casting_standard", 1 ] ], "qualities": [ { "id": "SAW_M", "level": 1 } ], - "flags": [ "EXPLOSIVE" ], "components": [ [ [ "delay_fuze", 1 ] ], [ [ "glue_strong", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -347,7 +338,6 @@ "book_learn": [ [ "manual_launcher", 7 ], [ "textbook_anarch", 8 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "explosives_casting_standard", 5 ], [ "military_explosive", 10000 ] ], - "flags": [ "EXPLOSIVE" ], "components": [ [ [ "delay_fuze", 1 ] ], [ [ "glue_strong", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -367,7 +357,6 @@ "book_learn": [ [ "manual_launcher", 7 ], [ "textbook_anarch", 8 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "explosives_casting_standard", 10 ], [ "military_explosive", 20000 ] ], - "flags": [ "EXPLOSIVE" ], "components": [ [ [ "delay_fuze", 1 ] ], [ [ "glue_strong", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -429,7 +418,6 @@ "autolearn": true, "proficiencies": [ { "proficiency": "prof_handloading" } ], "qualities": [ { "id": "SAW_M", "level": 1 } ], - "flags": [ "EXPLOSIVE" ], "using": [ [ "stable_explosive", 29 ], [ "volatile_explosive", 1 ] ], "components": [ [ [ "pipe", 1 ] ], [ [ "fuse", 1 ] ] ] }, @@ -459,7 +447,6 @@ "allowing it on smaller explosives, but not on the largest like ", "the barrel bombs." ], - "flags": [ "EXPLOSIVE" ], "components": [ [ [ "pipe", 1 ] ], [ [ "fuse", 1 ] ] ] }, { @@ -477,7 +464,6 @@ "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "stable_explosive", 226 ], [ "volatile_explosive", 6 ] ], "qualities": [ { "id": "SAW_M", "level": 1 } ], - "flags": [ "EXPLOSIVE" ], "components": [ [ [ "fuse", 1 ] ], [ [ "glue_strong", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], @@ -499,7 +485,6 @@ "book_learn": [ [ "manual_launcher", 4 ], [ "textbook_anarch", 5 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "stable_explosive", 253 ], [ "volatile_explosive", 6 ] ], - "flags": [ "EXPLOSIVE" ], "qualities": [ { "id": "SAW_M", "level": 1 } ], "components": [ [ [ "fuse", 1 ] ], [ [ "glue_strong", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], [ [ "jug_plastic", 1 ] ] ] }, @@ -513,7 +498,6 @@ "difficulty": 3, "time": "30 m", "reversible": true, - "flags": [ "EXPLOSIVE" ], "book_learn": [ [ "manual_launcher", 7 ], [ "textbook_anarch", 8 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], "using": [ [ "volatile_explosive", 86 ], [ "stable_explosive", 3354 ] ], @@ -531,7 +515,6 @@ "reversible": true, "book_learn": [ [ "manual_launcher", 7 ], [ "textbook_anarch", 8 ] ], "proficiencies": [ { "proficiency": "prof_handloading" } ], - "flags": [ "EXPLOSIVE" ], "using": [ [ "volatile_explosive", 173 ], [ "stable_explosive", 6747 ] ], "components": [ [ [ "fuse", 1 ] ], [ [ "glue_strong", 4 ], [ "duct_tape", 10 ], [ "cordage", 1, "LIST" ] ], [ [ "30gal_drum", 1 ] ] ] } diff --git a/src/crafting.cpp b/src/crafting.cpp index 5402a87f54cf6..1fb7858c938bb 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -34,7 +34,6 @@ #include "effect_on_condition.h" #include "enum_traits.h" #include "enums.h" -#include "explosion.h" #include "faction.h" #include "flag.h" #include "game.h" @@ -120,7 +119,6 @@ static const trait_id trait_INT_ALPHA( "INT_ALPHA" ); static const std::string flag_AFFECTED_BY_PAIN( "AFFECTED_BY_PAIN" ); static const std::string flag_BLIND_EASY( "BLIND_EASY" ); static const std::string flag_BLIND_HARD( "BLIND_HARD" ); -static const std::string flag_EXPLOSIVE( "EXPLOSIVE" ); static const std::string flag_FULL_MAGAZINE( "FULL_MAGAZINE" ); static const std::string flag_NO_BENCH( "NO_BENCH" ); static const std::string flag_NO_ENCHANTMENT( "NO_ENCHANTMENT" ); @@ -1363,55 +1361,6 @@ static void destroy_random_component( item &craft, const Character &crafter ) crafter.add_msg_player_or_npc( game_message_params( game_message_type::m_bad ), _( "You mess up and destroy the %s." ), _( " messes up and destroys the %s" ), destroyed.tname() ); - - // Explosive failure chance reduced by proficiency ratio - if( craft.has_flag( flag_EXPLOSIVE ) ) { - const recipe &rec = craft.get_making(); - const std::vector &profs = rec.proficiencies; - int num_required = 0; - int num_known = 0; - - for( const recipe_proficiency &prof : profs ) { - if( prof.required ) { - num_required++; - if( crafter.has_proficiency( prof.id ) ) { - num_known++; - } - } - } - double reduction = ( num_required > 0 ) ? ( static_cast( num_known ) / num_required ) : 0.0; - const double base_explosion_chance = 0.4; // 40% - double explosion_chance = base_explosion_chance * ( 1.0 - reduction ); - - int missing = num_required - num_known; - if( missing <= 0 ) { - missing = 1; - } - - int batch_size = craft.get_making_batch_size(); - if( batch_size <= 0 ) { - batch_size = 1; - } - - if( x_in_y( explosion_chance * 100, 100 ) ) { - const int weight_grams = units::to_gram(craft.weight()); - const int explosion_power = 2 * weight_grams * missing * batch_size; - const double casing_mass = static_cast(weight_grams * missing * batch_size); - const double fragment_mass = 0.1; - - explosion_data exp; - exp.power = explosion_power; - exp.shrapnel = cata::make_value(); - exp.shrapnel->casing_mass = casing_mass; - exp.shrapnel->fragment_mass = fragment_mass; - - crafter.add_msg_player_or_npc( m_bad, - _( "The explosive craft explodes violently!" ), - _( "The explosive craft explodes violently near !" ) - ); - explosion( crafter.pos(), exp ); - } - } } bool item::handle_craft_failure( Character &crafter ) diff --git a/src/mutation.cpp b/src/mutation.cpp index a1afe4147fe75..ea89bb62df496 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1388,6 +1388,7 @@ void Character::mutate_category( const mutation_category_id &cat, const bool use bool allow_good = false; bool allow_bad = false; bool allow_neutral = true; + if( select_mutation || true_random ) { // Mutation selector and true_random overrides good / bad mutation rolls allow_good = true; From 9f9f01af7168716bfc7839c6ca82ce384e886b38 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 3 Sep 2025 00:57:02 -0500 Subject: [PATCH 24/28] Update iuse_test.cpp --- tests/iuse_test.cpp | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index 7ef9e7f423eb4..946afc6a076f5 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -1084,38 +1084,26 @@ TEST_CASE( "water_tablet_purification_test", "[iuse][pur_tablets]" ) } } -static void use_item_by_type( avatar &you, const itype_id &id ) -{ - for( item &it : you.inv_dump() ) { - if( it.typeId() == id ) { - you.use( you.get_item_position( &it ) ); - break; - } - } -} TEST_CASE( "gracken_strong_arms_trait_change", "[gracken][traits][mutation][item_use]" ) { set_game_mods( { "dda", "Xedra_Evolved" } ); - clear_avatar(); - const profession *prof = profession::prof( "xe_gracken_hunter" ); - REQUIRE( prof != nullptr ); avatar &you = get_avatar(); - prof->apply( you ); + you.set_profession( profession_id( "xe_gracken_hunter" ) ); REQUIRE( you.has_trait( trait_id( "SHADE_ARMS" ) ) ); - item strong_arms( "gracken_strong_arms" ); + item strong_arms( itype_gracken_strong_arms, calendar::turn_zero ); you.i_add( strong_arms ); REQUIRE( you.has_amount( "gracken_strong_arms", 1 ) ); - use_item_by_type( you, itype_id( "gracken_strong_arms" ) ); + int pos = you.inv->position_by_type( itype_gracken_strong_arms ); + REQUIRE( pos != INT_MIN ); + you.use( pos ); REQUIRE_FALSE( you.has_amount( "gracken_strong_arms", 1 ) ); - REQUIRE_FALSE( you.has_trait( trait_id( "SHADE_ARMS" ) ) ); - REQUIRE( you.has_trait( trait_id( "SHADE_STRONG_ARMS" ) ) ); } From 5ca89e131c912c8291a3c2cbd2a882aebbfe358c Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 3 Sep 2025 01:00:28 -0500 Subject: [PATCH 25/28] Update src/mutation.cpp --- src/mutation.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/mutation.cpp b/src/mutation.cpp index ea89bb62df496..9bcd942325637 100644 --- a/src/mutation.cpp +++ b/src/mutation.cpp @@ -1440,10 +1440,6 @@ bool Character::mutation_selector( const std::vector &prospective_trai return false; } - void Character::mutate_category( const mutation_category_id & cat ) { - mutate_category( cat, !mutation_category_trait::get_category( cat ).vitamin.is_null() ); - } - // Setup menu uilist mmenu; mmenu.text = From 5544f1df7f5d058bc23e39dbc1ee74fe6d5d8592 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Wed, 3 Sep 2025 01:19:41 -0500 Subject: [PATCH 26/28] Update tests/iuse_test.cpp --- tests/iuse_test.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index 7ef9e7f423eb4..75494182161d7 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -1084,16 +1084,6 @@ TEST_CASE( "water_tablet_purification_test", "[iuse][pur_tablets]" ) } } -static void use_item_by_type( avatar &you, const itype_id &id ) -{ - for( item &it : you.inv_dump() ) { - if( it.typeId() == id ) { - you.use( you.get_item_position( &it ) ); - break; - } - } -} - TEST_CASE( "gracken_strong_arms_trait_change", "[gracken][traits][mutation][item_use]" ) { set_game_mods( { "dda", "Xedra_Evolved" } ); From 12b3e135334ebc4a5ac96a6c92d515606f86d9c9 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Sat, 13 Sep 2025 09:20:36 -0500 Subject: [PATCH 27/28] Apply suggestions from code review --- tests/iuse_test.cpp | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/tests/iuse_test.cpp b/tests/iuse_test.cpp index 946afc6a076f5..1aca1598bb399 100644 --- a/tests/iuse_test.cpp +++ b/tests/iuse_test.cpp @@ -8,11 +8,9 @@ #include "bodypart.h" #include "calendar.h" #include "cata_catch.h" -#include "character_id.h" #include "character_attire.h" #include "coordinates.h" #include "flag.h" -#include "game.h" #include "inventory.h" #include "item.h" #include "item_location.h" @@ -21,13 +19,10 @@ #include "map.h" #include "map_helpers.h" #include "map_selector.h" -#include "mod_manager.h" #include "player_helpers.h" #include "pocket_type.h" #include "point.h" -#include "profession.h" #include "ret_val.h" -#include "trait_group.h" #include "type_id.h" #include "value_ptr.h" @@ -71,7 +66,6 @@ static const itype_id itype_atomic_coffee( "atomic_coffee" ); static const itype_id itype_backpack( "backpack" ); static const itype_id itype_coffee( "coffee" ); static const itype_id itype_diazepam( "diazepam" ); -static const itype_id itype_gracken_strong_arms( "gracken_strong_arms" ); static const itype_id itype_inhaler( "inhaler" ); static const itype_id itype_oxygen( "oxygen" ); static const itype_id itype_oxygen_tank( "oxygen_tank" ); @@ -1083,27 +1077,3 @@ TEST_CASE( "water_tablet_purification_test", "[iuse][pur_tablets]" ) } } - - -TEST_CASE( "gracken_strong_arms_trait_change", "[gracken][traits][mutation][item_use]" ) -{ - set_game_mods( { "dda", "Xedra_Evolved" } ); - clear_avatar(); - - avatar &you = get_avatar(); - you.set_profession( profession_id( "xe_gracken_hunter" ) ); - - REQUIRE( you.has_trait( trait_id( "SHADE_ARMS" ) ) ); - - item strong_arms( itype_gracken_strong_arms, calendar::turn_zero ); - you.i_add( strong_arms ); - REQUIRE( you.has_amount( "gracken_strong_arms", 1 ) ); - - int pos = you.inv->position_by_type( itype_gracken_strong_arms ); - REQUIRE( pos != INT_MIN ); - you.use( pos ); - - REQUIRE_FALSE( you.has_amount( "gracken_strong_arms", 1 ) ); - REQUIRE_FALSE( you.has_trait( trait_id( "SHADE_ARMS" ) ) ); - REQUIRE( you.has_trait( trait_id( "SHADE_STRONG_ARMS" ) ) ); -} From b7bbdf6927f688bec8faf65467ebe94703176063 Mon Sep 17 00:00:00 2001 From: Maleclypse <54345792+Maleclypse@users.noreply.github.com> Date: Fri, 19 Sep 2025 21:02:18 -0500 Subject: [PATCH 28/28] Update npctalk.cpp --- src/npctalk.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/npctalk.cpp b/src/npctalk.cpp index f4cd0a9762b04..5bd1891ea88b7 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -3506,10 +3506,10 @@ talk_effect_fun_t::func f_add_trait( const JsonObject &jo, std::string_view memb const auto &existing_types = existing->types; for( const std::string &t : existing_types ) { bool match = false; - if constexpr( std::is_same &>::value ) { + if constexpr( std::is_same_v &> ) { match = new_types.count( t ) > 0; } else { - match = std::find( new_types.begin(), new_types.end(), t ) != new_types.end(); + match = new_types.find( t ) != new_types.end(); } if( match ) { guy->unset_mutation( existing );