diff --git a/src/condition.cpp b/src/condition.cpp index ea2d262c30fae..d4d6290a9cfc6 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -76,10 +76,11 @@ struct deferred_math { }; struct condition_parser { - using f_t = void ( conditional_t::* )( const JsonObject &, std::string_view ); - using f_t_beta = void ( conditional_t::* )( const JsonObject &, std::string_view, bool ); - using f_t_simple = void ( conditional_t::* )(); - using f_t_beta_simple = void ( conditional_t::* )( bool ); + using condition_func = conditional_t::func; + using f_t = condition_func( * )( const JsonObject &, std::string_view ); + using f_t_beta = condition_func( * )( const JsonObject &, std::string_view, bool ); + using f_t_simple = condition_func( * )(); + using f_t_beta_simple = condition_func( * )( bool ); condition_parser( std::string_view key_alpha_, jarg arg_, f_t f_ ) : key_alpha( key_alpha_ ), arg( arg_ ), f( f_ ) {} @@ -127,7 +128,7 @@ std::shared_ptr &defer_math( std::string_view str, bool ass ) return get_deferred_math().back().exp; } -} // namespace +} // namespace std::string get_talk_varname( const JsonObject &jo, std::string_view member, bool check_value, dbl_or_var &default_val ) @@ -444,7 +445,7 @@ static bodypart_id get_bp_from_str( const std::string &ctxt ) } void read_condition( const JsonObject &jo, const std::string &member_name, - std::function &condition, bool default_val ) + conditional_t::func &condition, bool default_val ) { const auto null_function = [default_val]( dialogue const & ) { return default_val; @@ -479,13 +480,74 @@ void finalize_conditions() } } -void conditional_t::set_has_any_trait( const JsonObject &jo, std::string_view member, bool is_npc ) +static std::string get_string_from_input( const JsonArray &objects, int index ) +{ + if( objects.has_string( index ) ) { + std::string type = objects.get_string( index ); + if( type == "u" || type == "npc" ) { + return type; + } + } + dbl_or_var empty; + JsonObject object = objects.get_object( index ); + if( object.has_string( "u_val" ) ) { + return "u_" + get_talk_varname( object, "u_val", false, empty ); + } else if( object.has_string( "npc_val" ) ) { + return "npc_" + get_talk_varname( object, "npc_val", false, empty ); + } else if( object.has_string( "global_val" ) ) { + return "global_" + get_talk_varname( object, "global_val", false, empty ); + } else if( object.has_string( "context_val" ) ) { + return "context_" + get_talk_varname( object, "context_val", false, empty ); + } else if( object.has_string( "faction_val" ) ) { + return "faction_" + get_talk_varname( object, "faction_val", false, empty ); + } else if( object.has_string( "party_val" ) ) { + return "party_" + get_talk_varname( object, "party_val", false, empty ); + } + object.throw_error( "Invalid input type." ); + return ""; +} + +static tripoint_abs_ms get_tripoint_from_string( const std::string &type, dialogue const &d ) +{ + if( type == "u" ) { + return d.actor( false )->global_pos(); + } else if( type == "npc" ) { + return d.actor( true )->global_pos(); + } else if( type.find( "u_" ) == 0 ) { + var_info var = var_info( var_type::u, type.substr( 2, type.size() - 2 ) ); + return get_tripoint_from_var( var, d ); + } else if( type.find( "npc_" ) == 0 ) { + var_info var = var_info( var_type::npc, type.substr( 4, type.size() - 4 ) ); + return get_tripoint_from_var( var, d ); + } else if( type.find( "global_" ) == 0 ) { + var_info var = var_info( var_type::global, type.substr( 7, type.size() - 7 ) ); + return get_tripoint_from_var( var, d ); + } else if( type.find( "faction_" ) == 0 ) { + var_info var = var_info( var_type::faction, type.substr( 8, type.size() - 8 ) ); + return get_tripoint_from_var( var, d ); + } else if( type.find( "party_" ) == 0 ) { + var_info var = var_info( var_type::party, type.substr( 6, type.size() - 6 ) ); + return get_tripoint_from_var( var, d ); + } else if( type.find( "context_" ) == 0 ) { + var_info var = var_info( var_type::context, type.substr( 8, type.size() - 8 ) ); + return get_tripoint_from_var( var, d ); + } + return tripoint_abs_ms(); +} + + +namespace conditional_fun +{ +namespace +{ + +conditional_t::func f_has_any_trait( const JsonObject &jo, std::string_view member, bool is_npc ) { std::vector traits_to_check; for( JsonValue jv : jo.get_array( member ) ) { traits_to_check.emplace_back( get_str_or_var( jv, member ) ); } - condition = [traits_to_check, is_npc]( dialogue const & d ) { + return [traits_to_check, is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); for( const str_or_var &trait : traits_to_check ) { if( actor->has_trait( trait_id( trait.evaluate( d ) ) ) ) { @@ -496,19 +558,19 @@ void conditional_t::set_has_any_trait( const JsonObject &jo, std::string_view me }; } -void conditional_t::set_has_trait( const JsonObject &jo, std::string_view member, bool is_npc ) +conditional_t::func f_has_trait( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var trait_to_check = get_str_or_var( jo.get_member( member ), member, true ); - condition = [trait_to_check, is_npc]( dialogue const & d ) { + return [trait_to_check, is_npc]( dialogue const & d ) { return d.actor( is_npc )->has_trait( trait_id( trait_to_check.evaluate( d ) ) ); }; } -void conditional_t::set_has_visible_trait( const JsonObject &jo, std::string_view member, +conditional_t::func f_has_visible_trait( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var trait_to_check = get_str_or_var( jo.get_member( member ), member, true ); - condition = [trait_to_check, is_npc]( dialogue const & d ) { + return [trait_to_check, is_npc]( dialogue const & d ) { const talker *observer = d.actor( !is_npc ); const talker *observed = d.actor( is_npc ); int visibility_cap = observer->get_character()->get_mutation_visibility_cap( @@ -520,20 +582,20 @@ void conditional_t::set_has_visible_trait( const JsonObject &jo, std::string_vie }; } -void conditional_t::set_has_martial_art( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_martial_art( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var style_to_check = get_str_or_var( jo.get_member( member ), member, true ); - condition = [style_to_check, is_npc]( dialogue const & d ) { + return [style_to_check, is_npc]( dialogue const & d ) { return d.actor( is_npc )->knows_martial_art( matype_id( style_to_check.evaluate( d ) ) ); }; } -void conditional_t::set_has_flag( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_flag( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var trait_flag_to_check = get_str_or_var( jo.get_member( member ), member, true ); - condition = [trait_flag_to_check, is_npc]( dialogue const & d ) { + return [trait_flag_to_check, is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); if( json_character_flag( trait_flag_to_check.evaluate( d ) ) == json_flag_MUTATION_THRESHOLD ) { return actor->crossed_threshold(); @@ -542,62 +604,72 @@ void conditional_t::set_has_flag( const JsonObject &jo, std::string_view member, }; } -void conditional_t::set_has_species( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_species( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var species_to_check = get_str_or_var( jo.get_member( member ), member, true ); - condition = [species_to_check, is_npc]( dialogue const & d ) { + return [species_to_check, is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); return actor->has_species( species_id( species_to_check.evaluate( d ) ) ); }; } -void conditional_t::set_bodytype( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_bodytype( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var bt_to_check = get_str_or_var( jo.get_member( member ), member, true ); - condition = [bt_to_check, is_npc]( dialogue const & d ) { + return [bt_to_check, is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); return actor->bodytype( bodytype_id( bt_to_check.evaluate( d ) ) ); }; } -void conditional_t::set_has_activity( bool is_npc ) +conditional_t::func f_has_activity( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->has_activity(); }; } -void conditional_t::set_has_proficiency( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_activity( const JsonObject &, std::string_view, bool is_npc ) +{ + return f_has_activity( is_npc ); +} + +conditional_t::func f_has_proficiency( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var proficiency_to_check = get_str_or_var( jo.get_member( member ), member, true ); - condition = [proficiency_to_check, is_npc]( dialogue const & d ) { + return [proficiency_to_check, is_npc]( dialogue const & d ) { return d.actor( is_npc )->knows_proficiency( proficiency_id( proficiency_to_check.evaluate( d ) ) ); }; } -void conditional_t::set_is_riding( bool is_npc ) +conditional_t::func f_is_riding( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->is_mounted(); }; } -void conditional_t::set_npc_has_class( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_is_riding( const JsonObject &, std::string_view, bool is_npc ) +{ + return f_is_riding( is_npc ); +} + +conditional_t::func f_npc_has_class( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var class_to_check = get_str_or_var( jo.get_member( member ), member, true ); - condition = [class_to_check, is_npc]( dialogue const & d ) { + return [class_to_check, is_npc]( dialogue const & d ) { return d.actor( is_npc )->is_myclass( npc_class_id( class_to_check.evaluate( d ) ) ); }; } -void conditional_t::set_u_has_mission( const JsonObject &jo, std::string_view member ) +conditional_t::func f_u_has_mission( const JsonObject &jo, std::string_view member ) { str_or_var u_mission = get_str_or_var( jo.get_member( member ), member, true ); - condition = [u_mission]( dialogue const & d ) { + return [u_mission]( dialogue const & d ) { for( mission *miss_it : get_avatar().get_active_missions() ) { if( miss_it->mission_id() == mission_type_id( u_mission.evaluate( d ) ) ) { return true; @@ -607,11 +679,11 @@ void conditional_t::set_u_has_mission( const JsonObject &jo, std::string_view me }; } -void conditional_t::set_u_monsters_in_direction( const JsonObject &jo, +conditional_t::func f_u_monsters_in_direction( const JsonObject &jo, std::string_view member ) { str_or_var dir = get_str_or_var( jo.get_member( member ), member, true ); - condition = [dir]( dialogue const & d ) { + return [dir]( dialogue const & d ) { //This string_to_enum function is defined in widget.h. Should it be moved? const int card_dir = static_cast( io::string_to_enum( dir.evaluate( d ) ) ); @@ -620,10 +692,10 @@ void conditional_t::set_u_monsters_in_direction( const JsonObject &jo, }; } -void conditional_t::set_u_safe_mode_trigger( const JsonObject &jo, std::string_view member ) +conditional_t::func f_u_safe_mode_trigger( const JsonObject &jo, std::string_view member ) { str_or_var dir = get_str_or_var( jo.get_member( member ), member, true ); - condition = [dir]( dialogue const & d ) { + return [dir]( dialogue const & d ) { //This string_to_enum function is defined in widget.h. Should it be moved? const int card_dir = static_cast( io::string_to_enum( dir.evaluate( d ) ) ); @@ -631,10 +703,10 @@ void conditional_t::set_u_safe_mode_trigger( const JsonObject &jo, std::string_v }; } -void conditional_t::set_u_profession( const JsonObject &jo, std::string_view member ) +conditional_t::func f_u_profession( const JsonObject &jo, std::string_view member ) { str_or_var u_profession = get_str_or_var( jo.get_member( member ), member, true ); - condition = [u_profession]( dialogue const & d ) { + return [u_profession]( dialogue const & d ) { const profession *prof = get_player_character().get_profession(); std::set hobbies = get_player_character().get_hobbies(); if( prof->get_profession_id() == profession_id( u_profession.evaluate( d ) ) ) { @@ -653,99 +725,99 @@ void conditional_t::set_u_profession( const JsonObject &jo, std::string_view mem }; } -void conditional_t::set_has_strength( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_strength( const JsonObject &jo, std::string_view member, + bool is_npc ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov, is_npc]( dialogue & d ) { + return [dov, is_npc]( dialogue & d ) { return d.actor( is_npc )->str_cur() >= dov.evaluate( d ); }; } -void conditional_t::set_has_dexterity( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_dexterity( const JsonObject &jo, std::string_view member, + bool is_npc ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov, is_npc]( dialogue & d ) { + return [dov, is_npc]( dialogue & d ) { return d.actor( is_npc )->dex_cur() >= dov.evaluate( d ); }; } -void conditional_t::set_has_intelligence( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_intelligence( const JsonObject &jo, std::string_view member, + bool is_npc ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov, is_npc]( dialogue & d ) { + return [dov, is_npc]( dialogue & d ) { return d.actor( is_npc )->int_cur() >= dov.evaluate( d ); }; } -void conditional_t::set_has_perception( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_perception( const JsonObject &jo, std::string_view member, + bool is_npc ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov, is_npc]( dialogue & d ) { + return [dov, is_npc]( dialogue & d ) { return d.actor( is_npc )->per_cur() >= dov.evaluate( d ); }; } -void conditional_t::set_has_hp( const JsonObject &jo, std::string_view member, bool is_npc ) +conditional_t::func f_has_hp( const JsonObject &jo, std::string_view member, bool is_npc ) { dbl_or_var dov = get_dbl_or_var( jo, member ); std::optional bp; optional( jo, false, "bodypart", bp ); - condition = [dov, bp, is_npc]( dialogue & d ) { + return [dov, bp, is_npc]( dialogue & d ) { bodypart_id bid = bp.value_or( get_bp_from_str( d.reason ) ); return d.actor( is_npc )->get_cur_hp( bid ) >= dov.evaluate( d ); }; } -void conditional_t::set_has_part_temp( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_part_temp( const JsonObject &jo, std::string_view member, + bool is_npc ) { dbl_or_var dov = get_dbl_or_var( jo, member ); std::optional bp; optional( jo, false, "bodypart", bp ); - condition = [dov, bp, is_npc]( dialogue & d ) { + return [dov, bp, is_npc]( dialogue & d ) { bodypart_id bid = bp.value_or( get_bp_from_str( d.reason ) ); return units::to_legacy_bodypart_temp( d.actor( is_npc )->get_cur_part_temp( bid ) ) >= dov.evaluate( d ); }; } -void conditional_t::set_is_wearing( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_is_wearing( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var item_id = get_str_or_var( jo.get_member( member ), member, true ); - condition = [item_id, is_npc]( dialogue const & d ) { + return [item_id, is_npc]( dialogue const & d ) { return d.actor( is_npc )->is_wearing( itype_id( item_id.evaluate( d ) ) ); }; } -void conditional_t::set_has_item( const JsonObject &jo, std::string_view member, bool is_npc ) +conditional_t::func f_has_item( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var item_id = get_str_or_var( jo.get_member( member ), member, true ); - condition = [item_id, is_npc]( dialogue const & d ) { + return [item_id, is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); return actor->charges_of( itype_id( item_id.evaluate( d ) ) ) > 0 || actor->has_amount( itype_id( item_id.evaluate( d ) ), 1 ); }; } -void conditional_t::set_has_items( const JsonObject &jo, const std::string_view member, - bool is_npc ) +conditional_t::func f_has_items( const JsonObject &jo, const std::string_view member, + bool is_npc ) { JsonObject has_items = jo.get_object( member ); if( !has_items.has_member( "item" ) || ( !has_items.has_member( "count" ) && !has_items.has_member( "charges" ) ) ) { - condition = []( dialogue const & ) { + return []( dialogue const & ) { return false; }; } else { str_or_var item_id = get_str_or_var( has_items.get_member( "item" ), "item", true ); dbl_or_var count = get_dbl_or_var( has_items, "count", false ); dbl_or_var charges = get_dbl_or_var( has_items, "charges", false ); - condition = [item_id, count, charges, is_npc]( dialogue & d ) { + return [item_id, count, charges, is_npc]( dialogue & d ) { const talker *actor = d.actor( is_npc ); itype_id id = itype_id( item_id.evaluate( d ) ); if( charges.evaluate( d ) == 0 && item::count_by_charges( id ) ) { @@ -763,16 +835,16 @@ void conditional_t::set_has_items( const JsonObject &jo, const std::string_view } } -void conditional_t::set_has_item_with_flag( const JsonObject &jo, std::string_view member, +conditional_t::func f_has_item_with_flag( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var flag = get_str_or_var( jo.get_member( member ), member, true ); - condition = [flag, is_npc]( dialogue const & d ) { + return [flag, is_npc]( dialogue const & d ) { return d.actor( is_npc )->has_item_with_flag( flag_id( flag.evaluate( d ) ) ); }; } -void conditional_t::set_has_item_category( const JsonObject &jo, std::string_view member, +conditional_t::func f_has_item_category( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var category_id = get_str_or_var( jo.get_member( member ), member, true ); @@ -784,7 +856,7 @@ void conditional_t::set_has_item_category( const JsonObject &jo, std::string_vie } } - condition = [category_id, count, is_npc]( dialogue const & d ) { + return [category_id, count, is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); const item_category_id cat_id = item_category_id( category_id.evaluate( d ) ); const auto items_with = actor->const_items_with( [cat_id]( const item & it ) { @@ -794,11 +866,11 @@ void conditional_t::set_has_item_category( const JsonObject &jo, std::string_vie }; } -void conditional_t::set_has_bionics( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_bionics( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var bionics_id = get_str_or_var( jo.get_member( member ), member, true ); - condition = [bionics_id, is_npc]( dialogue const & d ) { + return [bionics_id, is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); if( bionics_id.evaluate( d ) == "ANY" ) { return actor->num_bionics() > 0 || actor->has_max_power(); @@ -807,8 +879,8 @@ void conditional_t::set_has_bionics( const JsonObject &jo, std::string_view memb }; } -void conditional_t::set_has_any_effect( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_any_effect( const JsonObject &jo, std::string_view member, + bool is_npc ) { std::vector effects_to_check; for( JsonValue jv : jo.get_array( member ) ) { @@ -821,7 +893,7 @@ void conditional_t::set_has_any_effect( const JsonObject &jo, std::string_view m } else { bp.str_val = ""; } - condition = [effects_to_check, intensity, bp, is_npc]( dialogue & d ) { + return [effects_to_check, intensity, bp, is_npc]( dialogue & d ) { bodypart_id bid = bp.evaluate( d ).empty() ? get_bp_from_str( d.reason ) : bodypart_id( bp.evaluate( d ) ); for( const str_or_var &effect_id : effects_to_check ) { @@ -834,8 +906,8 @@ void conditional_t::set_has_any_effect( const JsonObject &jo, std::string_view m }; } -void conditional_t::set_has_effect( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_has_effect( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var effect_id = get_str_or_var( jo.get_member( member ), member, true ); dbl_or_var intensity = get_dbl_or_var( jo, "intensity", false, -1 ); @@ -845,7 +917,7 @@ void conditional_t::set_has_effect( const JsonObject &jo, std::string_view membe } else { bp.str_val = ""; } - condition = [effect_id, intensity, bp, is_npc]( dialogue & d ) { + return [effect_id, intensity, bp, is_npc]( dialogue & d ) { bodypart_id bid = bp.evaluate( d ).empty() ? get_bp_from_str( d.reason ) : bodypart_id( bp.evaluate( d ) ); effect target = d.actor( is_npc )->get_effect( efftype_id( effect_id.evaluate( d ) ), bid ); @@ -853,7 +925,7 @@ void conditional_t::set_has_effect( const JsonObject &jo, std::string_view membe }; } -void conditional_t::set_need( const JsonObject &jo, std::string_view member, bool is_npc ) +conditional_t::func f_need( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var need = get_str_or_var( jo.get_member( member ), member, true ); dbl_or_var dov; @@ -868,7 +940,7 @@ void conditional_t::set_need( const JsonObject &jo, std::string_view member, boo dov.min.dbl_val = static_cast( flevel->second ); } } - condition = [need, dov, is_npc]( dialogue & d ) { + return [need, dov, is_npc]( dialogue & d ) { const talker *actor = d.actor( is_npc ); int amount = dov.evaluate( d ); return ( actor->get_fatigue() > amount && need.evaluate( d ) == "fatigue" ) || @@ -877,11 +949,11 @@ void conditional_t::set_need( const JsonObject &jo, std::string_view member, boo }; } -void conditional_t::set_at_om_location( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_at_om_location( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var location = get_str_or_var( jo.get_member( member ), member, true ); - condition = [location, is_npc]( dialogue const & d ) { + return [location, is_npc]( dialogue const & d ) { const tripoint_abs_omt omt_pos = d.actor( is_npc )->global_omt_location(); const oter_id &omt_ter = overmap_buffer.ter( omt_pos ); const std::string &omt_str = omt_ter.id().str(); @@ -902,12 +974,12 @@ void conditional_t::set_at_om_location( const JsonObject &jo, std::string_view m }; } -void conditional_t::set_near_om_location( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_near_om_location( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var location = get_str_or_var( jo.get_member( member ), member, true ); const dbl_or_var range = get_dbl_or_var( jo, "range", false, 1 ); - condition = [location, range, is_npc]( dialogue & d ) { + return [location, range, is_npc]( dialogue & d ) { const tripoint_abs_omt omt_pos = d.actor( is_npc )->global_omt_location(); for( const tripoint_abs_omt &curr_pos : points_in_radius( omt_pos, range.evaluate( d ) ) ) { @@ -938,7 +1010,7 @@ void conditional_t::set_near_om_location( const JsonObject &jo, std::string_view }; } -void conditional_t::set_has_var( const JsonObject &jo, std::string_view member, bool is_npc ) +conditional_t::func f_has_var( const JsonObject &jo, std::string_view member, bool is_npc ) { dbl_or_var empty; const std::string var_name = get_talk_varname( jo, member, false, empty ); @@ -946,13 +1018,12 @@ void conditional_t::set_has_var( const JsonObject &jo, std::string_view member, const bool time_check = jo.has_member( "time" ) && jo.get_bool( "time" ); if( !time_check && !jo.has_member( "value" ) ) { jo.throw_error( R"(Missing field: "value" or "time")" ); - condition = []( dialogue const & ) { + return []( dialogue const & ) { return false; }; - return; } - condition = [var_name, value, time_check, is_npc]( dialogue const & d ) { + return [var_name, value, time_check, is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); if( time_check ) { return !actor->get_value( var_name ).empty(); @@ -961,7 +1032,7 @@ void conditional_t::set_has_var( const JsonObject &jo, std::string_view member, }; } -void conditional_t::set_expects_vars( const JsonObject &jo, std::string_view member ) +conditional_t::func f_expects_vars( const JsonObject &jo, std::string_view member ) { std::vector to_check; if( jo.has_array( member ) ) { @@ -970,7 +1041,7 @@ void conditional_t::set_expects_vars( const JsonObject &jo, std::string_view mem } } - condition = [to_check]( dialogue const & d ) { + return [to_check]( dialogue const & d ) { std::string missing_variables; for( const str_or_var &val : to_check ) { if( d.get_context().find( "npctalk_var_" + val.evaluate( d ) ) == d.get_context().end() ) { @@ -985,15 +1056,15 @@ void conditional_t::set_expects_vars( const JsonObject &jo, std::string_view mem }; } -void conditional_t::set_compare_var( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_compare_var( const JsonObject &jo, std::string_view member, + bool is_npc ) { dbl_or_var empty; const std::string var_name = get_talk_varname( jo, member, false, empty ); const std::string &op = jo.get_string( "op" ); dbl_or_var dov = get_dbl_or_var( jo, "value" ); - condition = [var_name, op, dov, is_npc]( dialogue & d ) { + return [var_name, op, dov, is_npc]( dialogue & d ) { double stored_value = 0; double value = dov.evaluate( d ); const std::string &var = d.actor( is_npc )->get_value( var_name ); @@ -1024,7 +1095,7 @@ void conditional_t::set_compare_var( const JsonObject &jo, std::string_view memb }; } -void conditional_t::set_compare_time_since_var( const JsonObject &jo, std::string_view member, +conditional_t::func f_compare_time_since_var( const JsonObject &jo, std::string_view member, bool is_npc ) { dbl_or_var empty; @@ -1032,7 +1103,7 @@ void conditional_t::set_compare_time_since_var( const JsonObject &jo, std::strin const std::string &op = jo.get_string( "op" ); const int value = to_turns( read_from_json_string( jo.get_member( "time" ), time_duration::units ) ); - condition = [var_name, op, value, is_npc]( dialogue const & d ) { + return [var_name, op, value, is_npc]( dialogue const & d ) { int stored_value = 0; const std::string &var = d.actor( is_npc )->get_value( var_name ); if( var.empty() ) { @@ -1066,10 +1137,10 @@ void conditional_t::set_compare_time_since_var( const JsonObject &jo, std::strin }; } -void conditional_t::set_npc_role_nearby( const JsonObject &jo, std::string_view member ) +conditional_t::func f_npc_role_nearby( const JsonObject &jo, std::string_view member ) { str_or_var role = get_str_or_var( jo.get_member( member ), member, true ); - condition = [role]( dialogue const & d ) { + return [role]( dialogue const & d ) { const std::vector available = g->get_npcs_if( [&]( const npc & guy ) { return d.actor( false )->posz() == guy.posz() && guy.companion_mission_role_id == role.evaluate( d ) && @@ -1079,18 +1150,18 @@ void conditional_t::set_npc_role_nearby( const JsonObject &jo, std::string_view }; } -void conditional_t::set_npc_allies( const JsonObject &jo, std::string_view member ) +conditional_t::func f_npc_allies( const JsonObject &jo, std::string_view member ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov]( dialogue & d ) { + return [dov]( dialogue & d ) { return g->allies().size() >= static_cast::size_type>( dov.evaluate( d ) ); }; } -void conditional_t::set_npc_allies_global( const JsonObject &jo, std::string_view member ) +conditional_t::func f_npc_allies_global( const JsonObject &jo, std::string_view member ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov]( dialogue & d ) { + return [dov]( dialogue & d ) { const auto all_npcs = overmap_buffer.get_overmap_npcs(); const size_t count = std::count_if( all_npcs.begin(), all_npcs.end(), []( const shared_ptr_fast &ptr ) { @@ -1101,87 +1172,87 @@ void conditional_t::set_npc_allies_global( const JsonObject &jo, std::string_vie }; } -void conditional_t::set_u_has_cash( const JsonObject &jo, std::string_view member ) +conditional_t::func f_u_has_cash( const JsonObject &jo, std::string_view member ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov]( dialogue & d ) { + return [dov]( dialogue & d ) { return d.actor( false )->cash() >= dov.evaluate( d ); }; } -void conditional_t::set_u_are_owed( const JsonObject &jo, std::string_view member ) +conditional_t::func f_u_are_owed( const JsonObject &jo, std::string_view member ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov]( dialogue & d ) { + return [dov]( dialogue & d ) { return d.actor( true )->debt() >= dov.evaluate( d ); }; } -void conditional_t::set_npc_aim_rule( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_npc_aim_rule( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var setting = get_str_or_var( jo.get_member( member ), member, true ); - condition = [setting, is_npc]( dialogue const & d ) { + return [setting, is_npc]( dialogue const & d ) { return d.actor( is_npc )->has_ai_rule( "aim_rule", setting.evaluate( d ) ); }; } -void conditional_t::set_npc_engagement_rule( const JsonObject &jo, std::string_view member, +conditional_t::func f_npc_engagement_rule( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var setting = get_str_or_var( jo.get_member( member ), member, true ); - condition = [setting, is_npc]( dialogue const & d ) { + return [setting, is_npc]( dialogue const & d ) { return d.actor( is_npc )->has_ai_rule( "engagement_rule", setting.evaluate( d ) ); }; } -void conditional_t::set_npc_cbm_reserve_rule( const JsonObject &jo, std::string_view member, +conditional_t::func f_npc_cbm_reserve_rule( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var setting = get_str_or_var( jo.get_member( member ), member, true ); - condition = [setting, is_npc]( dialogue const & d ) { + return [setting, is_npc]( dialogue const & d ) { return d.actor( is_npc )->has_ai_rule( "cbm_reserve_rule", setting.evaluate( d ) ); }; } -void conditional_t::set_npc_cbm_recharge_rule( const JsonObject &jo, std::string_view member, +conditional_t::func f_npc_cbm_recharge_rule( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var setting = get_str_or_var( jo.get_member( member ), member, true ); - condition = [setting, is_npc]( dialogue const & d ) { + return [setting, is_npc]( dialogue const & d ) { return d.actor( is_npc )->has_ai_rule( "cbm_recharge_rule", setting.evaluate( d ) ); }; } -void conditional_t::set_npc_rule( const JsonObject &jo, std::string_view member, bool is_npc ) +conditional_t::func f_npc_rule( const JsonObject &jo, std::string_view member, bool is_npc ) { str_or_var rule = get_str_or_var( jo.get_member( member ), member, true ); - condition = [rule, is_npc]( dialogue const & d ) { + return [rule, is_npc]( dialogue const & d ) { return d.actor( is_npc )->has_ai_rule( "ally_rule", rule.evaluate( d ) ); }; } -void conditional_t::set_npc_override( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_npc_override( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var rule = get_str_or_var( jo.get_member( member ), member, true ); - condition = [rule, is_npc]( dialogue const & d ) { + return [rule, is_npc]( dialogue const & d ) { return d.actor( is_npc )->has_ai_rule( "ally_override", rule.evaluate( d ) ); }; } -void conditional_t::set_days_since( const JsonObject &jo, std::string_view member ) +conditional_t::func f_days_since( const JsonObject &jo, std::string_view member ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov]( dialogue & d ) { + return [dov]( dialogue & d ) { return calendar::turn >= calendar::start_of_cataclysm + 1_days * dov.evaluate( d ); }; } -void conditional_t::set_is_season( const JsonObject &jo, std::string_view member ) +conditional_t::func f_is_season( const JsonObject &jo, std::string_view member ) { str_or_var season_name = get_str_or_var( jo.get_member( member ), member, true ); - condition = [season_name]( dialogue const & d ) { + return [season_name]( dialogue const & d ) { const season_type season = season_of_year( calendar::turn ); return ( season == SPRING && season_name.evaluate( d ) == "spring" ) || ( season == SUMMER && season_name.evaluate( d ) == "summer" ) || @@ -1190,11 +1261,11 @@ void conditional_t::set_is_season( const JsonObject &jo, std::string_view member }; } -void conditional_t::set_mission_goal( const JsonObject &jo, std::string_view member, - bool is_npc ) +conditional_t::func f_mission_goal( const JsonObject &jo, std::string_view member, + bool is_npc ) { str_or_var mission_goal_str = get_str_or_var( jo.get_member( member ), member, true ); - condition = [mission_goal_str, is_npc]( dialogue const & d ) { + return [mission_goal_str, is_npc]( dialogue const & d ) { mission *miss = d.actor( is_npc )->selected_mission(); if( !miss ) { return false; @@ -1204,65 +1275,74 @@ void conditional_t::set_mission_goal( const JsonObject &jo, std::string_view mem }; } -void conditional_t::set_is_gender( bool is_male, bool is_npc ) +conditional_t::func f_is_gender( bool is_male, bool is_npc ) { - condition = [is_male, is_npc]( dialogue const & d ) { + return [is_male, is_npc]( dialogue const & d ) { return d.actor( is_npc )->is_male() == is_male; }; } -void conditional_t::set_is_alive( bool is_npc ) +conditional_t::func f_is_male( bool is_npc ) +{ + return f_is_gender( true, is_npc ); +} +conditional_t::func f_is_female( bool is_npc ) +{ + return f_is_gender( false, is_npc ); +} + +conditional_t::func f_is_alive( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_is_alive(); }; } -void conditional_t::set_is_avatar( bool is_npc ) +conditional_t::func f_is_avatar( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_character() && d.actor( is_npc )->get_character()->is_avatar(); }; } -void conditional_t::set_is_npc( bool is_npc ) +conditional_t::func f_is_npc( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_npc(); }; } -void conditional_t::set_is_character( bool is_npc ) +conditional_t::func f_is_character( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_character(); }; } -void conditional_t::set_is_monster( bool is_npc ) +conditional_t::func f_is_monster( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_monster(); }; } -void conditional_t::set_is_item( bool is_npc ) +conditional_t::func f_is_item( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_item(); }; } -void conditional_t::set_is_furniture( bool is_npc ) +conditional_t::func f_is_furniture( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->get_computer(); }; } -void conditional_t::set_player_see( bool is_npc ) +conditional_t::func f_player_see( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { const Creature *c = d.actor( is_npc )->get_creature(); if( c ) { return get_player_view().sees( *c ); @@ -1272,164 +1352,164 @@ void conditional_t::set_player_see( bool is_npc ) }; } -void conditional_t::set_no_assigned_mission() +conditional_t::func f_no_assigned_mission() { - condition = []( dialogue const & d ) { + return []( dialogue const & d ) { return d.missions_assigned.empty(); }; } -void conditional_t::set_has_assigned_mission() +conditional_t::func f_has_assigned_mission() { - condition = []( dialogue const & d ) { + return []( dialogue const & d ) { return d.missions_assigned.size() == 1; }; } -void conditional_t::set_has_many_assigned_missions() +conditional_t::func f_has_many_assigned_missions() { - condition = []( dialogue const & d ) { + return []( dialogue const & d ) { return d.missions_assigned.size() >= 2; }; } -void conditional_t::set_no_available_mission( bool is_npc ) +conditional_t::func f_no_available_mission( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->available_missions().empty(); }; } -void conditional_t::set_has_available_mission( bool is_npc ) +conditional_t::func f_has_available_mission( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->available_missions().size() == 1; }; } -void conditional_t::set_has_many_available_missions( bool is_npc ) +conditional_t::func f_has_many_available_missions( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->available_missions().size() >= 2; }; } -void conditional_t::set_mission_complete( bool is_npc ) +conditional_t::func f_mission_complete( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { mission *miss = d.actor( is_npc )->selected_mission(); return miss && miss->is_complete( d.actor( is_npc )->getID() ); }; } -void conditional_t::set_mission_incomplete( bool is_npc ) +conditional_t::func f_mission_incomplete( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { mission *miss = d.actor( is_npc )->selected_mission(); return miss && !miss->is_complete( d.actor( is_npc )->getID() ); }; } -void conditional_t::set_mission_failed( bool is_npc ) +conditional_t::func f_mission_failed( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { mission *miss = d.actor( is_npc )->selected_mission(); return miss && miss->has_failed(); }; } -void conditional_t::set_npc_service( const JsonObject &jo, std::string_view member, bool is_npc ) +conditional_t::func f_npc_service( const JsonObject &jo, std::string_view member, bool is_npc ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [is_npc, dov]( dialogue & d ) { + return [is_npc, dov]( dialogue & d ) { return !d.actor( is_npc )->has_effect( effect_currently_busy, bodypart_str_id::NULL_ID() ) && d.actor( false )->cash() >= dov.evaluate( d ); }; } -void conditional_t::set_npc_available( bool is_npc ) +conditional_t::func f_npc_available( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return !d.actor( is_npc )->has_effect( effect_currently_busy, bodypart_str_id::NULL_ID() ); }; } -void conditional_t::set_npc_following( bool is_npc ) +conditional_t::func f_npc_following( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->is_following(); }; } -void conditional_t::set_npc_friend( bool is_npc ) +conditional_t::func f_npc_friend( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->is_friendly( get_player_character() ); }; } -void conditional_t::set_npc_hostile( bool is_npc ) +conditional_t::func f_npc_hostile( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return d.actor( is_npc )->is_enemy(); }; } -void conditional_t::set_npc_train_skills( bool is_npc ) +conditional_t::func f_npc_train_skills( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return !d.actor( is_npc )->skills_offered_to( *d.actor( !is_npc ) ).empty(); }; } -void conditional_t::set_npc_train_styles( bool is_npc ) +conditional_t::func f_npc_train_styles( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return !d.actor( is_npc )->styles_offered_to( *d.actor( !is_npc ) ).empty(); }; } -void conditional_t::set_npc_train_spells( bool is_npc ) +conditional_t::func f_npc_train_spells( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return !d.actor( is_npc )->spells_offered_to( *d.actor( !is_npc ) ).empty(); }; } -void conditional_t::set_at_safe_space( bool is_npc ) +conditional_t::func f_at_safe_space( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return overmap_buffer.is_safe( d.actor( is_npc )->global_omt_location() ) && d.actor( is_npc )->is_safe(); }; } -void conditional_t::set_can_stow_weapon( bool is_npc ) +conditional_t::func f_can_stow_weapon( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); return !actor->unarmed_attack() && actor->can_stash_weapon(); }; } -void conditional_t::set_can_drop_weapon( bool is_npc ) +conditional_t::func f_can_drop_weapon( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); return !actor->unarmed_attack() && !actor->wielded_with_flag( flag_NO_UNWIELD ); }; } -void conditional_t::set_has_weapon( bool is_npc ) +conditional_t::func f_has_weapon( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return !d.actor( is_npc )->unarmed_attack(); }; } -void conditional_t::set_is_driving( bool is_npc ) +conditional_t::func f_is_driving( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); if( const optional_vpart_position vp = get_map().veh_at( actor->pos() ) ) { return vp->vehicle().is_moving() && actor->is_in_control_of( vp->vehicle() ); @@ -1438,47 +1518,47 @@ void conditional_t::set_is_driving( bool is_npc ) }; } -void conditional_t::set_has_stolen_item( bool /*is_npc*/ ) +conditional_t::func f_has_stolen_item( bool /*is_npc*/ ) { - condition = []( dialogue const & d ) { + return []( dialogue const & d ) { return d.actor( false )->has_stolen_item( *d.actor( true ) ); }; } -void conditional_t::set_is_day() +conditional_t::func f_is_day() { - condition = []( dialogue const & ) { + return []( dialogue const & ) { return !is_night( calendar::turn ); }; } -void conditional_t::set_is_outside( bool is_npc ) +conditional_t::func f_is_outside( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return is_creature_outside( *d.actor( is_npc )->get_creature() ); }; } -void conditional_t::set_is_underwater( bool is_npc ) +conditional_t::func f_is_underwater( bool is_npc ) { - condition = [is_npc]( dialogue const & d ) { + return [is_npc]( dialogue const & d ) { return get_map().is_divable( d.actor( is_npc )->pos() ); }; } -void conditional_t::set_one_in_chance( const JsonObject &jo, std::string_view member ) +conditional_t::func f_one_in_chance( const JsonObject &jo, std::string_view member ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov]( dialogue & d ) { + return [dov]( dialogue & d ) { return one_in( dov.evaluate( d ) ); }; } -void conditional_t::set_query( const JsonObject &jo, std::string_view member, bool is_npc ) +conditional_t::func f_query( const JsonObject &jo, std::string_view member, bool is_npc ) { translation_or_var message = get_translation_or_var( jo.get_member( member ), member, true ); bool default_val = jo.get_bool( "default" ); - condition = [message, default_val, is_npc]( dialogue const & d ) { + return [message, default_val, is_npc]( dialogue const & d ) { const talker *actor = d.actor( is_npc ); if( actor->get_character() && actor->get_character()->is_avatar() ) { std::string translated_message = message.evaluate( d ); @@ -1489,7 +1569,7 @@ void conditional_t::set_query( const JsonObject &jo, std::string_view member, bo }; } -void conditional_t::set_query_tile( const JsonObject &jo, std::string_view member, bool is_npc ) +conditional_t::func f_query_tile( const JsonObject &jo, std::string_view member, bool is_npc ) { std::string type = jo.get_string( member.data() ); var_info target_var = read_var_info( jo.get_object( "target_var" ) ); @@ -1502,7 +1582,7 @@ void conditional_t::set_query_tile( const JsonObject &jo, std::string_view membe range = get_dbl_or_var( jo, "range" ); } bool z_level = jo.get_bool( "z_level", false ); - condition = [type, target_var, message, range, z_level, is_npc]( dialogue & d ) { + return [type, target_var, message, range, z_level, is_npc]( dialogue & d ) { std::optional loc; Character *ch = d.actor( is_npc )->get_character(); if( ch && ch->as_avatar() ) { @@ -1546,26 +1626,26 @@ void conditional_t::set_query_tile( const JsonObject &jo, std::string_view membe }; } -void conditional_t::set_x_in_y_chance( const JsonObject &jo, const std::string_view member ) +conditional_t::func f_x_in_y_chance( const JsonObject &jo, const std::string_view member ) { const JsonObject &var_obj = jo.get_object( member ); dbl_or_var dovx = get_dbl_or_var( var_obj, "x" ); dbl_or_var dovy = get_dbl_or_var( var_obj, "y" ); - condition = [dovx, dovy]( dialogue & d ) { + return [dovx, dovy]( dialogue & d ) { return x_in_y( dovx.evaluate( d ), dovy.evaluate( d ) ); }; } -void conditional_t::set_is_weather( const JsonObject &jo, std::string_view member ) +conditional_t::func f_is_weather( const JsonObject &jo, std::string_view member ) { str_or_var weather = get_str_or_var( jo.get_member( member ), member, true ); - condition = [weather]( dialogue const & d ) { + return [weather]( dialogue const & d ) { return get_weather().weather_id == weather_type_id( weather.evaluate( d ) ); }; } -void conditional_t::set_map_ter_furn_with_flag( const JsonObject &jo, std::string_view member ) +conditional_t::func f_map_ter_furn_with_flag( const JsonObject &jo, std::string_view member ) { str_or_var furn_type = get_str_or_var( jo.get_member( member ), member, true ); var_info loc_var = read_var_info( jo.get_object( "loc" ) ); @@ -1575,7 +1655,7 @@ void conditional_t::set_map_ter_furn_with_flag( const JsonObject &jo, std::strin } else if( member == "map_furniture_with_flag" ) { terrain = false; } - condition = [terrain, furn_type, loc_var]( dialogue const & d ) { + return [terrain, furn_type, loc_var]( dialogue const & d ) { tripoint loc = get_map().getlocal( get_tripoint_from_var( loc_var, d ) ); if( terrain ) { return get_map().ter( loc )->has_flag( furn_type.evaluate( d ) ); @@ -1585,10 +1665,10 @@ void conditional_t::set_map_ter_furn_with_flag( const JsonObject &jo, std::strin }; } -void conditional_t::set_map_in_city( const JsonObject &jo, std::string_view member ) +conditional_t::func f_map_in_city( const JsonObject &jo, std::string_view member ) { str_or_var target = get_str_or_var( jo.get_member( member ), member, true ); - condition = [target]( dialogue const & d ) { + return [target]( dialogue const & d ) { tripoint_abs_ms target_pos = tripoint_abs_ms( tripoint::from_string( target.evaluate( d ) ) ); city_reference c = overmap_buffer.closest_city( project_to( target_pos ) ); c.distance = rl_dist( c.abs_sm_pos, project_to( target_pos ) ); @@ -1596,10 +1676,10 @@ void conditional_t::set_map_in_city( const JsonObject &jo, std::string_view memb }; } -void conditional_t::set_mod_is_loaded( const JsonObject &jo, std::string_view member ) +conditional_t::func f_mod_is_loaded( const JsonObject &jo, std::string_view member ) { str_or_var compared_mod = get_str_or_var( jo.get_member( member ), member, true ); - condition = [compared_mod]( dialogue const & d ) { + return [compared_mod]( dialogue const & d ) { mod_id comp_mod = mod_id( compared_mod.evaluate( d ) ); for( const mod_id &mod : world_generator->active_world->active_mod_order ) { if( comp_mod == mod ) { @@ -1610,80 +1690,24 @@ void conditional_t::set_mod_is_loaded( const JsonObject &jo, std::string_view me }; } -void conditional_t::set_has_faction_trust( const JsonObject &jo, std::string_view member ) +conditional_t::func f_has_faction_trust( const JsonObject &jo, std::string_view member ) { dbl_or_var dov = get_dbl_or_var( jo, member ); - condition = [dov]( dialogue & d ) { + return [dov]( dialogue & d ) { return d.actor( true )->get_faction()->trusts_u >= dov.evaluate( d ); }; } -static std::string get_string_from_input( const JsonArray &objects, int index ) -{ - if( objects.has_string( index ) ) { - std::string type = objects.get_string( index ); - if( type == "u" || type == "npc" ) { - return type; - } - } - dbl_or_var empty; - JsonObject object = objects.get_object( index ); - if( object.has_string( "u_val" ) ) { - return "u_" + get_talk_varname( object, "u_val", false, empty ); - } else if( object.has_string( "npc_val" ) ) { - return "npc_" + get_talk_varname( object, "npc_val", false, empty ); - } else if( object.has_string( "global_val" ) ) { - return "global_" + get_talk_varname( object, "global_val", false, empty ); - } else if( object.has_string( "context_val" ) ) { - return "context_" + get_talk_varname( object, "context_val", false, empty ); - } else if( object.has_string( "faction_val" ) ) { - return "faction_" + get_talk_varname( object, "faction_val", false, empty ); - } else if( object.has_string( "party_val" ) ) { - return "party_" + get_talk_varname( object, "party_val", false, empty ); - } - object.throw_error( "Invalid input type." ); - return ""; -} - -static tripoint_abs_ms get_tripoint_from_string( const std::string &type, dialogue const &d ) -{ - if( type == "u" ) { - return d.actor( false )->global_pos(); - } else if( type == "npc" ) { - return d.actor( true )->global_pos(); - } else if( type.find( "u_" ) == 0 ) { - var_info var = var_info( var_type::u, type.substr( 2, type.size() - 2 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "npc_" ) == 0 ) { - var_info var = var_info( var_type::npc, type.substr( 4, type.size() - 4 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "global_" ) == 0 ) { - var_info var = var_info( var_type::global, type.substr( 7, type.size() - 7 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "faction_" ) == 0 ) { - var_info var = var_info( var_type::faction, type.substr( 8, type.size() - 8 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "party_" ) == 0 ) { - var_info var = var_info( var_type::party, type.substr( 6, type.size() - 6 ) ); - return get_tripoint_from_var( var, d ); - } else if( type.find( "context_" ) == 0 ) { - var_info var = var_info( var_type::context, type.substr( 8, type.size() - 8 ) ); - return get_tripoint_from_var( var, d ); - } - return tripoint_abs_ms(); -} - -void conditional_t::set_compare_string( const JsonObject &jo, std::string_view member ) +conditional_t::func f_compare_string( const JsonObject &jo, std::string_view member ) { str_or_var first; str_or_var second; JsonArray objects = jo.get_array( member ); if( objects.size() != 2 ) { jo.throw_error( "incorrect number of values. Expected 2 in " + jo.str() ); - condition = []( dialogue const & ) { + return []( dialogue const & ) { return false; }; - return; } if( objects.has_object( 0 ) ) { @@ -1697,84 +1721,259 @@ void conditional_t::set_compare_string( const JsonObject &jo, std::string_view m second.str_val = objects.next_string(); } - condition = [first, second]( dialogue const & d ) { + return [first, second]( dialogue const & d ) { return first.evaluate( d ) == second.evaluate( d ); }; } -void conditional_t::set_get_condition( const JsonObject &jo, std::string_view member ) +conditional_t::func f_get_condition( const JsonObject &jo, std::string_view member ) { str_or_var conditionalToGet = get_str_or_var( jo.get_member( member ), member, true ); - condition = [conditionalToGet]( dialogue & d ) { + return [conditionalToGet]( dialogue & d ) { return d.evaluate_conditional( conditionalToGet.evaluate( d ), d ); }; } -void conditional_t::set_get_option( const JsonObject &jo, std::string_view member ) +conditional_t::func f_get_option( const JsonObject &jo, std::string_view member ) { str_or_var optionToGet = get_str_or_var( jo.get_member( member ), member, true ); - condition = [optionToGet]( dialogue & d ) { + return [optionToGet]( dialogue & d ) { return get_option( optionToGet.evaluate( d ) ); }; } -void conditional_t::set_compare_num( const JsonObject &jo, const std::string_view member ) +conditional_t::func f_compare_num( const JsonObject &jo, const std::string_view member ) { JsonArray objects = jo.get_array( member ); if( objects.size() != 3 ) { jo.throw_error( "incorrect number of values. Expected three in " + jo.str() ); - condition = []( dialogue const & ) { + return []( dialogue const & ) { return false; }; - return; } - std::function get_first_dbl = objects.has_object( 0 ) ? get_get_dbl( - objects.get_object( 0 ) ) : get_get_dbl( objects.get_string( 0 ), jo ); - std::function get_second_dbl = objects.has_object( 2 ) ? get_get_dbl( - objects.get_object( 2 ) ) : get_get_dbl( objects.get_string( 2 ), jo ); + std::function get_first_dbl = objects.has_object( + 0 ) ? conditional_t::get_get_dbl( + objects.get_object( 0 ) ) : conditional_t::get_get_dbl( objects.get_string( 0 ), jo ); + std::function get_second_dbl = objects.has_object( + 2 ) ? conditional_t::get_get_dbl( + objects.get_object( 2 ) ) : conditional_t::get_get_dbl( objects.get_string( 2 ), jo ); const std::string &op = objects.get_string( 1 ); if( op == "==" || op == "=" ) { - condition = [get_first_dbl, get_second_dbl]( dialogue & d ) { + return [get_first_dbl, get_second_dbl]( dialogue & d ) { return get_first_dbl( d ) == get_second_dbl( d ); }; } else if( op == "!=" ) { - condition = [get_first_dbl, get_second_dbl]( dialogue & d ) { + return [get_first_dbl, get_second_dbl]( dialogue & d ) { return get_first_dbl( d ) != get_second_dbl( d ); }; } else if( op == "<=" ) { - condition = [get_first_dbl, get_second_dbl]( dialogue & d ) { + return [get_first_dbl, get_second_dbl]( dialogue & d ) { return get_first_dbl( d ) <= get_second_dbl( d ); }; } else if( op == ">=" ) { - condition = [get_first_dbl, get_second_dbl]( dialogue & d ) { + return [get_first_dbl, get_second_dbl]( dialogue & d ) { return get_first_dbl( d ) >= get_second_dbl( d ); }; } else if( op == "<" ) { - condition = [get_first_dbl, get_second_dbl]( dialogue & d ) { + return [get_first_dbl, get_second_dbl]( dialogue & d ) { return get_first_dbl( d ) < get_second_dbl( d ); }; } else if( op == ">" ) { - condition = [get_first_dbl, get_second_dbl]( dialogue & d ) { + return [get_first_dbl, get_second_dbl]( dialogue & d ) { return get_first_dbl( d ) > get_second_dbl( d ); }; } else { jo.throw_error( "unexpected operator " + jo.get_string( "op" ) + " in " + jo.str() ); - condition = []( dialogue const & ) { + return []( dialogue const & ) { return false; }; } } -void conditional_t::set_math( const JsonObject &jo, const std::string_view member ) +conditional_t::func f_math( const JsonObject &jo, const std::string_view member ) { eoc_math math; math.from_json( jo, member, eoc_math::type_t::compare ); - condition = [math = std::move( math )]( dialogue & d ) { + return [math = std::move( math )]( dialogue & d ) { return math.act( d ); }; } +conditional_t::func f_u_has_camp() +{ + return []( dialogue const & ) { + return !get_player_character().camps.empty(); + }; +} + +conditional_t::func f_has_pickup_list( bool is_npc ) +{ + return [is_npc]( dialogue const & d ) { + return d.actor( is_npc )->has_ai_rule( "pickup_rule", "any" ); + }; +} + +conditional_t::func f_is_by_radio() +{ + return []( dialogue const & d ) { + return d.by_radio; + }; +} + +conditional_t::func f_has_reason() +{ + return []( dialogue const & d ) { + return !d.reason.empty(); + }; +} + +conditional_t::func f_roll_contested( const JsonObject &jo, const std::string_view member ) +{ + std::function get_check = conditional_t::get_get_dbl( jo.get_object( + member ) ); + dbl_or_var difficulty = get_dbl_or_var( jo, "difficulty", true ); + dbl_or_var die_size = get_dbl_or_var( jo, "die_size", false, 10 ); + return [get_check, difficulty, die_size]( dialogue & d ) { + return rng( 1, die_size.evaluate( d ) ) + get_check( d ) > difficulty.evaluate( d ); + }; +} + +conditional_t::func f_u_know_recipe( const JsonObject &jo, std::string_view member ) +{ + str_or_var known_recipe_id = get_str_or_var( jo.get_member( member ), member, true ); + return [known_recipe_id]( dialogue & d ) { + const recipe &rep = recipe_id( known_recipe_id.evaluate( d ) ).obj(); + // should be a talker function but recipes aren't in Character:: yet + return get_player_character().knows_recipe( &rep ); + }; +} + +conditional_t::func f_mission_has_generic_rewards() +{ + return []( dialogue const & d ) { + mission *miss = d.actor( true )->selected_mission(); + if( miss == nullptr ) { + debugmsg( "mission_has_generic_rewards: mission_selected == nullptr" ); + return true; + } + return miss->has_generic_rewards(); + }; +} + +conditional_t::func f_has_worn_with_flag( const JsonObject &jo, std::string_view member, + bool is_npc ) +{ + str_or_var flag = get_str_or_var( jo.get_member( member ), member, true ); + std::optional bp; + optional( jo, false, "bodypart", bp ); + return [flag, bp, is_npc]( dialogue const & d ) { + bodypart_id bid = bp.value_or( get_bp_from_str( d.reason ) ); + return d.actor( is_npc )->worn_with_flag( flag_id( flag.evaluate( d ) ), bid ); + }; +} + +conditional_t::func f_has_wielded_with_flag( const JsonObject &jo, std::string_view member, + bool is_npc ) +{ + str_or_var flag = get_str_or_var( jo.get_member( member ), member, true ); + return [flag, is_npc]( dialogue const & d ) { + return d.actor( is_npc )->wielded_with_flag( flag_id( flag.evaluate( d ) ) ); + }; +} + +conditional_t::func f_has_wielded_with_weapon_category( const JsonObject &jo, + std::string_view member, + bool is_npc ) +{ + str_or_var w_cat = get_str_or_var( jo.get_member( member ), member, true ); + return [w_cat, is_npc]( dialogue const & d ) { + return d.actor( is_npc )->wielded_with_weapon_category( weapon_category_id( w_cat.evaluate( d ) ) ); + }; +} + +conditional_t::func f_can_see( bool is_npc ) +{ + return [is_npc]( dialogue const & d ) { + return d.actor( is_npc )->can_see(); + }; +} + +conditional_t::func f_is_deaf( bool is_npc ) +{ + return [is_npc]( dialogue const & d ) { + return d.actor( is_npc )->is_deaf(); + }; +} + +conditional_t::func f_is_on_terrain( const JsonObject &jo, std::string_view member, + bool is_npc ) +{ + str_or_var terrain_type = get_str_or_var( jo.get_member( member ), member, true ); + return [terrain_type, is_npc]( dialogue const & d ) { + map &here = get_map(); + return here.ter( d.actor( is_npc )->pos() ) == ter_id( terrain_type.evaluate( d ) ); + }; +} + +conditional_t::func f_is_on_terrain_with_flag( const JsonObject &jo, std::string_view member, + bool is_npc ) +{ + str_or_var terrain_type = get_str_or_var( jo.get_member( member ), member, true ); + return [terrain_type, is_npc]( dialogue const & d ) { + map &here = get_map(); + return here.ter( d.actor( is_npc )->pos() )->has_flag( terrain_type.evaluate( d ) ); + }; +} + +conditional_t::func f_is_in_field( const JsonObject &jo, std::string_view member, + bool is_npc ) +{ + str_or_var field_type = get_str_or_var( jo.get_member( member ), member, true ); + return [field_type, is_npc]( dialogue const & d ) { + map &here = get_map(); + field_type_id ft = field_type_id( field_type.evaluate( d ) ); + for( const std::pair &f : here.field_at( d.actor( + is_npc )->pos() ) ) { + if( f.second.get_field_type() == ft ) { + return true; + } + } + return false; + }; +} + +conditional_t::func f_has_move_mode( const JsonObject &jo, std::string_view member, + bool is_npc ) +{ + str_or_var mode = get_str_or_var( jo.get_member( member ), member, true ); + return [mode, is_npc]( dialogue const & d ) { + return d.actor( is_npc )->get_move_mode() == move_mode_id( mode.evaluate( d ) ); + }; +} + +conditional_t::func f_can_see_location( const JsonObject &jo, std::string_view member, + bool is_npc ) +{ + str_or_var target = get_str_or_var( jo.get_member( member ), member, true ); + return [is_npc, target]( dialogue const & d ) { + tripoint_abs_ms target_pos = tripoint_abs_ms( tripoint::from_string( target.evaluate( d ) ) ); + return d.actor( is_npc )->can_see_location( get_map().getlocal( target_pos ) ); + }; +} + +conditional_t::func f_using_martial_art( const JsonObject &jo, std::string_view member, + bool is_npc ) +{ + str_or_var style_to_check = get_str_or_var( jo.get_member( member ), member, true ); + return [style_to_check, is_npc]( dialogue const & d ) { + return d.actor( is_npc )->using_martial_art( matype_id( style_to_check.evaluate( d ) ) ); + }; +} + +} // namespace +} // namespace conditional_fun + template static std::function get_get_str_( const JsonObject &jo, std::function ret_func ) @@ -2963,185 +3162,6 @@ conditional_t::get_set_dbl( const J &jo, const std::optional &m return []( dialogue const &, double ) {}; } -void talk_effect_fun_t::set_arithmetic( const JsonObject &jo, std::string_view member, - bool no_result ) -{ - JsonArray objects = jo.get_array( member ); - std::optional min; - std::optional max; - if( jo.has_member( "min" ) ) { - min = get_dbl_or_var_part( jo.get_member( "min" ), "min" ); - } else if( jo.has_member( "min_time" ) ) { - dbl_or_var_part value; - time_duration min_time; - mandatory( jo, false, "min_time", min_time ); - value.dbl_val = to_turns( min_time ); - min = value; - } - if( jo.has_member( "max" ) ) { - max = get_dbl_or_var_part( jo.get_member( "max" ), "max" ); - } else if( jo.has_member( "max_time" ) ) { - dbl_or_var_part value; - time_duration max_time; - mandatory( jo, false, "max_time", max_time ); - value.dbl_val = to_turns( max_time ); - max = value; - } - std::string op = "none"; - std::string result = "none"; - std::function set_dbl = conditional_t::get_set_dbl( - objects.get_object( 0 ), min, - max, no_result ); - int no_result_mod = no_result ? 2 : 0; //In the case of a no result we have fewer terms. - // Normal full version - if( static_cast( objects.size() ) == 5 - no_result_mod ) { - op = objects.get_string( 3 - no_result_mod ); - if( !no_result ) { - result = objects.get_string( 1 ); - if( result != "=" ) { - jo.throw_error( "invalid result " + op + " in " + jo.str() ); - function = []( dialogue const & ) { - return false; - }; - } - } - std::function get_first_dbl = conditional_t::get_get_dbl( - objects.get_object( 2 - no_result_mod ) ); - std::function get_second_dbl = conditional_t::get_get_dbl( - objects.get_object( 4 - no_result_mod ) ); - if( op == "*" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) * get_second_dbl( d ) ); - }; - } else if( op == "/" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) / get_second_dbl( d ) ); - }; - } else if( op == "+" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) + get_second_dbl( d ) ); - }; - } else if( op == "-" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) - get_second_dbl( d ) ); - }; - } else if( op == "%" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, static_cast( get_first_dbl( d ) ) % static_cast( get_second_dbl( d ) ) ); - }; - } else if( op == "^" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, pow( get_first_dbl( d ), get_second_dbl( d ) ) ); - }; - } else { - jo.throw_error( "unexpected operator " + op + " in " + jo.str() ); - function = []( dialogue const & ) { - return false; - }; - } - // ~ - } else if( objects.size() == 4 && !no_result ) { - op = objects.get_string( 3 ); - result = objects.get_string( 1 ); - if( result != "=" ) { - jo.throw_error( "invalid result " + op + " in " + jo.str() ); - function = []( dialogue const & ) { - return false; - }; - } - std::function get_first_dbl = conditional_t::get_get_dbl( - objects.get_object( 2 ) ); - if( op == "~" ) { - function = [get_first_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, ~static_cast( get_first_dbl( d ) ) ); - }; - } else { - jo.throw_error( "unexpected operator " + op + " in " + jo.str() ); - function = []( dialogue const & ) { - return false; - }; - } - - // =, -=, +=, *=, and /= - } else if( objects.size() == 3 && !no_result ) { - result = objects.get_string( 1 ); - std::function get_first_dbl = conditional_t::get_get_dbl( - objects.get_object( 0 ) ); - std::function get_second_dbl = conditional_t::get_get_dbl( - objects.get_object( 2 ) ); - if( result == "+=" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) + get_second_dbl( d ) ); - }; - } else if( result == "-=" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) - get_second_dbl( d ) ); - }; - } else if( result == "*=" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) * get_second_dbl( d ) ); - }; - } else if( result == "/=" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) / get_second_dbl( d ) ); - }; - } else if( result == "%=" ) { - function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, static_cast( get_first_dbl( d ) ) % static_cast( get_second_dbl( d ) ) ); - }; - } else if( result == "=" ) { - function = [get_second_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_second_dbl( d ) ); - }; - } else { - jo.throw_error( "unexpected result " + result + " in " + jo.str() ); - function = []( dialogue const & ) { - return false; - }; - } - // ++ and -- - } else if( objects.size() == 2 && !no_result ) { - op = objects.get_string( 1 ); - std::function get_first_dbl = conditional_t::get_get_dbl( - objects.get_object( 0 ) ); - if( op == "++" ) { - function = [get_first_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) + 1 ); - }; - } else if( op == "--" ) { - function = [get_first_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) - 1 ); - }; - } else { - jo.throw_error( "unexpected operator " + op + " in " + jo.str() ); - function = []( dialogue const & ) { - return false; - }; - } - } else if( objects.size() == 1 && no_result ) { - std::function get_first_dbl = conditional_t::get_get_dbl( - objects.get_object( 0 ) ); - function = [get_first_dbl, set_dbl]( dialogue & d ) { - set_dbl( d, get_first_dbl( d ) ); - }; - } else { - jo.throw_error( "Invalid number of args in " + jo.str() ); - function = []( dialogue const & ) { - return false; - }; - return; - } -} - -void talk_effect_fun_t::set_math( const JsonObject &jo, std::string_view member ) -{ - eoc_math math; - math.from_json( jo, member, eoc_math::type_t::assign ); - function = [math = std::move( math )]( dialogue & d ) { - return math.act( d ); - }; -} - void eoc_math::_validate_type( JsonArray const &objects, type_t type_ ) const { if( type_ != type_t::compare && action >= oper::equal ) { @@ -3269,259 +3289,88 @@ double eoc_math::act( dialogue &d ) const return 0; } -void conditional_t::set_u_has_camp() -{ - condition = []( dialogue const & ) { - return !get_player_character().camps.empty(); - }; -} - -void conditional_t::set_has_pickup_list( bool is_npc ) -{ - condition = [is_npc]( dialogue const & d ) { - return d.actor( is_npc )->has_ai_rule( "pickup_rule", "any" ); - }; -} - -void conditional_t::set_is_by_radio() -{ - condition = []( dialogue const & d ) { - return d.by_radio; - }; -} - -void conditional_t::set_has_reason() -{ - condition = []( dialogue const & d ) { - return !d.reason.empty(); - }; -} - -void conditional_t::set_roll_contested( const JsonObject &jo, const std::string_view member ) -{ - std::function get_check = conditional_t::get_get_dbl( jo.get_object( - member ) ); - dbl_or_var difficulty = get_dbl_or_var( jo, "difficulty", true ); - dbl_or_var die_size = get_dbl_or_var( jo, "die_size", false, 10 ); - condition = [get_check, difficulty, die_size]( dialogue & d ) { - return rng( 1, die_size.evaluate( d ) ) + get_check( d ) > difficulty.evaluate( d ); - }; -} - -void conditional_t::set_u_know_recipe( const JsonObject &jo, std::string_view member ) -{ - str_or_var known_recipe_id = get_str_or_var( jo.get_member( member ), member, true ); - condition = [known_recipe_id]( dialogue & d ) { - const recipe &rep = recipe_id( known_recipe_id.evaluate( d ) ).obj(); - // should be a talker function but recipes aren't in Character:: yet - return get_player_character().knows_recipe( &rep ); - }; -} - -void conditional_t::set_mission_has_generic_rewards() -{ - condition = []( dialogue const & d ) { - mission *miss = d.actor( true )->selected_mission(); - if( miss == nullptr ) { - debugmsg( "mission_has_generic_rewards: mission_selected == nullptr" ); - return true; - } - return miss->has_generic_rewards(); - }; -} - -void conditional_t::set_has_worn_with_flag( const JsonObject &jo, std::string_view member, - bool is_npc ) -{ - str_or_var flag = get_str_or_var( jo.get_member( member ), member, true ); - std::optional bp; - optional( jo, false, "bodypart", bp ); - condition = [flag, bp, is_npc]( dialogue const & d ) { - bodypart_id bid = bp.value_or( get_bp_from_str( d.reason ) ); - return d.actor( is_npc )->worn_with_flag( flag_id( flag.evaluate( d ) ), bid ); - }; -} - -void conditional_t::set_has_wielded_with_flag( const JsonObject &jo, std::string_view member, - bool is_npc ) -{ - str_or_var flag = get_str_or_var( jo.get_member( member ), member, true ); - condition = [flag, is_npc]( dialogue const & d ) { - return d.actor( is_npc )->wielded_with_flag( flag_id( flag.evaluate( d ) ) ); - }; -} - -void conditional_t::set_has_wielded_with_weapon_category( const JsonObject &jo, - std::string_view member, - bool is_npc ) -{ - str_or_var w_cat = get_str_or_var( jo.get_member( member ), member, true ); - condition = [w_cat, is_npc]( dialogue const & d ) { - return d.actor( is_npc )->wielded_with_weapon_category( weapon_category_id( w_cat.evaluate( d ) ) ); - }; -} - -void conditional_t::set_can_see( bool is_npc ) -{ - condition = [is_npc]( dialogue const & d ) { - return d.actor( is_npc )->can_see(); - }; -} - -void conditional_t::set_is_deaf( bool is_npc ) -{ - condition = [is_npc]( dialogue const & d ) { - return d.actor( is_npc )->is_deaf(); - }; -} - -void conditional_t::set_is_on_terrain( const JsonObject &jo, std::string_view member, - bool is_npc ) -{ - str_or_var terrain_type = get_str_or_var( jo.get_member( member ), member, true ); - condition = [terrain_type, is_npc]( dialogue const & d ) { - map &here = get_map(); - return here.ter( d.actor( is_npc )->pos() ) == ter_id( terrain_type.evaluate( d ) ); - }; -} - -void conditional_t::set_is_on_terrain_with_flag( const JsonObject &jo, std::string_view member, - bool is_npc ) -{ - str_or_var terrain_type = get_str_or_var( jo.get_member( member ), member, true ); - condition = [terrain_type, is_npc]( dialogue const & d ) { - map &here = get_map(); - return here.ter( d.actor( is_npc )->pos() )->has_flag( terrain_type.evaluate( d ) ); - }; -} - -void conditional_t::set_is_in_field( const JsonObject &jo, std::string_view member, - bool is_npc ) -{ - str_or_var field_type = get_str_or_var( jo.get_member( member ), member, true ); - condition = [field_type, is_npc]( dialogue const & d ) { - map &here = get_map(); - field_type_id ft = field_type_id( field_type.evaluate( d ) ); - for( const std::pair &f : here.field_at( d.actor( - is_npc )->pos() ) ) { - if( f.second.get_field_type() == ft ) { - return true; - } - } - return false; - }; -} - -void conditional_t::set_has_move_mode( const JsonObject &jo, std::string_view member, - bool is_npc ) -{ - str_or_var mode = get_str_or_var( jo.get_member( member ), member, true ); - condition = [mode, is_npc]( dialogue const & d ) { - return d.actor( is_npc )->get_move_mode() == move_mode_id( mode.evaluate( d ) ); - }; -} - -void conditional_t::set_can_see_location( const JsonObject &jo, std::string_view member, - bool is_npc ) -{ - str_or_var target = get_str_or_var( jo.get_member( member ), member, true ); - condition = [is_npc, target]( dialogue const & d ) { - tripoint_abs_ms target_pos = tripoint_abs_ms( tripoint::from_string( target.evaluate( d ) ) ); - return d.actor( is_npc )->can_see_location( get_map().getlocal( target_pos ) ); - }; -} - -void conditional_t::set_using_martial_art( const JsonObject &jo, std::string_view member, - bool is_npc ) -{ - str_or_var style_to_check = get_str_or_var( jo.get_member( member ), member, true ); - condition = [style_to_check, is_npc]( dialogue const & d ) { - return d.actor( is_npc )->using_martial_art( matype_id( style_to_check.evaluate( d ) ) ); - }; -} - static const std::vector parsers = { - {"u_has_any_trait", "npc_has_any_trait", jarg::array, &conditional_t::set_has_any_trait }, - {"u_has_trait", "npc_has_trait", jarg::member, &conditional_t::set_has_trait }, - {"u_has_visible_trait", "npc_has_visible_trait", jarg::member, &conditional_t::set_has_visible_trait }, - {"u_has_martial_art", "npc_has_martial_art", jarg::member, &conditional_t::set_has_martial_art }, - {"u_using_martial_art", "npc_using_martial_art", jarg::member, &conditional_t::set_using_martial_art }, - {"u_has_proficiency", "npc_has_proficiency", jarg::member, &conditional_t::set_has_proficiency }, - {"u_has_flag", "npc_has_flag", jarg::member, &conditional_t::set_has_flag }, - {"u_has_species", "npc_has_species", jarg::member, &conditional_t::set_has_species }, - {"u_bodytype", "npc_bodytype", jarg::member, &conditional_t::set_bodytype }, - {"u_has_class", "npc_has_class", jarg::member, &conditional_t::set_npc_has_class }, - {"u_has_activity", "npc_has_activity", jarg::string, &conditional_t::set_has_activity }, - {"u_is_riding", "npc_is_riding", jarg::string, &conditional_t::set_is_riding }, - {"u_has_mission", jarg::string, &conditional_t::set_u_has_mission }, - {"u_monsters_in_direction", jarg::string, &conditional_t::set_u_monsters_in_direction }, - {"u_safe_mode_trigger", jarg::member, &conditional_t::set_u_safe_mode_trigger }, - {"u_profession", jarg::string, &conditional_t::set_u_profession }, - {"u_has_strength", "npc_has_strength", jarg::member | jarg::array, &conditional_t::set_has_strength }, - {"u_has_dexterity", "npc_has_dexterity", jarg::member | jarg::array, &conditional_t::set_has_dexterity }, - {"u_has_intelligence", "npc_has_intelligence", jarg::member | jarg::array, &conditional_t::set_has_intelligence }, - {"u_has_perception", "npc_has_perception", jarg::member | jarg::array, &conditional_t::set_has_perception }, - {"u_has_hp", "npc_has_hp", jarg::member | jarg::array, &conditional_t::set_has_hp }, - {"u_has_part_temp", "npc_has_part_temp", jarg::member | jarg::array, &conditional_t::set_has_part_temp }, - {"u_is_wearing", "npc_is_wearing", jarg::member, &conditional_t::set_is_wearing }, - {"u_has_item", "npc_has_item", jarg::member, &conditional_t::set_has_item }, - {"u_has_item_with_flag", "npc_has_item_with_flag", jarg::member, &conditional_t::set_has_item_with_flag }, - {"u_has_items", "npc_has_items", jarg::member, &conditional_t::set_has_items }, - {"u_has_item_category", "npc_has_item_category", jarg::member, &conditional_t::set_has_item_category }, - {"u_has_bionics", "npc_has_bionics", jarg::member, &conditional_t::set_has_bionics }, - {"u_has_any_effect", "npc_has_any_effect", jarg::array, &conditional_t::set_has_any_effect }, - {"u_has_effect", "npc_has_effect", jarg::member, &conditional_t::set_has_effect }, - {"u_need", "npc_need", jarg::member, &conditional_t::set_need }, - {"u_query", "npc_query", jarg::member, &conditional_t::set_query }, - {"u_query_tile", "npc_query_tile", jarg::member, &conditional_t::set_query_tile }, - {"u_at_om_location", "npc_at_om_location", jarg::member, &conditional_t::set_at_om_location }, - {"u_near_om_location", "npc_near_om_location", jarg::member, &conditional_t::set_near_om_location }, - {"u_has_var", "npc_has_var", jarg::string, &conditional_t::set_has_var }, - {"expects_vars", jarg::member, &conditional_t::set_expects_vars }, - {"u_compare_var", "npc_compare_var", jarg::string, &conditional_t::set_compare_var }, - {"u_compare_time_since_var", "npc_compare_time_since_var", jarg::string, &conditional_t::set_compare_time_since_var }, - {"npc_role_nearby", jarg::string, &conditional_t::set_npc_role_nearby }, - {"npc_allies", jarg::member | jarg::array, &conditional_t::set_npc_allies }, - {"npc_allies_global", jarg::member | jarg::array, &conditional_t::set_npc_allies_global }, - {"u_service", "npc_service", jarg::member, &conditional_t::set_npc_service }, - {"u_has_cash", jarg::member | jarg::array, &conditional_t::set_u_has_cash }, - {"u_are_owed", jarg::member | jarg::array, &conditional_t::set_u_are_owed }, - {"u_aim_rule", "npc_aim_rule", jarg::member, &conditional_t::set_npc_aim_rule }, - {"u_engagement_rule", "npc_engagement_rule", jarg::member, &conditional_t::set_npc_engagement_rule }, - {"u_cbm_reserve_rule", "npc_cbm_reserve_rule", jarg::member, &conditional_t::set_npc_cbm_reserve_rule }, - {"u_cbm_recharge_rule", "npc_cbm_recharge_rule", jarg::member, &conditional_t::set_npc_cbm_recharge_rule }, - {"u_rule", "npc_rule", jarg::member, &conditional_t::set_npc_rule }, - {"u_override", "npc_override", jarg::member, &conditional_t::set_npc_override }, - {"days_since_cataclysm", jarg::member | jarg::array, &conditional_t::set_days_since }, - {"is_season", jarg::member, &conditional_t::set_is_season }, - {"u_mission_goal", "mission_goal", jarg::member, &conditional_t::set_mission_goal }, - {"u_mission_goal", "npc_mission_goal", jarg::member, &conditional_t::set_mission_goal }, - {"roll_contested", jarg::member, &conditional_t::set_roll_contested }, - {"u_know_recipe", jarg::member, &conditional_t::set_u_know_recipe }, - {"one_in_chance", jarg::member | jarg::array, &conditional_t::set_one_in_chance }, - {"x_in_y_chance", jarg::object, &conditional_t::set_x_in_y_chance }, - {"u_has_worn_with_flag", "npc_has_worn_with_flag", jarg::member, &conditional_t::set_has_worn_with_flag }, - {"u_has_wielded_with_flag", "npc_has_wielded_with_flag", jarg::member, &conditional_t::set_has_wielded_with_flag }, - {"u_has_wielded_with_weapon_category", "npc_has_wielded_with_weapon_category", jarg::member, &conditional_t::set_has_wielded_with_weapon_category }, - {"u_is_on_terrain", "npc_is_on_terrain", jarg::member, &conditional_t::set_is_on_terrain }, - {"u_is_on_terrain_with_flag", "npc_is_on_terrain_with_flag", jarg::member, &conditional_t::set_is_on_terrain_with_flag }, - {"u_is_in_field", "npc_is_in_field", jarg::member, &conditional_t::set_is_in_field }, - {"u_has_move_mode", "npc_has_move_mode", jarg::member, &conditional_t::set_has_move_mode }, - {"u_can_see_location", "npc_can_see_location", jarg::member, &conditional_t::set_can_see_location }, - {"is_weather", jarg::member, &conditional_t::set_is_weather }, - {"map_terrain_with_flag", jarg::member, &conditional_t::set_map_ter_furn_with_flag }, - {"map_furniture_with_flag", jarg::member, &conditional_t::set_map_ter_furn_with_flag }, - {"map_in_city", jarg::member, &conditional_t::set_map_in_city }, - {"mod_is_loaded", jarg::member, &conditional_t::set_mod_is_loaded }, - {"u_has_faction_trust", jarg::member | jarg::array, &conditional_t::set_has_faction_trust }, - {"compare_int", jarg::member, &conditional_t::set_compare_num }, - {"compare_num", jarg::member, &conditional_t::set_compare_num }, - {"math", jarg::member, &conditional_t::set_math }, - {"compare_string", jarg::member, &conditional_t::set_compare_string }, - {"get_condition", jarg::member, &conditional_t::set_get_condition }, - {"get_game_option", jarg::member, &conditional_t::set_get_option }, + {"u_has_any_trait", "npc_has_any_trait", jarg::array, &conditional_fun::f_has_any_trait }, + {"u_has_trait", "npc_has_trait", jarg::member, &conditional_fun::f_has_trait }, + {"u_has_visible_trait", "npc_has_visible_trait", jarg::member, &conditional_fun::f_has_visible_trait }, + {"u_has_martial_art", "npc_has_martial_art", jarg::member, &conditional_fun::f_has_martial_art }, + {"u_using_martial_art", "npc_using_martial_art", jarg::member, &conditional_fun::f_using_martial_art }, + {"u_has_proficiency", "npc_has_proficiency", jarg::member, &conditional_fun::f_has_proficiency }, + {"u_has_flag", "npc_has_flag", jarg::member, &conditional_fun::f_has_flag }, + {"u_has_species", "npc_has_species", jarg::member, &conditional_fun::f_has_species }, + {"u_bodytype", "npc_bodytype", jarg::member, &conditional_fun::f_bodytype }, + {"u_has_class", "npc_has_class", jarg::member, &conditional_fun::f_npc_has_class }, + {"u_has_activity", "npc_has_activity", jarg::string, &conditional_fun::f_has_activity }, + {"u_is_riding", "npc_is_riding", jarg::string, &conditional_fun::f_is_riding }, + {"u_has_mission", jarg::string, &conditional_fun::f_u_has_mission }, + {"u_monsters_in_direction", jarg::string, &conditional_fun::f_u_monsters_in_direction }, + {"u_safe_mode_trigger", jarg::member, &conditional_fun::f_u_safe_mode_trigger }, + {"u_profession", jarg::string, &conditional_fun::f_u_profession }, + {"u_has_strength", "npc_has_strength", jarg::member | jarg::array, &conditional_fun::f_has_strength }, + {"u_has_dexterity", "npc_has_dexterity", jarg::member | jarg::array, &conditional_fun::f_has_dexterity }, + {"u_has_intelligence", "npc_has_intelligence", jarg::member | jarg::array, &conditional_fun::f_has_intelligence }, + {"u_has_perception", "npc_has_perception", jarg::member | jarg::array, &conditional_fun::f_has_perception }, + {"u_has_hp", "npc_has_hp", jarg::member | jarg::array, &conditional_fun::f_has_hp }, + {"u_has_part_temp", "npc_has_part_temp", jarg::member | jarg::array, &conditional_fun::f_has_part_temp }, + {"u_is_wearing", "npc_is_wearing", jarg::member, &conditional_fun::f_is_wearing }, + {"u_has_item", "npc_has_item", jarg::member, &conditional_fun::f_has_item }, + {"u_has_item_with_flag", "npc_has_item_with_flag", jarg::member, &conditional_fun::f_has_item_with_flag }, + {"u_has_items", "npc_has_items", jarg::member, &conditional_fun::f_has_items }, + {"u_has_item_category", "npc_has_item_category", jarg::member, &conditional_fun::f_has_item_category }, + {"u_has_bionics", "npc_has_bionics", jarg::member, &conditional_fun::f_has_bionics }, + {"u_has_any_effect", "npc_has_any_effect", jarg::array, &conditional_fun::f_has_any_effect }, + {"u_has_effect", "npc_has_effect", jarg::member, &conditional_fun::f_has_effect }, + {"u_need", "npc_need", jarg::member, &conditional_fun::f_need }, + {"u_query", "npc_query", jarg::member, &conditional_fun::f_query }, + {"u_query_tile", "npc_query_tile", jarg::member, &conditional_fun::f_query_tile }, + {"u_at_om_location", "npc_at_om_location", jarg::member, &conditional_fun::f_at_om_location }, + {"u_near_om_location", "npc_near_om_location", jarg::member, &conditional_fun::f_near_om_location }, + {"u_has_var", "npc_has_var", jarg::string, &conditional_fun::f_has_var }, + {"expects_vars", jarg::member, &conditional_fun::f_expects_vars }, + {"u_compare_var", "npc_compare_var", jarg::string, &conditional_fun::f_compare_var }, + {"u_compare_time_since_var", "npc_compare_time_since_var", jarg::string, &conditional_fun::f_compare_time_since_var }, + {"npc_role_nearby", jarg::string, &conditional_fun::f_npc_role_nearby }, + {"npc_allies", jarg::member | jarg::array, &conditional_fun::f_npc_allies }, + {"npc_allies_global", jarg::member | jarg::array, &conditional_fun::f_npc_allies_global }, + {"u_service", "npc_service", jarg::member, &conditional_fun::f_npc_service }, + {"u_has_cash", jarg::member | jarg::array, &conditional_fun::f_u_has_cash }, + {"u_are_owed", jarg::member | jarg::array, &conditional_fun::f_u_are_owed }, + {"u_aim_rule", "npc_aim_rule", jarg::member, &conditional_fun::f_npc_aim_rule }, + {"u_engagement_rule", "npc_engagement_rule", jarg::member, &conditional_fun::f_npc_engagement_rule }, + {"u_cbm_reserve_rule", "npc_cbm_reserve_rule", jarg::member, &conditional_fun::f_npc_cbm_reserve_rule }, + {"u_cbm_recharge_rule", "npc_cbm_recharge_rule", jarg::member, &conditional_fun::f_npc_cbm_recharge_rule }, + {"u_rule", "npc_rule", jarg::member, &conditional_fun::f_npc_rule }, + {"u_override", "npc_override", jarg::member, &conditional_fun::f_npc_override }, + {"days_since_cataclysm", jarg::member | jarg::array, &conditional_fun::f_days_since }, + {"is_season", jarg::member, &conditional_fun::f_is_season }, + {"u_mission_goal", "mission_goal", jarg::member, &conditional_fun::f_mission_goal }, + {"u_mission_goal", "npc_mission_goal", jarg::member, &conditional_fun::f_mission_goal }, + {"roll_contested", jarg::member, &conditional_fun::f_roll_contested }, + {"u_know_recipe", jarg::member, &conditional_fun::f_u_know_recipe }, + {"one_in_chance", jarg::member | jarg::array, &conditional_fun::f_one_in_chance }, + {"x_in_y_chance", jarg::object, &conditional_fun::f_x_in_y_chance }, + {"u_has_worn_with_flag", "npc_has_worn_with_flag", jarg::member, &conditional_fun::f_has_worn_with_flag }, + {"u_has_wielded_with_flag", "npc_has_wielded_with_flag", jarg::member, &conditional_fun::f_has_wielded_with_flag }, + {"u_has_wielded_with_weapon_category", "npc_has_wielded_with_weapon_category", jarg::member, &conditional_fun::f_has_wielded_with_weapon_category }, + {"u_is_on_terrain", "npc_is_on_terrain", jarg::member, &conditional_fun::f_is_on_terrain }, + {"u_is_on_terrain_with_flag", "npc_is_on_terrain_with_flag", jarg::member, &conditional_fun::f_is_on_terrain_with_flag }, + {"u_is_in_field", "npc_is_in_field", jarg::member, &conditional_fun::f_is_in_field }, + {"u_has_move_mode", "npc_has_move_mode", jarg::member, &conditional_fun::f_has_move_mode }, + {"u_can_see_location", "npc_can_see_location", jarg::member, &conditional_fun::f_can_see_location }, + {"is_weather", jarg::member, &conditional_fun::f_is_weather }, + {"map_terrain_with_flag", jarg::member, &conditional_fun::f_map_ter_furn_with_flag }, + {"map_furniture_with_flag", jarg::member, &conditional_fun::f_map_ter_furn_with_flag }, + {"map_in_city", jarg::member, &conditional_fun::f_map_in_city }, + {"mod_is_loaded", jarg::member, &conditional_fun::f_mod_is_loaded }, + {"u_has_faction_trust", jarg::member | jarg::array, &conditional_fun::f_has_faction_trust }, + {"compare_int", jarg::member, &conditional_fun::f_compare_num }, + {"compare_num", jarg::member, &conditional_fun::f_compare_num }, + {"math", jarg::member, &conditional_fun::f_math }, + {"compare_string", jarg::member, &conditional_fun::f_compare_string }, + {"get_condition", jarg::member, &conditional_fun::f_get_condition }, + {"get_game_option", jarg::member, &conditional_fun::f_get_option }, }; // When updating this, please also update `dynamic_line_string_keys` in @@ -3530,59 +3379,59 @@ parsers = { static const std::vector parsers_simple = { - {"u_male", "npc_male", &conditional_t::set_is_male }, - {"u_female", "npc_female", &conditional_t::set_is_female }, - {"has_no_assigned_mission", &conditional_t::set_no_assigned_mission }, - {"has_assigned_mission", &conditional_t::set_has_assigned_mission }, - {"has_many_assigned_missions", &conditional_t::set_has_many_assigned_missions }, - {"u_has_no_available_mission", "has_no_available_mission", &conditional_t::set_no_available_mission }, - {"u_has_no_available_mission", "npc_has_no_available_mission", &conditional_t::set_no_available_mission }, - {"u_has_available_mission", "has_available_mission", &conditional_t::set_has_available_mission }, - {"u_has_available_mission", "npc_has_available_mission", &conditional_t::set_has_available_mission }, - {"u_has_many_available_missions", "has_many_available_missions", &conditional_t::set_has_many_available_missions }, - {"u_has_many_available_missions", "npc_has_many_available_missions", &conditional_t::set_has_many_available_missions }, - {"u_mission_complete", "mission_complete", &conditional_t::set_mission_complete }, - {"u_mission_complete", "npc_mission_complete", &conditional_t::set_mission_complete }, - {"u_mission_incomplete", "mission_incomplete", &conditional_t::set_mission_incomplete }, - {"u_mission_incomplete", "npc_mission_incomplete", &conditional_t::set_mission_incomplete }, - {"u_mission_failed", "mission_failed", &conditional_t::set_mission_failed }, - {"u_mission_failed", "npc_mission_failed", &conditional_t::set_mission_failed }, - {"u_available", "npc_available", &conditional_t::set_npc_available }, - {"u_following", "npc_following", &conditional_t::set_npc_following }, - {"u_friend", "npc_friend", &conditional_t::set_npc_friend }, - {"u_hostile", "npc_hostile", &conditional_t::set_npc_hostile }, - {"u_train_skills", "npc_train_skills", &conditional_t::set_npc_train_skills }, - {"u_train_styles", "npc_train_styles", &conditional_t::set_npc_train_styles }, - {"u_train_spells", "npc_train_spells", &conditional_t::set_npc_train_spells }, - {"u_at_safe_space", "at_safe_space", &conditional_t::set_at_safe_space }, - {"u_at_safe_space", "npc_at_safe_space", &conditional_t::set_at_safe_space }, - {"u_can_stow_weapon", "npc_can_stow_weapon", &conditional_t::set_can_stow_weapon }, - {"u_can_drop_weapon", "npc_can_drop_weapon", &conditional_t::set_can_drop_weapon }, - {"u_has_weapon", "npc_has_weapon", &conditional_t::set_has_weapon }, - {"u_driving", "npc_driving", &conditional_t::set_is_driving }, - {"u_has_activity", "npc_has_activity", &conditional_t::set_has_activity }, - {"u_is_riding", "npc_is_riding", &conditional_t::set_is_riding }, - {"is_day", &conditional_t::set_is_day }, - {"u_has_stolen_item", "npc_has_stolen_item", &conditional_t::set_has_stolen_item }, - {"u_is_outside", "is_outside", &conditional_t::set_is_outside }, - {"u_is_outside", "npc_is_outside", &conditional_t::set_is_outside }, - {"u_is_underwater", "npc_is_underwater", &conditional_t::set_is_underwater }, - {"u_has_camp", &conditional_t::set_u_has_camp }, - {"u_has_pickup_list", "has_pickup_list", &conditional_t::set_has_pickup_list }, - {"u_has_pickup_list", "npc_has_pickup_list", &conditional_t::set_has_pickup_list }, - {"is_by_radio", &conditional_t::set_is_by_radio }, - {"has_reason", &conditional_t::set_has_reason }, - {"mission_has_generic_rewards", &conditional_t::set_mission_has_generic_rewards }, - {"u_can_see", "npc_can_see", &conditional_t::set_can_see }, - {"u_is_deaf", "npc_is_deaf", &conditional_t::set_is_deaf }, - {"u_is_alive", "npc_is_alive", &conditional_t::set_is_alive }, - {"u_is_avatar", "npc_is_avatar", &conditional_t::set_is_avatar }, - {"u_is_npc", "npc_is_npc", &conditional_t::set_is_npc }, - {"u_is_character", "npc_is_character", &conditional_t::set_is_character }, - {"u_is_monster", "npc_is_monster", &conditional_t::set_is_monster }, - {"u_is_item", "npc_is_item", &conditional_t::set_is_item }, - {"u_is_furniture", "npc_is_furniture", &conditional_t::set_is_furniture }, - {"player_see_u", "player_see_npc", &conditional_t::set_player_see }, + {"u_male", "npc_male", &conditional_fun::f_is_male }, + {"u_female", "npc_female", &conditional_fun::f_is_female }, + {"has_no_assigned_mission", &conditional_fun::f_no_assigned_mission }, + {"has_assigned_mission", &conditional_fun::f_has_assigned_mission }, + {"has_many_assigned_missions", &conditional_fun::f_has_many_assigned_missions }, + {"u_has_no_available_mission", "has_no_available_mission", &conditional_fun::f_no_available_mission }, + {"u_has_no_available_mission", "npc_has_no_available_mission", &conditional_fun::f_no_available_mission }, + {"u_has_available_mission", "has_available_mission", &conditional_fun::f_has_available_mission }, + {"u_has_available_mission", "npc_has_available_mission", &conditional_fun::f_has_available_mission }, + {"u_has_many_available_missions", "has_many_available_missions", &conditional_fun::f_has_many_available_missions }, + {"u_has_many_available_missions", "npc_has_many_available_missions", &conditional_fun::f_has_many_available_missions }, + {"u_mission_complete", "mission_complete", &conditional_fun::f_mission_complete }, + {"u_mission_complete", "npc_mission_complete", &conditional_fun::f_mission_complete }, + {"u_mission_incomplete", "mission_incomplete", &conditional_fun::f_mission_incomplete }, + {"u_mission_incomplete", "npc_mission_incomplete", &conditional_fun::f_mission_incomplete }, + {"u_mission_failed", "mission_failed", &conditional_fun::f_mission_failed }, + {"u_mission_failed", "npc_mission_failed", &conditional_fun::f_mission_failed }, + {"u_available", "npc_available", &conditional_fun::f_npc_available }, + {"u_following", "npc_following", &conditional_fun::f_npc_following }, + {"u_friend", "npc_friend", &conditional_fun::f_npc_friend }, + {"u_hostile", "npc_hostile", &conditional_fun::f_npc_hostile }, + {"u_train_skills", "npc_train_skills", &conditional_fun::f_npc_train_skills }, + {"u_train_styles", "npc_train_styles", &conditional_fun::f_npc_train_styles }, + {"u_train_spells", "npc_train_spells", &conditional_fun::f_npc_train_spells }, + {"u_at_safe_space", "at_safe_space", &conditional_fun::f_at_safe_space }, + {"u_at_safe_space", "npc_at_safe_space", &conditional_fun::f_at_safe_space }, + {"u_can_stow_weapon", "npc_can_stow_weapon", &conditional_fun::f_can_stow_weapon }, + {"u_can_drop_weapon", "npc_can_drop_weapon", &conditional_fun::f_can_drop_weapon }, + {"u_has_weapon", "npc_has_weapon", &conditional_fun::f_has_weapon }, + {"u_driving", "npc_driving", &conditional_fun::f_is_driving }, + {"u_has_activity", "npc_has_activity", &conditional_fun::f_has_activity }, + {"u_is_riding", "npc_is_riding", &conditional_fun::f_is_riding }, + {"is_day", &conditional_fun::f_is_day }, + {"u_has_stolen_item", "npc_has_stolen_item", &conditional_fun::f_has_stolen_item }, + {"u_is_outside", "is_outside", &conditional_fun::f_is_outside }, + {"u_is_outside", "npc_is_outside", &conditional_fun::f_is_outside }, + {"u_is_underwater", "npc_is_underwater", &conditional_fun::f_is_underwater }, + {"u_has_camp", &conditional_fun::f_u_has_camp }, + {"u_has_pickup_list", "has_pickup_list", &conditional_fun::f_has_pickup_list }, + {"u_has_pickup_list", "npc_has_pickup_list", &conditional_fun::f_has_pickup_list }, + {"is_by_radio", &conditional_fun::f_is_by_radio }, + {"has_reason", &conditional_fun::f_has_reason }, + {"mission_has_generic_rewards", &conditional_fun::f_mission_has_generic_rewards }, + {"u_can_see", "npc_can_see", &conditional_fun::f_can_see }, + {"u_is_deaf", "npc_is_deaf", &conditional_fun::f_is_deaf }, + {"u_is_alive", "npc_is_alive", &conditional_fun::f_is_alive }, + {"u_is_avatar", "npc_is_avatar", &conditional_fun::f_is_avatar }, + {"u_is_npc", "npc_is_npc", &conditional_fun::f_is_npc }, + {"u_is_character", "npc_is_character", &conditional_fun::f_is_character }, + {"u_is_monster", "npc_is_monster", &conditional_fun::f_is_monster }, + {"u_is_item", "npc_is_item", &conditional_fun::f_is_item }, + {"u_is_furniture", "npc_is_furniture", &conditional_fun::f_is_furniture }, + {"player_see_u", "player_see_npc", &conditional_fun::f_player_see }, }; conditional_t::conditional_t( const JsonObject &jo ) @@ -3645,14 +3494,14 @@ conditional_t::conditional_t( const JsonObject &jo ) for( const condition_parser &p : parsers ) { if( p.has_beta ) { if( p.check( jo ) ) { - ( this->*p.f_beta )( jo, p.key_alpha, false ); + condition = p.f_beta( jo, p.key_alpha, false ); found = true; } else if( p.check( jo, true ) ) { - ( this->*p.f_beta )( jo, p.key_beta, true ); + condition = p.f_beta( jo, p.key_beta, true ); found = true; } } else if( p.check( jo ) ) { - ( this->*p.f )( jo, p.key_alpha ); + condition = p.f( jo, p.key_alpha ); if( jo.has_member( "math" ) ) { found_sub_member = true; } @@ -3685,14 +3534,14 @@ conditional_t::conditional_t( std::string_view type ) for( const condition_parser &p : parsers_simple ) { if( p.has_beta ) { if( type == p.key_alpha ) { - ( this->*p.f_beta_simple )( false ); + condition = p.f_beta_simple( false ); found = true; } else if( type == p.key_beta ) { - ( this->*p.f_beta_simple )( true ); + condition = p.f_beta_simple( true ); found = true; } } else if( type == p.key_alpha ) { - ( this->*p.f_simple )(); + condition = p.f_simple(); found = true; } if( found ) { @@ -3741,3 +3590,8 @@ template std::function conditional_t::get_set_dbl<>( const kwargs_shim &, const std::optional &, const std::optional &, bool ); + +template std::function +conditional_t::get_set_dbl<>( const JsonObject &, + const std::optional &, + const std::optional &, bool ); diff --git a/src/condition.h b/src/condition.h index aea1323d7e422..6898d61e20a9c 100644 --- a/src/condition.h +++ b/src/condition.h @@ -70,148 +70,13 @@ void finalize_conditions(); * returns whether the response is allowed. */ struct conditional_t { - private: - std::function condition; - public: + using func = std::function; + conditional_t() = default; explicit conditional_t( std::string_view type ); explicit conditional_t( const JsonObject &jo ); - void set_has_any_trait( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_trait( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_visible_trait( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_martial_art( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_flag( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_species( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_proficiency( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_bodytype( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_var( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_expects_vars( const JsonObject &jo, std::string_view member ); - void set_compare_var( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_compare_time_since_var( const JsonObject &jo, std::string_view member, - bool is_npc = false ); - void set_has_activity( bool is_npc = false ); - void set_has_activity( const JsonObject &, std::string_view, bool is_npc = false ) { - set_has_activity( is_npc ); - } - void set_is_riding( bool is_npc = false ); - void set_is_riding( const JsonObject &, std::string_view, bool is_npc = false ) { - set_is_riding( is_npc ); - } - void set_npc_has_class( const JsonObject &jo, std::string_view member, bool is_npc ); - void set_u_has_mission( const JsonObject &jo, std::string_view member ); - void set_u_monsters_in_direction( const JsonObject &jo, std::string_view member ); - void set_u_safe_mode_trigger( const JsonObject &jo, std::string_view member ); - void set_u_profession( const JsonObject &jo, std::string_view member ); - void set_has_strength( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_dexterity( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_intelligence( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_perception( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_hp( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_part_temp( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_is_deaf( bool is_npc = false ); - void set_is_on_terrain( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_is_on_terrain_with_flag( const JsonObject &jo, std::string_view member, - bool is_npc = false ); - void set_is_in_field( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_one_in_chance( const JsonObject &jo, std::string_view member ); - void set_query( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_query_tile( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_x_in_y_chance( const JsonObject &jo, std::string_view member ); - void set_has_worn_with_flag( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_wielded_with_flag( const JsonObject &jo, std::string_view member, - bool is_npc = false ); - void set_has_wielded_with_weapon_category( const JsonObject &jo, std::string_view member, - bool is_npc = false ); - void set_is_wearing( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_item( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_items( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_item_with_flag( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_item_category( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_bionics( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_any_effect( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_effect( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_need( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_at_om_location( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_near_om_location( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_has_move_mode( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_can_see_location( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_using_martial_art( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_npc_role_nearby( const JsonObject &jo, std::string_view member ); - void set_npc_allies( const JsonObject &jo, std::string_view member ); - void set_npc_allies_global( const JsonObject &jo, std::string_view member ); - void set_u_has_cash( const JsonObject &jo, std::string_view member ); - void set_u_are_owed( const JsonObject &jo, std::string_view member ); - void set_npc_aim_rule( const JsonObject &jo, std::string_view member, bool is_npc ); - void set_npc_engagement_rule( const JsonObject &jo, std::string_view member, bool is_npc ); - void set_npc_cbm_reserve_rule( const JsonObject &jo, std::string_view member, bool is_npc ); - void set_npc_cbm_recharge_rule( const JsonObject &jo, std::string_view member, bool is_npc ); - void set_npc_rule( const JsonObject &jo, std::string_view member, bool is_npc ); - void set_npc_override( const JsonObject &jo, std::string_view member, bool is_npc ); - void set_days_since( const JsonObject &jo, std::string_view member ); - void set_is_season( const JsonObject &jo, std::string_view member ); - void set_is_weather( const JsonObject &jo, std::string_view member ); - void set_map_ter_furn_with_flag( const JsonObject &jo, std::string_view member ); - void set_map_in_city( const JsonObject &jo, std::string_view member ); - void set_mod_is_loaded( const JsonObject &jo, std::string_view member ); - void set_mission_goal( const JsonObject &jo, std::string_view member, bool is_npc ); - void set_has_faction_trust( const JsonObject &jo, std::string_view member ); - void set_no_assigned_mission(); - void set_has_assigned_mission(); - void set_has_many_assigned_missions(); - void set_no_available_mission( bool is_npc ); - void set_has_available_mission( bool is_npc ); - void set_has_many_available_missions( bool is_npc ); - void set_mission_complete( bool is_npc ); - void set_mission_incomplete( bool is_npc ); - void set_mission_failed( bool is_npc ); - void set_npc_service( const JsonObject &, std::string_view, bool is_npc ); - void set_npc_available( bool is_npc ); - void set_npc_following( bool is_npc ); - void set_npc_friend( bool is_npc ); - void set_npc_hostile( bool is_npc ); - void set_npc_train_skills( bool is_npc ); - void set_npc_train_styles( bool is_npc ); - void set_npc_train_spells( bool is_npc ); - void set_at_safe_space( bool is_npc ); - void set_can_stow_weapon( bool is_npc = false ); - void set_can_drop_weapon( bool is_npc = false ); - void set_has_weapon( bool is_npc = false ); - void set_is_driving( bool is_npc = false ); - void set_is_day(); - void set_has_stolen_item( bool is_npc = false ); - void set_is_outside( bool is_npc = false ); - void set_is_underwater( bool is_npc = false ); - void set_is_by_radio(); - void set_u_has_camp(); - void set_has_pickup_list( bool is_npc ); - void set_has_reason(); - void set_is_alive( bool is_npc = false ); - void set_is_avatar( bool is_npc = false ); - void set_is_npc( bool is_npc = false ); - void set_is_character( bool is_npc = false ); - void set_is_monster( bool is_npc = false ); - void set_is_item( bool is_npc = false ); - void set_is_furniture( bool is_npc = false ); - void set_is_gender( bool is_male, bool is_npc = false ); - void set_is_male( bool is_npc = false ) { - set_is_gender( true, is_npc ); - } - void set_is_female( bool is_npc = false ) { - set_is_gender( false, is_npc ); - } - void set_has_skill( const JsonObject &jo, std::string_view member, bool is_npc = false ); - void set_roll_contested( const JsonObject &jo, std::string_view member ); - void set_u_know_recipe( const JsonObject &jo, std::string_view member ); - void set_mission_has_generic_rewards(); - void set_can_see( bool is_npc = false ); - void set_player_see( bool is_npc = false ); - void set_get_option( const JsonObject &jo, std::string_view member ); - void set_compare_string( const JsonObject &jo, std::string_view member ); - void set_get_condition( const JsonObject &jo, std::string_view member ); - void set_compare_num( const JsonObject &jo, std::string_view member ); - void set_math( const JsonObject &jo, std::string_view member ); static std::function get_get_string( const JsonObject &jo ); static std::function get_get_translation( const JsonObject &jo ); template @@ -228,6 +93,9 @@ struct conditional_t { } return condition( d ); } + + private: + func condition; }; extern template std::function diff --git a/src/npctalk.cpp b/src/npctalk.cpp index ecdd72608ae84..cbe6aae85b374 100644 --- a/src/npctalk.cpp +++ b/src/npctalk.cpp @@ -5962,6 +5962,185 @@ void talk_effect_fun_t::set_teleport( const JsonObject &jo, std::string_view mem }; } +void talk_effect_fun_t::set_arithmetic( const JsonObject &jo, std::string_view member, + bool no_result ) +{ + JsonArray objects = jo.get_array( member ); + std::optional min; + std::optional max; + if( jo.has_member( "min" ) ) { + min = get_dbl_or_var_part( jo.get_member( "min" ), "min" ); + } else if( jo.has_member( "min_time" ) ) { + dbl_or_var_part value; + time_duration min_time; + mandatory( jo, false, "min_time", min_time ); + value.dbl_val = to_turns( min_time ); + min = value; + } + if( jo.has_member( "max" ) ) { + max = get_dbl_or_var_part( jo.get_member( "max" ), "max" ); + } else if( jo.has_member( "max_time" ) ) { + dbl_or_var_part value; + time_duration max_time; + mandatory( jo, false, "max_time", max_time ); + value.dbl_val = to_turns( max_time ); + max = value; + } + std::string op = "none"; + std::string result = "none"; + std::function set_dbl = conditional_t::get_set_dbl( + objects.get_object( 0 ), min, + max, no_result ); + int no_result_mod = no_result ? 2 : 0; //In the case of a no result we have fewer terms. + // Normal full version + if( static_cast( objects.size() ) == 5 - no_result_mod ) { + op = objects.get_string( 3 - no_result_mod ); + if( !no_result ) { + result = objects.get_string( 1 ); + if( result != "=" ) { + jo.throw_error( "invalid result " + op + " in " + jo.str() ); + function = []( dialogue const & ) { + return false; + }; + } + } + std::function get_first_dbl = conditional_t::get_get_dbl( + objects.get_object( 2 - no_result_mod ) ); + std::function get_second_dbl = conditional_t::get_get_dbl( + objects.get_object( 4 - no_result_mod ) ); + if( op == "*" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) * get_second_dbl( d ) ); + }; + } else if( op == "/" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) / get_second_dbl( d ) ); + }; + } else if( op == "+" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) + get_second_dbl( d ) ); + }; + } else if( op == "-" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) - get_second_dbl( d ) ); + }; + } else if( op == "%" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, static_cast( get_first_dbl( d ) ) % static_cast( get_second_dbl( d ) ) ); + }; + } else if( op == "^" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, pow( get_first_dbl( d ), get_second_dbl( d ) ) ); + }; + } else { + jo.throw_error( "unexpected operator " + op + " in " + jo.str() ); + function = []( dialogue const & ) { + return false; + }; + } + // ~ + } else if( objects.size() == 4 && !no_result ) { + op = objects.get_string( 3 ); + result = objects.get_string( 1 ); + if( result != "=" ) { + jo.throw_error( "invalid result " + op + " in " + jo.str() ); + function = []( dialogue const & ) { + return false; + }; + } + std::function get_first_dbl = conditional_t::get_get_dbl( + objects.get_object( 2 ) ); + if( op == "~" ) { + function = [get_first_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, ~static_cast( get_first_dbl( d ) ) ); + }; + } else { + jo.throw_error( "unexpected operator " + op + " in " + jo.str() ); + function = []( dialogue const & ) { + return false; + }; + } + + // =, -=, +=, *=, and /= + } else if( objects.size() == 3 && !no_result ) { + result = objects.get_string( 1 ); + std::function get_first_dbl = conditional_t::get_get_dbl( + objects.get_object( 0 ) ); + std::function get_second_dbl = conditional_t::get_get_dbl( + objects.get_object( 2 ) ); + if( result == "+=" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) + get_second_dbl( d ) ); + }; + } else if( result == "-=" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) - get_second_dbl( d ) ); + }; + } else if( result == "*=" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) * get_second_dbl( d ) ); + }; + } else if( result == "/=" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) / get_second_dbl( d ) ); + }; + } else if( result == "%=" ) { + function = [get_first_dbl, get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, static_cast( get_first_dbl( d ) ) % static_cast( get_second_dbl( d ) ) ); + }; + } else if( result == "=" ) { + function = [get_second_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_second_dbl( d ) ); + }; + } else { + jo.throw_error( "unexpected result " + result + " in " + jo.str() ); + function = []( dialogue const & ) { + return false; + }; + } + // ++ and -- + } else if( objects.size() == 2 && !no_result ) { + op = objects.get_string( 1 ); + std::function get_first_dbl = conditional_t::get_get_dbl( + objects.get_object( 0 ) ); + if( op == "++" ) { + function = [get_first_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) + 1 ); + }; + } else if( op == "--" ) { + function = [get_first_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) - 1 ); + }; + } else { + jo.throw_error( "unexpected operator " + op + " in " + jo.str() ); + function = []( dialogue const & ) { + return false; + }; + } + } else if( objects.size() == 1 && no_result ) { + std::function get_first_dbl = conditional_t::get_get_dbl( + objects.get_object( 0 ) ); + function = [get_first_dbl, set_dbl]( dialogue & d ) { + set_dbl( d, get_first_dbl( d ) ); + }; + } else { + jo.throw_error( "Invalid number of args in " + jo.str() ); + function = []( dialogue const & ) { + return false; + }; + return; + } +} + +void talk_effect_fun_t::set_math( const JsonObject &jo, std::string_view member ) +{ + eoc_math math; + math.from_json( jo, member, eoc_math::type_t::assign ); + function = [math = std::move( math )]( dialogue & d ) { + return math.act( d ); + }; +} + void talk_effect_t::set_effect_consequence( const talk_effect_fun_t &fun, dialogue_consequence con ) {