Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
acba7d3
split off item_vars into its own class
usagirei Oct 15, 2025
3ac7bae
Add array2d class
usagirei Oct 16, 2025
7d3d9af
Make submap use array2d instead of c arrays
usagirei Oct 16, 2025
70e4f0f
Update data_vars
usagirei Oct 16, 2025
000a708
Add reset method to array2d
usagirei Oct 16, 2025
380d27e
Add data_vars support to furniture and terrain
usagirei Oct 16, 2025
7416296
style(autofix.ci): automated formatting
autofix-ci[bot] Oct 16, 2025
73605b4
Move data_vars conversion stuff to separate file
usagirei Oct 17, 2025
dd085ba
add const char* overloads for data_vars to fetch strings directly wit…
usagirei Oct 18, 2025
00a37a1
add basic_converter / json_converter
usagirei Oct 18, 2025
99d5f3f
Merge branch 'main' into data_vars
usagirei Oct 18, 2025
c5de6e1
style(autofix.ci): automated formatting
autofix-ci[bot] Oct 18, 2025
ae62417
add merge function to data_set
usagirei Oct 18, 2025
9cd8c36
Merge branch 'data_vars' of github.com:usagirei/Cataclysm-BN into dat…
usagirei Oct 18, 2025
f0457fa
Merge branch 'main' into data_vars
usagirei Oct 22, 2025
934a9d8
fix merge function
usagirei Oct 22, 2025
5ce4f42
style(autofix.ci): automated formatting
autofix-ci[bot] Oct 22, 2025
6d18f10
remove data_vars basic_converter in favor of json_converter
usagirei Oct 22, 2025
79f2c0d
remove unused using type from array2d
usagirei Oct 22, 2025
fc023d2
make msvc happy?
usagirei Oct 22, 2025
6490e35
change integer types on tests so msvc doesn't complain
usagirei Oct 22, 2025
0354aab
store furniture / terrain vars on-demand on an unordered map instead …
usagirei Oct 22, 2025
6153f49
Merge branch 'main' into data_vars
usagirei Oct 22, 2025
bf5b78a
split off array2d changes into separate branch
usagirei Oct 22, 2025
218aad2
* use templated get_var / set_var for item
usagirei Oct 23, 2025
3b3e2bc
add const char* overload to get_var
usagirei Oct 23, 2025
71a5f39
add const char* overload to set_var
usagirei Oct 23, 2025
8977e6e
wrap json_converter read/write in a try-catch block because throw_on_…
usagirei Oct 23, 2025
ec6b074
Merge branch 'main' into data_vars
usagirei Oct 23, 2025
8f41364
Merge branch 'main' into data_vars
usagirei Nov 4, 2025
e98ead0
Merge branch 'main' into data_vars
usagirei Nov 30, 2025
a1d9a3f
Merge branch 'main' into furnterdatastorage
WishDuck Feb 2, 2026
75600ba
fix json item vars & autoloader
WishDuck Feb 2, 2026
bb4824a
Merge branch 'cataclysmbn:main' into furnterdatastorage
WishDuck Feb 4, 2026
e51a77f
Merge branch 'cataclysmbn:main' into furnterdatastorage
WishDuck Feb 8, 2026
dd3652d
hopefullyfix
WishDuck Feb 8, 2026
62c0bec
didn't mean to remove that
WishDuck Feb 9, 2026
b32a5f0
Merge branch 'main' into furnterdatastorage
WishDuck Feb 16, 2026
b3935d9
emergency fix
WishDuck Feb 16, 2026
7e6101f
another fix for merge
WishDuck Feb 16, 2026
c1382b2
fix json serilize issue
WishDuck Mar 15, 2026
c9c0e4f
feat: add furniture multicooker
WishDuck Mar 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions data/json/construction/construct_workshop.json
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,19 @@
"pre_special": "check_empty",
"post_furniture": "f_oven"
},
{
"type": "construction",
"id": "constr_multicooker",
"group": "install_multicooker",
"category": "WORKSHOP",
"required_skills": [ ],
"time": "10 m",
"qualities": [ ],
"components": [ [ [ "multi_cooker", 1 ] ] ],
"pre_note": "Will only work if constructed in/on a building that has an electric grid with a mounted battery.",
"pre_special": "check_empty",
"post_furniture": "f_multicooker"
},
{
"type": "construction",
"id": "constr_gridfridge",
Expand Down
5 changes: 5 additions & 0 deletions data/json/construction_group.json
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,11 @@
"id": "install_oven",
"name": "Plug In Oven"
},
{
"type": "construction_group",
"id": "install_multicooker",
"name": "Plug In Multi Cooker"
},
{
"type": "construction_group",
"id": "install_refrigerator",
Expand Down
39 changes: 39 additions & 0 deletions data/json/furniture_and_terrain/furniture-appliances.json
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,45 @@
"ranged": { "reduction": [ 4, 8 ], "destroy_threshold": 30, "block_unaimed_chance": "50%" }
}
},
{
"type": "furniture",
"id": "f_multicooker",
"name": "multi cooker",
"looks_like": "f_oven",
"symbol": "#",
"description": "Used for automatic cooking food with electricity.",
"color": "dark_gray",
"move_cost_mod": 2,
"coverage": 60,
"required_str": 10,
"crafting_pseudo_item": "fake_oven",
"flags": [ "PLACE_ITEM", "TRANSPARENT", "FIRE_CONTAINER", "CONTAINER", "BLOCKSDOOR", "MOUNTABLE", "EASY_DECONSTRUCT" ],
"examine_action": "multicooker",
"deconstruct": { "items": [ { "item": "multi_cooker", "count": 1 } ] },
"max_volume": "40 L",
"bash": {
"str_min": 8,
"str_max": 30,
"sound": "metal screeching!",
"sound_fail": "clang!",
"items": [
{ "item": "sheet_metal", "count": [ 1, 4 ] },
{ "item": "sheet_metal_small", "count": [ 8, 12 ] },
{ "item": "steel_chunk", "count": [ 0, 3 ] },
{ "item": "scrap", "count": [ 0, 6 ] },
{ "item": "element", "count": [ 1, 3 ] },
{ "item": "cable", "charges": [ 1, 3 ] },
{ "item": "pilot_light", "count": 1 }
],
"//": "Variable reduction since might hit more or less material.",
"ranged": { "reduction": [ 4, 8 ], "destroy_threshold": 30, "block_unaimed_chance": "50%" }
},
"default_vars": {
"CATEGORYIDS": "[ \"CSC_FOOD_MEAT\", \"CSC_FOOD_VEGGI\", \"CSC_FOOD_PASTA\" ]",
"CHARGE_PER_MIN": "10",
"CHARGE_START": "10"
}
},
{
"type": "furniture",
"id": "f_rvoven",
Expand Down
17 changes: 17 additions & 0 deletions docs/en/mod/json/reference/tiles/furn_and_terrain.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ title: Furniture and Terrain
"message": "The safe is hacksawed open!",
"sound": "Gachunk!",
"byproducts": [{ "item": "scrap", "count": 13 }]
},
"default_vars": {
"CATEGORYIDS": "[ \"CSC_FOOD_MEAT\", \"CSC_FOOD_VEGGI\", \"CSC_FOOD_PASTA\" ]",
"CHARGE_PER_MIN": "5",
"CHARGE_START": "100",
"CRAFTSPEEDMULT": "1.0"
}
}
```
Expand Down Expand Up @@ -171,6 +177,17 @@ it for the purpose of surgery.
(Optional) Dispenses infinite amounts of specified liquid item when interacted. Must be used with
`"examine_action": "liquid_source"` to work.

#### `default_vars`

(Optional) Default string variables for objects, always a string string pair; Can be used to store arbitrary data or for some data for iuses such as

- Multicooker
- "CATEGORYIDS"; String is a json array of categories for applicable recipes
- "RECIPEIDS": String is a json array of valid recipes
- "CHARGE_PER_MIN": Charges consumed per minute
- "CHARGE_START": Charges consumed at start
- "CRAFTSPEEDMULT": Multiplier on craft speed

### Terrain

```json
Expand Down
14 changes: 13 additions & 1 deletion src/assign.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "assign.h"

