diff --git a/data/json/items/generic.json b/data/json/items/generic.json index 774c727135384..d1c62150a9b2c 100644 --- a/data/json/items/generic.json +++ b/data/json/items/generic.json @@ -295,7 +295,8 @@ "material": [ "steel" ], "techniques": [ "WRAP" ], "volume": "1 L", - "bashing": 12, + "bashing": 26, + "to_hit": -2, "price": 8000, "price_postapoc": 50 }, diff --git a/data/json/items/melee/bludgeons.json b/data/json/items/melee/bludgeons.json index a482bd0302df4..997d7bf51a3d1 100644 --- a/data/json/items/melee/bludgeons.json +++ b/data/json/items/melee/bludgeons.json @@ -9,7 +9,7 @@ "volume": "3750 ml", "price": 25000, "price_postapoc": 3000, - "bashing": 40, + "bashing": 50, "material": [ "wood", "steel" ], "symbol": "\\", "color": "dark_gray", @@ -26,7 +26,7 @@ "volume": "3750 ml", "price": 4000, "price_postapoc": 1000, - "bashing": 19, + "bashing": 26, "material": [ "wood" ], "symbol": "\\", "color": "brown", @@ -474,13 +474,13 @@ "name": { "str": "homewrecker" }, "description": "A long piece of wood with several chunks of steel firmly tied to it. The resulting weapon is unwieldy and slow but very heavy hitting.", "weight": "3024 g", - "to_hit": -3, + "to_hit": -2, "color": "brown", "symbol": "/", "material": [ "wood", "steel" ], "techniques": [ "WBLOCK_1" ], "volume": "1250 ml", - "bashing": 28, + "bashing": 35, "cutting": 2, "qualities": [ [ "HAMMER", 1 ] ], "flags": [ "STAB", "NONCONDUCTIVE" ], @@ -661,7 +661,7 @@ "flags": [ "BELT_CLIP", "NONCONDUCTIVE" ], "weight": "400 g", "volume": "350 ml", - "bashing": 9, + "bashing": 12, "to_hit": 1, "price_postapoc": 50, "category": "weapons" @@ -689,14 +689,14 @@ "name": { "str": "morningstar" }, "description": "A medieval weapon consisting of a wood handle with a heavy, spiked iron ball on the end. It deals devastating crushing damage, with a small amount of piercing to boot.", "weight": "1400 g", - "to_hit": 1, + "to_hit": -1, "color": "dark_gray", "symbol": "/", "material": [ "iron", "wood" ], "techniques": [ "SWEEP" ], "volume": "1500 ml", - "bashing": 33, - "cutting": 4, + "bashing": 38, + "cutting": 6, "flags": [ "DURABLE_MELEE", "SPEAR", "NONCONDUCTIVE" ], "price": 120000, "price_postapoc": 8000, @@ -708,14 +708,14 @@ "name": { "str": "morningstar" }, "description": "A light, cheaply made replica of a medieval weapon that would normally consist of a wood handle with a heavy, spiked iron ball on the end.", "weight": "700 g", - "to_hit": 1, + "to_hit": -1, "color": "dark_gray", "symbol": "/", "looks_like": "morningstar", "material": [ "aluminum", "wood" ], "techniques": [ "SWEEP" ], "volume": "1500 ml", - "bashing": 8, + "bashing": 26, "cutting": 1, "flags": [ "SPEAR", "NONCONDUCTIVE" ], "price": 12000, @@ -727,14 +727,14 @@ "name": { "str": "morningstar" }, "description": "A medieval weapon consisting of a wood handle with a heavy, spiked iron ball on the end. That end feels lighter than it should.", "weight": "1000 g", - "to_hit": 1, + "to_hit": -1, "color": "dark_gray", "symbol": "/", "looks_like": "morningstar", "material": [ "budget_steel", "wood" ], "techniques": [ "SWEEP" ], "volume": "1500 ml", - "bashing": 11, + "bashing": 26, "cutting": 1, "flags": [ "SPEAR", "NONCONDUCTIVE" ], "price": 12000, @@ -862,7 +862,7 @@ "weight": "1007 g", "volume": "500 ml", "bashing": 8, - "to_hit": 1, + "to_hit": -1, "qualities": [ [ "HAMMER", 1 ] ] }, { diff --git a/src/character.cpp b/src/character.cpp index 8fc17e136dc4e..281c78cb51c1f 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -6360,7 +6360,7 @@ float Character::active_light() const lumination = static_cast( maxlum ); float mut_lum = 0.0f; - for( const std::pair &mut : my_mutations ) { + for( const std::pair &mut : my_mutations ) { if( mut.second.powered ) { float curr_lum = 0.0f; for( const auto elem : mut.first->lumination ) { @@ -7953,7 +7953,7 @@ void Character::recalculate_enchantment_cache() } // get from traits/ mutations - for( const std::pair &mut_map : my_mutations ) { + for( const std::pair &mut_map : my_mutations ) { const mutation_branch &mut = mut_map.first.obj(); // only add the passive or powered active mutations diff --git a/src/event.cpp b/src/event.cpp index c0daa07ac241d..2e42f49f433c5 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -138,7 +138,7 @@ DEFINE_EVENT_FIELDS( teleports_into_wall ) } // namespace event_detail template -static void get_fields_if_match( event_type type, std::map &out ) +static void get_fields_if_match( event_type type, event::fields_type &out ) { if( Type == type ) { out = { event_detail::event_spec::fields.begin(), @@ -148,10 +148,10 @@ static void get_fields_if_match( event_type type, std::map -static std::map +static event::fields_type get_fields_helper( event_type type, std::integer_sequence ) { - std::map result; + event::fields_type result; bool discard[] = { ( get_fields_if_match( I )>( type, result ), true )... }; @@ -159,7 +159,7 @@ get_fields_helper( event_type type, std::integer_sequence ) return result; } -std::map event::get_fields( event_type type ) +event::fields_type event::get_fields( event_type type ) { return get_fields_helper( type, std::make_integer_sequence( event_type::num_event_types )> {} ); diff --git a/src/event.h b/src/event.h index e5a42030cffe9..f618bb6c23f54 100644 --- a/src/event.h +++ b/src/event.h @@ -558,7 +558,8 @@ class event > ()( calendar::turn, std::forward( args )... ); } - static std::map get_fields( event_type ); + using fields_type = std::unordered_map; + static fields_type get_fields( event_type ); event_type type() const { return type_; @@ -577,6 +578,14 @@ class event return it->second; } + cata_variant get_variant_or_void( const std::string &key ) const { + auto it = data_.find( key ); + if( it == data_.end() ) { + return cata_variant(); + } + return it->second; + } + template auto get( const std::string &key ) const { return get_variant( key ).get(); diff --git a/src/event_field_transformations.cpp b/src/event_field_transformations.cpp index 719b57824879c..8239678e62bcf 100644 --- a/src/event_field_transformations.cpp +++ b/src/event_field_transformations.cpp @@ -17,6 +17,9 @@ static std::vector species_of_monster( const cata_variant &v ) return result; } -const std::unordered_map event_field_transformations = { - { "species_of_monster", species_of_monster }, +const std::unordered_map event_field_transformations = { + { + "species_of_monster", + { species_of_monster, cata_variant_type::species_id, { cata_variant_type::mtype_id } } + }, }; diff --git a/src/event_field_transformations.h b/src/event_field_transformations.h index 55b1f3d4a8cd9..e8c4362a88535 100644 --- a/src/event_field_transformations.h +++ b/src/event_field_transformations.h @@ -8,7 +8,14 @@ #include "cata_variant.h" -using EventFieldTransformation = std::vector( * )( const cata_variant & ); -extern const std::unordered_map event_field_transformations; +struct event_field_transformation { + using function_type = std::vector( * )( const cata_variant & ); + function_type function; + cata_variant_type return_type; + std::vector argument_types; +}; + +extern const std::unordered_map +event_field_transformations; #endif // CATA_SRC_EVENT_FIELD_TRANSFORMATIONS_H diff --git a/src/event_statistics.cpp b/src/event_statistics.cpp index 28e57c5aa25b9..0b9f0fc6784cf 100644 --- a/src/event_statistics.cpp +++ b/src/event_statistics.cpp @@ -145,6 +145,7 @@ class event_transformation::impl virtual event_multiset initialize( stats_tracker & ) const = 0; virtual std::unique_ptr watch( stats_tracker & ) const = 0; virtual void check( const std::string &/*name*/ ) const {} + virtual cata::event::fields_type fields() const = 0; virtual monotonically monotonicity() const = 0; virtual std::unique_ptr clone() const = 0; }; @@ -156,6 +157,7 @@ class event_statistic::impl virtual cata_variant value( stats_tracker & ) const = 0; virtual std::unique_ptr watch( stats_tracker & ) const = 0; virtual void check( const std::string &/*name*/ ) const {} + virtual cata_variant_type type() const = 0; virtual monotonically monotonicity() const = 0; virtual std::unique_ptr clone() const = 0; }; @@ -200,10 +202,31 @@ struct value_constraint { } } - void check( const std::string &name ) const { - if( equals_statistic_ && !equals_statistic_->is_valid() ) { - debugmsg( "constraint for event_transformation %s refers to invalid statistic %s", - name, equals_statistic_->str() ); + void check( const std::string &name, const cata_variant_type input_type ) const { + if( equals_statistic_ ) { + if( !equals_statistic_->is_valid() ) { + debugmsg( "constraint for event_transformation %s refers to invalid statistic %s", + name, equals_statistic_->str() ); + return; + } + + cata_variant_type stat_type = ( *equals_statistic_ )->type(); + if( stat_type != input_type ) { + debugmsg( "constraint for event_transformation %s matches statistic %s of " + "different type. Statistic has type %s but value compared with it has " + "type %s", + name, equals_statistic_->str(), io::enum_to_string( stat_type ), + io::enum_to_string( input_type ) ); + } + } + + if( equals_ ) { + if( input_type != equals_->type() ) { + debugmsg( "constraint for event_transformation %s matches constant of type %s but " + "value compared with it has type %s", + name, io::enum_to_string( equals_->type() ), + io::enum_to_string( input_type ) ); + } } } @@ -214,7 +237,7 @@ struct value_constraint { }; struct new_field { - EventFieldTransformation transformation; + event_field_transformation transformation; std::string input_field; void deserialize( JsonIn &jsin ) { @@ -235,20 +258,46 @@ struct new_field { } } + void check( const std::string &context_name, + const cata::event::fields_type &input_fields ) const { + auto it = input_fields.find( input_field ); + if( it == input_fields.end() ) { + debugmsg( "event_transformation %s specifies transformation on field %s but not such " + "field exists on the input", context_name, input_field ); + return; + } + if( transformation.argument_types.size() != 1 ) { + debugmsg( "event_field_transformations of arity not 1 not supported" ); + return; + } + if( it->second != transformation.argument_types[0] ) { + debugmsg( "event_transformation %s specifies transformation on field %s of incorrect " + "type. Transformation expects %s; field was %s.", context_name, input_field, + io::enum_to_string( transformation.argument_types[0] ), + io::enum_to_string( it->second ) ); + } + } + std::vector transform( const cata::event::data_type &data, const std::string &new_field_name ) const { std::vector result; auto it = data.find( input_field ); if( it == data.end() ) { - debugmsg( "Expected input field '%s' not present in event", input_field ); + // Field missing, probably due to stale data. Reporting an error + // would spam, so we rely on the fact that it should already have + // been reported at startup time. return result; } - for( cata_variant v : transformation( it->second ) ) { + for( cata_variant v : transformation.function( it->second ) ) { result.push_back( data ); result.back().emplace( new_field_name, v ); } return result; } + + cata_variant_type type( const cata::event::fields_type &/*input*/ ) const { + return transformation.return_type; + } }; // Helper struct to abstract the two possible sources of event_multisets: @@ -278,6 +327,22 @@ struct event_source { } } + std::string debug_description() const { + if( transformation.is_empty() ) { + return "event type " + io::enum_to_string( type ); + } else { + return "event_transformation " + transformation->id.str(); + } + } + + bool is_game_start() const { + if( transformation.is_empty() ) { + return type == event_type::game_start; + } else { + return false; + } + } + void add_watcher( stats_tracker &stats, event_multiset_watcher *watcher ) const { if( transformation.is_empty() ) { stats.add_watcher( type, watcher ); @@ -286,6 +351,14 @@ struct event_source { } } + cata::event::fields_type fields() const { + if( transformation.is_empty() ) { + return cata::event::get_fields( type ); + } else { + return transformation->fields(); + } + } + monotonically monotonicity() const { if( transformation.is_empty() ) { return monotonically::increasing; @@ -369,6 +442,35 @@ struct event_transformation_impl : public event_transformation::impl { return initialize( source_.get( stats ).counts(), stats ); } + void check( const std::string &name ) const override { + const cata::event::fields_type input_fields = source_.fields(); + + for( const std::pair &p : new_fields_ ) { + if( input_fields.count( p.first ) ) { + debugmsg( "event_transformation %s tries to add field with name %s but a field " + "with that name already exists", name, p.first ); + } + p.second.check( name, input_fields ); + } + + for( const std::pair &p : constraints_ ) { + auto it = input_fields.find( p.first ); + if( it == input_fields.end() ) { + debugmsg( "event_transformation %s applies constraint to field %s, but no field " + "with that name exists in the input", name, p.first ); + } else { + p.second.check( name, it->second ); + } + } + + for( const std::string drop_field_name : drop_fields_ ) { + if( input_fields.find( drop_field_name ) == input_fields.end() ) { + debugmsg( "event_transformation %s lists field %s to be dropped, but no field " + "with that name exists in the input", name, drop_field_name ); + } + } + } + struct state : stats_tracker_state, event_multiset_watcher, stat_watcher { state( const event_transformation_impl *trans, stats_tracker &stats ) : transformation_( trans ), @@ -408,10 +510,18 @@ struct event_transformation_impl : public event_transformation::impl { return std::make_unique( this, stats ); } - void check( const std::string &name ) const override { - for( const std::pair &p : constraints_ ) { - p.second.check( name ); + cata::event::fields_type fields() const override { + cata::event::fields_type result = source_.fields(); + + for( const std::pair &p : new_fields_ ) { + result.emplace( p.first, p.second.type( result ) ); + } + + for( const std::string drop_field_name : drop_fields_ ) { + result.erase( drop_field_name ); } + + return result; } monotonically monotonicity() const override { @@ -460,6 +570,11 @@ void event_transformation::check() const impl_->check( id.str() ); } +cata::event::fields_type event_transformation::fields() const +{ + return impl_->fields(); +} + monotonically event_transformation::monotonicity() const { return impl_->monotonicity(); @@ -504,6 +619,10 @@ struct event_statistic_count : event_statistic::impl { return std::make_unique( this, stats ); } + cata_variant_type type() const override { + return cata_variant_type::int_; + } + monotonically monotonicity() const override { return source.monotonicity(); } @@ -553,6 +672,10 @@ struct event_statistic_total : event_statistic::impl { return std::make_unique( this, stats ); } + cata_variant_type type() const override { + return cata_variant_type::int_; + } + monotonically monotonicity() const override { return source.monotonicity(); } @@ -563,17 +686,17 @@ struct event_statistic_total : event_statistic::impl { }; struct event_statistic_unique_value : event_statistic::impl { - event_statistic_unique_value( const string_id &id, event_type type, + event_statistic_unique_value( const string_id &id, const event_source &s, const std::string &field ) : - id_( id ), type_( type ), field_( field ) + id_( id ), source_( s ), field_( field ) {} string_id id_; - event_type type_; + event_source source_; std::string field_; cata_variant value( stats_tracker &stats ) const override { - const event_multiset::counts_type &counts = stats.get_events( type_ ).counts(); + const event_multiset::counts_type counts = source_.get( stats ).counts(); if( counts.size() != 1 ) { return cata_variant(); } @@ -590,18 +713,18 @@ struct event_statistic_unique_value : event_statistic::impl { state( const event_statistic_unique_value *s, stats_tracker &stats ) : stat( s ) { init( stats ); - stats.add_watcher( stat->type_, this ); + stat->source_.add_watcher( stats, this ); } void init( stats_tracker &stats ) { - count = stats.get_events( stat->type_ ).count(); + count = stat->source_.get( stats ).count(); value = stat->value( stats ); } void event_added( const cata::event &e, stats_tracker &stats ) override { ++count; if( count == 1 ) { - value = e.get_variant( stat->field_ ); + value = e.get_variant_or_void( stat->field_ ); } else if( count == 2 ) { value = cata_variant(); } else { @@ -625,16 +748,26 @@ struct event_statistic_unique_value : event_statistic::impl { } void check( const std::string &name ) const override { - std::map event_fields = cata::event::get_fields( type_ ); + cata::event::fields_type event_fields = source_.fields(); auto it = event_fields.find( field_ ); if( it == event_fields.end() ) { - debugmsg( "event_statistic %s refers to field %s in event_type %s, but that type has " - "no such field", name, field_, io::enum_to_string( type_ ) ); + debugmsg( "event_statistic %s refers to field %s in event source %s, but that source " + "has no such field", name, field_, source_.debug_description() ); + } + } + + cata_variant_type type() const override { + cata::event::fields_type source_fields = source_.fields(); + auto it = source_fields.find( field_ ); + if( it == source_fields.end() ) { + return cata_variant_type::void_; + } else { + return it->second; } } monotonically monotonicity() const override { - if( type_ == event_type::game_start ) { + if( source_.is_game_start() ) { return monotonically::constant; } else { return monotonically::unknown; @@ -686,6 +819,11 @@ void event_statistic::check() const impl_->check( id.str() ); } +cata_variant_type event_statistic::type() const +{ + return impl_->type(); +} + monotonically event_statistic::monotonicity() const { return impl_->monotonicity(); diff --git a/src/event_statistics.h b/src/event_statistics.h index bae47d0676f08..197e64e4e75aa 100644 --- a/src/event_statistics.h +++ b/src/event_statistics.h @@ -4,6 +4,7 @@ #include #include +#include #include #include "clone_ptr.h" @@ -11,6 +12,7 @@ #include "translations.h" class cata_variant; +enum class cata_variant_type : int; class event_multiset; enum class event_type : int; class JsonObject; @@ -18,6 +20,8 @@ enum class monotonically : int; class stats_tracker; class stats_tracker_state; +using event_fields_type = std::unordered_map; + // event_tansformations and event_statistics are both functions of events. // They are intended to be calculated via a stats_tracker object. // They can be defined in json, and are useful therein for the creation of @@ -48,6 +52,7 @@ class event_transformation string_id id; bool was_loaded = false; + event_fields_type fields() const; monotonically monotonicity() const; class impl; @@ -75,6 +80,7 @@ class event_statistic return description_; } + cata_variant_type type() const; monotonically monotonicity() const; class impl; diff --git a/src/json.h b/src/json.h index fdedbb6750fae..61844e9593b4f 100644 --- a/src/json.h +++ b/src/json.h @@ -1412,7 +1412,7 @@ void deserialize( cata::optional &obj, JsonIn &jsin ) obj.reset(); } else { obj.emplace(); - jsin.read( *obj ); + jsin.read( *obj, true ); } } diff --git a/src/units.h b/src/units.h index c457606ceccca..9b76e51c45dce 100644 --- a/src/units.h +++ b/src/units.h @@ -700,7 +700,7 @@ T read_from_json_string( JsonIn &jsin, const std::vector