Skip to content

Commit

Permalink
Jsonify water purification via boiling
Browse files Browse the repository at this point in the history
  • Loading branch information
moxian committed Dec 14, 2024
1 parent 3f9df95 commit 8cef392
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 9 deletions.
8 changes: 7 additions & 1 deletion data/json/items/comestibles/drink.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 } ]
},
{
Expand All @@ -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 } ]
},
Expand Down
8 changes: 8 additions & 0 deletions doc/JSON_INFO.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <product name>_mill_<source amount>_<product amount>. 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`
Expand Down
3 changes: 0 additions & 3 deletions src/game_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
21 changes: 16 additions & 5 deletions src/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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" );
Expand Down Expand Up @@ -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;
}
}
}
}
}

Expand Down
38 changes: 38 additions & 0 deletions src/item_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down Expand Up @@ -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<islot_temperature_effects> &slotptr, const std::string &src )
{
if( !jo.has_member( member ) ) {
return;
}
slotptr = cata::make_value<islot_temperature_effects>();
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 );
Expand Down Expand Up @@ -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" ) ) {
Expand Down
17 changes: 17 additions & 0 deletions src/itype.h
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,22 @@ class islot_milling
void deserialize( const JsonObject &jo );
};

struct temperature_effect{
std::optional<units::temperature> temperature_above;
std::optional<units::temperature> 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<temperature_effect> effects;
};

struct memory_card_info {
float data_chance;
itype_id on_read_convert_to;
Expand Down Expand Up @@ -1260,6 +1276,7 @@ struct itype {
cata::value_ptr<islot_seed> seed;
cata::value_ptr<relic> relic_data;
cata::value_ptr<islot_milling> milling_data;
cata::value_ptr<islot_temperature_effects> temperature_effects_data;
/*@}*/

/** Action to take BEFORE the item is placed on map. If it returns non-zero, item won't be placed. */
Expand Down

0 comments on commit 8cef392

Please sign in to comment.