#include "data_vars.h"
#include <algorithm>

void report_strict_violation( const JsonObject &jo, const std::string &message,
Expand Down Expand Up @@ -695,3 +695,15 @@
}
}
}

bool assign( const JsonObject &jo,
const std::string &name,
data_vars::data_set &val,
const bool strict )

Check warning on line 702 in src/assign.cpp

View workflow job for this annotation

GitHub Actions / build

parameter 'strict' is unused [misc-unused-parameters]

Check warning on line 702 in src/assign.cpp

View workflow job for this annotation

GitHub Actions / build

unused parameter 'strict' [clang-diagnostic-unused-parameter]
{
for( const JsonMember member : jo.get_object( name ) ) {
val[member.name()] = member.get_string();
}
return true;
}

7 changes: 6 additions & 1 deletion src/assign.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "units.h"
#include "units_serde.h"
#include "concepts_utility.h"

#include "data_vars.h"
namespace detail
{
template<typename ...T>
Expand Down Expand Up @@ -424,6 +424,11 @@ bool assign( const JsonObject &jo,
nc_color &val,
const bool strict = false );

bool assign( const JsonObject &jo,
const std::string &name,
data_vars::data_set &val,
const bool strict = false );

class time_duration;

template<typename T>
Expand Down
39 changes: 24 additions & 15 deletions src/catalua_bindings_item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,24 +525,33 @@ void reg_item( sol::state &lua )
SET_FX( convert );

DOC( "Get variable as string" );
luna::set_fx( ut, "get_var_str",
sol::resolve<std::string( const std::string &, const std::string & ) const>
( &item::get_var ) );
luna::set_fx( ut, "get_var_str", []( const UT_CLASS & c, const std::string & name, const std::string & def_val )
{
return c.get_var( name, def_val );
} );
DOC( "Get variable as float number" );
luna::set_fx( ut, "get_var_num",
sol::resolve<double( const std::string &, double ) const>( &item::get_var ) );
luna::set_fx( ut, "get_var_num", []( const UT_CLASS & c, const std::string & name, const double & def_val )
{
return c.get_var( name, def_val );
} );
DOC( "Get variable as tripoint" );
luna::set_fx( ut, "get_var_tri",
sol::resolve<tripoint( const std::string &, const tripoint & ) const>
( &item::get_var ) );

luna::set_fx( ut, "set_var_str", sol::resolve<void( const std::string &, const std::string & )>
( &item::set_var ) );
luna::set_fx( ut, "set_var_num",
sol::resolve<void( const std::string &, double )>( &item::set_var ) );
luna::set_fx( ut, "set_var_tri",
sol::resolve<void( const std::string &, const tripoint & )>( &item::set_var ) );
luna::set_fx( ut, "get_var_tri", []( const UT_CLASS & c, const std::string & name, const tripoint & def_val )
{
return c.get_var( name, def_val );
} );

luna::set_fx( ut, "set_var_str", []( UT_CLASS & c, const std::string & name, const std::string & val )
{
c.set_var( name, val );
} );
luna::set_fx( ut, "set_var_num", []( UT_CLASS & c, const std::string & name, const double & val )
{
c.set_var( name, val );
} );
luna::set_fx( ut, "set_var_tri", []( UT_CLASS & c, const std::string & name, const tripoint & val )
{
c.set_var( name, val );
} );
SET_FX( attack_cost );
SET_FX( stamina_cost );

Expand Down
117 changes: 117 additions & 0 deletions src/data_vars.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#pragma once

#include <map>
#include <string>

#include "data_vars_cvt.h"

namespace data_vars
{

template<typename T>
struct type_converter;

template<typename T>
using type_converter_t = typename type_converter<T>::type;

class data_set
{
public:
using storage = std::map<std::string, std::string>;
using key_type = storage::key_type;
using value_type = storage::value_type;
using mapped_type = storage::mapped_type;
using iterator = storage::iterator;
using const_iterator = storage::const_iterator;

template<typename Value, typename Conv = type_converter_t<Value>>
bool try_get( const std::string &key, Value &out_val, const Conv &converter = {} ) const {
const auto it = _data.find( key );
if( it == _data.end() ) {
return false;
}
return converter( it->second, out_val );
}

template <typename Value, typename Conv = type_converter_t<Value>>
Value get( const std::string &key, const Value &default_value = {}, const Conv &converter = {} )
const {
Value val;
if( !data_set::try_get<Value>( key, val, converter ) ) {
return default_value;
}
return val;
}

template <typename Value, typename Conv = type_converter_t<Value>>
void set( const key_type &name, const Value &value, const Conv &converter = {} ) {
std::string str;
if( !converter( value, str ) ) {
throw std::runtime_error( "failed to convert value to string" );
}
_data[name] = str;
}

bool try_get( const std::string &key, mapped_type &out_val ) const {
const auto it = _data.find( key );
if( it == _data.end() ) {
return false;
}
out_val = it->second;
return true;
}

mapped_type get( const std::string &key, const mapped_type &default_value = {} ) const {
std::string val;
if( !try_get( key, val ) ) {
return default_value;
}
return val;
}

void set( const key_type &name, const mapped_type &value ) {
_data[name] = value;
}

std::string get( const std::string &key, const char *default_value ) const {
std::string val;
if( !try_get( key, val ) ) {
return default_value;
}
return val;
}

void set( const key_type &name, const char *value ) {
_data[name] = std::string{value};
}

void merge( const data_set &other, bool skip_existing = false ) {
for( const auto &[key, value] : other ) {
if( skip_existing && contains( key ) ) {
continue;
}
set( key, value );
}
}

bool operator==( const data_set &other ) const { return ( _data ) == other._data; }
mapped_type &operator[]( const key_type &name ) { return _data[name]; }

bool empty() const { return _data.empty(); }
bool contains( const key_type &key ) const { return _data.contains( key ); }
iterator begin() { return _data.begin(); }
const_iterator begin() const { return _data.begin(); }
iterator end() { return _data.end(); }
const_iterator end() const { return _data.end(); }
iterator find( const key_type &key ) { return _data.find( key ); }
const_iterator find( const key_type &key ) const { return _data.find( key ); }

void clear() { _data.clear(); }
void erase( const key_type &name ) { _data.erase( name ); }
void erase( const iterator it ) { _data.erase( it ); }

private:
storage _data;
};

} // namespace data_vars
51 changes: 51 additions & 0 deletions src/data_vars_cvt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once

#include <sstream>
#include <iomanip>

#include "point.h"
#include "json.h"
#include "cata_utility.h"

namespace data_vars
{

template<typename T>
struct json_converter {
using value_type = T;

// Need a try-catch blocks because JsonIn/Out
// Doesn't care if you ask it to not throw on error
// And may just do so anyway

bool operator()( const T &in_val, std::string &out_val ) const {
try {
std::ostringstream os;
JsonOut jsout{os};
jsout.write( in_val );
out_val = os.str();
return true;
} catch( JsonError &e ) {
debugmsg( "Error writing value: %s", e.what() );
return false;
}
}

bool operator()( const std::string &in_val, T &out_val ) const {
try {
std::istringstream is{in_val};
JsonIn jsin{is};
return jsin.read( out_val, false );
} catch( JsonError &e ) {
debugmsg( "Error reading value '%s': %s", in_val, e.what() );
return false;
}
}
};

template<typename T>
struct type_converter {
using type = json_converter<T>;
};

} // namespace data_vars
Loading
Loading