From 3f9df95765a7a97f32d4b546c8ace737d0a0c755 Mon Sep 17 00:00:00 2001 From: moxian Date: Fri, 13 Dec 2024 18:35:05 -0800 Subject: [PATCH 1/7] Move itype::name to be first name in struct for ease of debugging Visual Studio debugger takes AGES to show value of any struct members, but even longer for members that are down the list (since it seemingly retrieves them in order, and in order to see the `name` halfway through the struct you need to first see milling data, and weight and its pockets and...) --- src/itype.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/itype.h b/src/itype.h index 4066ca32bfb5f..9b91452458f4d 100644 --- a/src/itype.h +++ b/src/itype.h @@ -1228,6 +1228,14 @@ struct itype { using FlagsSetType = std::set; + protected: + // private because is should only be accessed through itype::nname! + // nname() is used for display purposes + translation name = no_translation( "none" ); + + public: + translation description; // Flavor text + /** * Slots for various item type properties. Each slot may contain a valid pointer or null, check * this before using it. @@ -1390,14 +1398,6 @@ struct itype { // How should the item explode explosion_data explosion; - translation description; // Flavor text - - protected: - // private because is should only be accessed through itype::nname! - // nname() is used for display purposes - translation name = no_translation( "none" ); - - public: // Total of item's material portions (materials->second) int mat_portion_total = 0; From 8cef39204ba4bc86800fbc43c5105c083c062f87 Mon Sep 17 00:00:00 2001 From: moxian Date: Sat, 14 Dec 2024 01:06:25 -0800 Subject: [PATCH 2/7] Jsonify water purification via boiling --- data/json/items/comestibles/drink.json | 8 +++++- doc/JSON_INFO.md | 8 ++++++ src/game_constants.h | 3 -- src/item.cpp | 21 ++++++++++---- src/item_factory.cpp | 38 ++++++++++++++++++++++++++ src/itype.h | 17 ++++++++++++ 6 files changed, 86 insertions(+), 9 deletions(-) diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index d9d107a681cea..31a4c3f15d15e 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -1500,6 +1500,11 @@ "container": "bottle_plastic", "sealed": false, "delete": { "flags": [ "DECAYS_IN_AIR" ] }, + "temperature_effects": [{ + "temperature_above": "373 K", + "transform": "water_clean", + "remove_poison": true + }], "contamination": [ { "disease": "highly_contaminated_food", "probability": 0.1 }, { "disease": "bad_food", "probability": 1 } ] }, { @@ -1508,7 +1513,8 @@ "copy-from": "water", "name": { "str_sp": "murky water" }, "description": "Water, the stuff of life. This water looks like it has quite a bit of life in it in fact, and not the good kind. You should filter and sterilize it if you want to drink it.", - "quench": 30, + "temperature_effects": [], + "quench": 30, "parasites": 5, "contamination": [ { "disease": "highly_contaminated_food", "probability": 100 } ] }, diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index af06b1ced0f57..a6bae946c470f 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -3502,6 +3502,14 @@ Weakpoints only match if they share the same id, so it's important to define the "recipe": "paste_nut_mill_10_1" // Reference to the recipe that performs the task. The syntax is _mill__. The recipe is then defined as a normal recipe for the source with the product as its result and an id_suffix of "mill_X_Y". // See data/json/recipes/food/milling.json for such recipes. Can also use "milling": { "into": "null", "recipe": "" } to override milling from a copied base item. }, +"temperature_effects": [{ // Optional. Specifies certain effects happening to the item when it reaches certain internal temperature thresholds. + // Holds an array of objects + "temperature_above": "373 K", // Temperature needs to be at least this high for the effect to happen. + "temperature_below": "0 K", // Temperature needs to be at least this low for the effect to happen. + // Exactly one of temperature_above and temperature_below must be set. + "transform": "water_clean", // The item id that we transform into upon reaching the temperature. Boiling water gives clean water, as an example. + "remove_poison": true // Whether we should remove poison from comestible item. Defaults to false. +}], "explode_in_fire": true, // Should the item explode if set on fire "nanofab_template_group": "nanofab_recipes", // This item is nanofabricator recipe, and point to itemgroup with items, that it could possibly contain; require nanofab_template_group "template_requirements": "nanofabricator", // `requirement`, that needed to craft any of this templates; used as "one full requirememt per 250 ml of item's volume" - item with volume 750 ml would require three times of `requirement`, item of 2L - eight times of `requirement` diff --git a/src/game_constants.h b/src/game_constants.h index 2a82625d81864..6312a30a81979 100644 --- a/src/game_constants.h +++ b/src/game_constants.h @@ -109,9 +109,6 @@ constexpr units::temperature freezer = units::from_celsius( -5 ); // -5 Celsius // Temperature in which water freezes. constexpr units::temperature freezing = units::from_celsius( 0 ); // 0 Celsius - -// Temperature in which water boils. -constexpr units::temperature boiling = units::from_celsius( 100 ); // 100 Celsius } // namespace temperatures // Slowest speed at which a gun can be aimed. diff --git a/src/item.cpp b/src/item.cpp index 4a06128fdf848..e46ecbe26a2e0 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -182,8 +182,6 @@ static const itype_id itype_rad_badge( "rad_badge" ); static const itype_id itype_rm13_armor( "rm13_armor" ); static const itype_id itype_stock_none( "stock_none" ); static const itype_id itype_tuned_mechanism( "tuned_mechanism" ); -static const itype_id itype_water( "water" ); -static const itype_id itype_water_clean( "water_clean" ); static const itype_id itype_waterproof_gunmod( "waterproof_gunmod" ); static const json_character_flag json_flag_CANNIBAL( "CANNIBAL" ); @@ -13222,9 +13220,22 @@ void item::set_temp_flags( units::temperature new_temperature, float freeze_perc set_flag( flag_COLD ); } - // Convert water into clean water if it starts boiling - if( typeId() == itype_water && new_temperature > temperatures::boiling ) { - convert( itype_water_clean ).poison = 0; + // Execute temperature effects if a new threshold is reached. + // Water turning into clean water when boiling is a canonical example. + const islot_temperature_effects *te_data = type->temperature_effects_data.get(); + if( te_data != nullptr ) { + for( const temperature_effect &eff : te_data->effects ) { + if( eff.temperature_above.has_value() && eff.temperature_above.value() <= new_temperature || + eff.temperature_below.has_value() && eff.temperature_below.value() >= new_temperature + ) { + if( eff.transform_into ) { + convert( eff.transform_into ); + } + if( eff.remove_poison ) { + poison = 0; + } + } + } } } diff --git a/src/item_factory.cpp b/src/item_factory.cpp index ab112f3fb4ae7..6a951e412dbec 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -825,6 +825,19 @@ void Item_factory::finalize_post( itype &obj ) } } } + + // temperature_effects consistency + if( obj.temperature_effects_data ) { + for( const temperature_effect &eff : obj.temperature_effects_data->effects ) { + if( eff.temperature_above.has_value() == eff.temperature_below.has_value() ) { + debugmsg( "Exactly one of temperature_above and temperature_above must be set in %s temperature_effects", + obj.id.str() ); + } + if( !eff.transform_into.is_valid() ) { + debugmsg( "%s is not a valid item id (in %s temperature_effects)", obj.id.str() ); + } + } + } } void Item_factory::finalize_post_armor( itype &obj ) @@ -2667,6 +2680,29 @@ void islot_milling::deserialize( const JsonObject &jo ) load( jo ); } +void temperature_effect::load( const JsonObject &jo ) +{ + optional( jo, was_loaded, "temperature_above", temperature_above ); + optional( jo, was_loaded, "temperature_below", temperature_below ); + optional( jo, was_loaded, "transform", transform_into ); + optional( jo, was_loaded, "remove_poison", remove_poison ); +} + +static void load_temperature_effects( + const JsonObject &jo, const std::string_view member, + cata::value_ptr &slotptr, const std::string &src ) +{ + if( !jo.has_member( member ) ) { + return; + } + slotptr = cata::make_value(); + for( const JsonObject &tejo : jo.get_array( member ) ) { + temperature_effect eff; + eff.load( tejo ); + slotptr->effects.push_back( eff ); + } +} + static void load_memory_card_data( memory_card_info &mcd, const JsonObject &jo ) { mcd.data_chance = jo.get_float( "data_chance", 1.0f ); @@ -4494,6 +4530,8 @@ void Item_factory::load_basic_info( const JsonObject &jo, itype &def, const std: assign( jo, "compostable", def.compostable, src == "dda" ); load_slot_optional( def.relic_data, jo, "relic_data", src ); assign( jo, "milling", def.milling_data, src == "dda" ); + load_temperature_effects( jo, "temperature_effects", def.temperature_effects_data, src ); + // optional gunmod slot may also specify mod data if( jo.has_member( "gunmod_data" ) ) { diff --git a/src/itype.h b/src/itype.h index 9b91452458f4d..d91021d05138a 100644 --- a/src/itype.h +++ b/src/itype.h @@ -1204,6 +1204,22 @@ class islot_milling void deserialize( const JsonObject &jo ); }; +struct temperature_effect{ + std::optional temperature_above; + std::optional temperature_below; + + itype_id transform_into; + bool remove_poison = false; + + bool was_loaded = false; + void load( const JsonObject &jo ); +}; + +struct islot_temperature_effects +{ + std::vector effects; +}; + struct memory_card_info { float data_chance; itype_id on_read_convert_to; @@ -1260,6 +1276,7 @@ struct itype { cata::value_ptr seed; cata::value_ptr relic_data; cata::value_ptr milling_data; + cata::value_ptr temperature_effects_data; /*@}*/ /** Action to take BEFORE the item is placed on map. If it returns non-zero, item won't be placed. */ From c06e5861a3076b57b3f6678e4320136ebfac6293 Mon Sep 17 00:00:00 2001 From: moxian Date: Sat, 14 Dec 2024 02:12:00 -0800 Subject: [PATCH 3/7] Error handling --- src/item_factory.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 6a951e412dbec..851ffc57d563a 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -833,8 +833,9 @@ void Item_factory::finalize_post( itype &obj ) debugmsg( "Exactly one of temperature_above and temperature_above must be set in %s temperature_effects", obj.id.str() ); } - if( !eff.transform_into.is_valid() ) { - debugmsg( "%s is not a valid item id (in %s temperature_effects)", obj.id.str() ); + if( eff.transform_into.is_null() || !eff.transform_into.is_valid() ) { + debugmsg( "'%s' is not a valid item id (in %s temperature_effects)", + eff.transform_into.c_str(), obj.id.str() ); } } } From 01c25e63fb55e3b87c73d7854f65cec74daea336 Mon Sep 17 00:00:00 2001 From: moxian Date: Sat, 14 Dec 2024 02:12:36 -0800 Subject: [PATCH 4/7] typo --- src/itype.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/itype.h b/src/itype.h index d91021d05138a..9c1276dedf5ab 100644 --- a/src/itype.h +++ b/src/itype.h @@ -1245,7 +1245,7 @@ struct itype { using FlagsSetType = std::set; protected: - // private because is should only be accessed through itype::nname! + // private because it should only be accessed through itype::nname! // nname() is used for display purposes translation name = no_translation( "none" ); From 1bb05c1c75442d1d54afd80d483ebf5a2e710760 Mon Sep 17 00:00:00 2001 From: moxian Date: Sat, 14 Dec 2024 02:15:32 -0800 Subject: [PATCH 5/7] json format --- data/json/items/comestibles/drink.json | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/data/json/items/comestibles/drink.json b/data/json/items/comestibles/drink.json index 31a4c3f15d15e..a56bfc1733237 100644 --- a/data/json/items/comestibles/drink.json +++ b/data/json/items/comestibles/drink.json @@ -1500,11 +1500,7 @@ "container": "bottle_plastic", "sealed": false, "delete": { "flags": [ "DECAYS_IN_AIR" ] }, - "temperature_effects": [{ - "temperature_above": "373 K", - "transform": "water_clean", - "remove_poison": true - }], + "temperature_effects": [ { "temperature_above": "373 K", "transform": "water_clean", "remove_poison": true } ], "contamination": [ { "disease": "highly_contaminated_food", "probability": 0.1 }, { "disease": "bad_food", "probability": 1 } ] }, { @@ -1513,8 +1509,8 @@ "copy-from": "water", "name": { "str_sp": "murky water" }, "description": "Water, the stuff of life. This water looks like it has quite a bit of life in it in fact, and not the good kind. You should filter and sterilize it if you want to drink it.", - "temperature_effects": [], - "quench": 30, + "temperature_effects": [ ], + "quench": 30, "parasites": 5, "contamination": [ { "disease": "highly_contaminated_food", "probability": 100 } ] }, From 2338456f94d62975ddbd2c3c58fd487b7878fbbe Mon Sep 17 00:00:00 2001 From: moxian Date: Sat, 14 Dec 2024 02:17:48 -0800 Subject: [PATCH 6/7] astyle once more v_v --- src/itype.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/itype.h b/src/itype.h index 9c1276dedf5ab..3a483e188a832 100644 --- a/src/itype.h +++ b/src/itype.h @@ -1204,7 +1204,7 @@ class islot_milling void deserialize( const JsonObject &jo ); }; -struct temperature_effect{ +struct temperature_effect { std::optional temperature_above; std::optional temperature_below; @@ -1215,8 +1215,7 @@ struct temperature_effect{ void load( const JsonObject &jo ); }; -struct islot_temperature_effects -{ +struct islot_temperature_effects { std::vector effects; }; From c0c6e0008aeec47425a36f1d8781b4e6d5214e09 Mon Sep 17 00:00:00 2001 From: moxian Date: Sat, 14 Dec 2024 04:28:30 -0800 Subject: [PATCH 7/7] clang-tidy --- src/item.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/item.cpp b/src/item.cpp index e46ecbe26a2e0..4d95e278135fe 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -13225,8 +13225,8 @@ void item::set_temp_flags( units::temperature new_temperature, float freeze_perc const islot_temperature_effects *te_data = type->temperature_effects_data.get(); if( te_data != nullptr ) { for( const temperature_effect &eff : te_data->effects ) { - if( eff.temperature_above.has_value() && eff.temperature_above.value() <= new_temperature || - eff.temperature_below.has_value() && eff.temperature_below.value() >= new_temperature + if( ( eff.temperature_above.has_value() && eff.temperature_above.value() <= new_temperature ) || + ( eff.temperature_below.has_value() && eff.temperature_below.value() >= new_temperature ) ) { if( eff.transform_into ) { convert( eff.transform_into );