diff --git a/data/json/construction.json b/data/json/construction.json index 6c0b491b2f474..076d4a529b55f 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -4893,7 +4893,7 @@ "time": "360 m", "qualities": [ [ { "id": "HAMMER", "level": 2 } ] ], "components": [ [ [ "2x4", 12 ] ], [ [ "nail", 24 ], [ "bronze_nail", 24 ] ] ], - "pre_special": "check_empty_up_OK", + "pre_special": [ "check_empty", "check_up_OK" ], "post_terrain": "t_wood_stairs_up_half" }, { @@ -4955,7 +4955,7 @@ "time": "300 m", "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "DIG", "level": 2 } ] ], "components": [ [ [ "material_soil", 50 ] ], [ [ "stick", 12 ], [ "stick_long", 6 ], [ "2x4", 6 ] ], [ [ "rock", 20 ] ] ], - "pre_special": "check_ramp_low", + "pre_special": [ "check_empty", "check_stable", "check_up_OK", "check_nofloor_above" ], "post_terrain": "t_earth_ramp_up_low", "post_special": "done_ramp_low" }, @@ -4970,7 +4970,7 @@ "time": "300 m", "qualities": [ [ { "id": "HAMMER", "level": 2 } ], [ { "id": "DIG", "level": 2 } ] ], "components": [ [ [ "material_soil", 50 ] ], [ [ "stick", 10 ], [ "2x4", 8 ] ], [ [ "rock", 20 ] ] ], - "pre_special": "check_ramp_high", + "pre_special": [ "check_empty", "check_stable", "check_up_OK", "check_nofloor_above", "check_ramp_high" ], "post_terrain": "t_earth_ramp_up_high", "post_special": "done_ramp_high" }, @@ -4986,7 +4986,7 @@ "tools": [ [ [ "con_mix", 125 ] ] ], "qualities": [ [ { "id": "SMOOTH", "level": 2 } ] ], "components": [ [ [ "concrete", 5 ] ], [ [ "water", 5 ], [ "water_clean", 5 ] ] ], - "pre_special": "check_ramp_low", + "pre_special": [ "check_empty", "check_stable", "check_up_OK", "check_nofloor_above" ], "post_terrain": "t_ramp_up_low", "post_special": "done_ramp_low" }, @@ -5002,7 +5002,7 @@ "tools": [ [ [ "con_mix", 125 ] ] ], "qualities": [ [ { "id": "SMOOTH", "level": 2 } ] ], "components": [ [ [ "concrete", 5 ] ], [ [ "water", 5 ], [ "water_clean", 5 ] ] ], - "pre_special": "check_ramp_high", + "pre_special": [ "check_empty", "check_stable", "check_up_OK", "check_nofloor_above", "check_ramp_high" ], "post_terrain": "t_ramp_up_high", "post_special": "done_ramp_high" }, @@ -6961,7 +6961,7 @@ "on_display": true, "qualities": [ { "id": "DIG", "level": 1 } ], "pre_flags": [ "DIGGABLE", "FLAT" ], - "pre_special": "check_channel", + "pre_special": [ "check_empty", "check_channel" ], "post_terrain": "t_water_moving_sh", "byproducts": [ { "group": "digging_soil_loam_50L", "count": 5 } ], "activity_level": "EXTRA_EXERCISE", diff --git a/src/construction.cpp b/src/construction.cpp index 7c2e908489ee0..edbc1f67dd270 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -139,18 +139,16 @@ static bool check_support( const tripoint_bub_ms & ); // at least two orthogonal static bool check_support_below( const tripoint_bub_ms & ); // at least two orthogonal supports at the level below static bool check_stable( const tripoint_bub_ms & ); // tile below has a flag SUPPORTS_ROOF -static bool check_empty_stable( const tripoint_bub_ms - & ); // tile is empty, tile below has a flag SUPPORTS_ROOF static bool check_nofloor_above( const tripoint_bub_ms & ); // tile above has a flag NO_FLOOR static bool check_deconstruct( const tripoint_bub_ms & ); // either terrain or furniture must be deconstructible -static bool check_empty_up_OK( const tripoint_bub_ms & ); // tile is empty and below OVERMAP_HEIGHT static bool check_up_OK( const tripoint_bub_ms & ); // tile is below OVERMAP_HEIGHT static bool check_down_OK( const tripoint_bub_ms & ); // tile is above OVERMAP_DEPTH -static bool check_no_trap( const tripoint_bub_ms & ); -static bool check_ramp_low( const tripoint_bub_ms & ); -static bool check_ramp_high( const tripoint_bub_ms & ); -static bool check_no_wiring( const tripoint_bub_ms & ); +static bool check_no_trap( const tripoint_bub_ms & ); // tile doesn't contain any trap +static bool check_ramp_high( const tripoint_bub_ms + & ); // one of the adjacent tiles on the z-level above has a completed down ramp +static bool check_no_wiring( const tripoint_bub_ms + & ); // tile doesn't contain appliances/vehicle parts with WIRING flag like ap_wall_wiring // Special actions to be run post-terrain-mod static void done_nothing( const tripoint_bub_ms &, Character & ) {} @@ -931,15 +929,20 @@ bool can_construct( const construction &con, const tripoint_bub_ms &p ) const map &here = get_map(); const furn_id f = here.furn( p ); const ter_id t = here.ter( p ); - - if( !con.pre_special( p ) || // pre-function - !has_pre_terrain( con, p ) || // terrain type + if( con.pre_specials.size() > 1 ) { // pre-functions + for( const auto &special : con.pre_specials ) { + if( !special( p ) ) { + return false; + } + } + } else if( !con.pre_special( p ) ) { // pre-function + return false; + } + if( !has_pre_terrain( con, p ) || // terrain type !can_construct_furn_ter( con, f, t ) ) { // flags return false; } - - // make sure the construction would actually do something - if( !con.post_terrain.empty() ) { + if( !con.post_terrain.empty() ) { // make sure the construction would actually do something if( con.post_is_furniture ) { return f != furn_id( con.post_terrain ); } else { @@ -1172,7 +1175,13 @@ void complete_construction( Character *you ) // This comes after clearing the activity, in case the function interrupts // activities - built.post_special( terp, *you ); + if( built.post_specials.size() > 1 ) { // pre-functions + for( const auto &special : built.post_specials ) { + special( terp, *you ); + } + } else { + built.post_special( terp, *you ); + } // Players will not automatically resume backlog, other Characters will. if( you->is_avatar() && !you->backlog.empty() && you->backlog.front().id() == ACT_MULTIPLE_CONSTRUCTION ) { @@ -1183,12 +1192,13 @@ void complete_construction( Character *you ) bool construct::check_channel( const tripoint_bub_ms &p ) { - map &here = get_map(); - return check_empty( p ) && ( here.has_flag( ter_furn_flag::TFLAG_CURRENT, p + point_north ) || - here.has_flag( ter_furn_flag::TFLAG_CURRENT, p + point_south ) || - here.has_flag( ter_furn_flag::TFLAG_CURRENT, p + point_east ) || - here.has_flag( ter_furn_flag::TFLAG_CURRENT, p + point_west ) ); + for( const point &offset : four_adjacent_offsets ) { + if( here.has_flag( ter_furn_flag::TFLAG_CURRENT, p + offset ) ) { + return true; + } + } + return false; } bool construct::check_empty_lite( const tripoint_bub_ms &p ) @@ -1208,16 +1218,6 @@ bool construct::check_empty( const tripoint_bub_ms &p ) here.i_at( p ).empty() && !here.veh_at( p ) ); } -static std::array get_orthogonal_neighbors( const tripoint_bub_ms &p ) -{ - return {{ - p + point_north, - p + point_south, - p + point_west, - p + point_east - }}; -} - bool construct::check_support( const tripoint_bub_ms &p ) { map &here = get_map(); @@ -1226,8 +1226,8 @@ bool construct::check_support( const tripoint_bub_ms &p ) return false; } int num_supports = 0; - for( const tripoint_bub_ms &nb : get_orthogonal_neighbors( p ) ) { - if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, nb ) ) { + for( const point &offset : four_adjacent_offsets ) { + if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + offset ) ) { num_supports++; } } @@ -1258,8 +1258,8 @@ bool construct::check_support_below( const tripoint_bub_ms &p ) } // need two or more orthogonally adjacent supports at the Z level below int num_supports = 0; - for( const tripoint_bub_ms &nb : get_orthogonal_neighbors( p + tripoint_below ) ) { - if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, nb ) ) { + for( const point &offset : four_adjacent_offsets ) { + if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + offset + tripoint_below ) ) { num_supports++; } } @@ -1271,11 +1271,6 @@ bool construct::check_stable( const tripoint_bub_ms &p ) return get_map().has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + tripoint_below ); } -bool construct::check_empty_stable( const tripoint_bub_ms &p ) -{ - return check_empty( p ) && check_stable( p ); -} - bool construct::check_nofloor_above( const tripoint_bub_ms &p ) { return get_map().has_flag( ter_furn_flag::TFLAG_NO_FLOOR, p + tripoint_above ); @@ -1295,11 +1290,6 @@ bool construct::check_deconstruct( const tripoint_bub_ms &p ) return here.ter( p ).obj().deconstruct.can_do; } -bool construct::check_empty_up_OK( const tripoint_bub_ms &p ) -{ - return check_empty( p ) && check_up_OK( p ); -} - bool construct::check_up_OK( const tripoint_bub_ms & ) { // You're not going above +OVERMAP_HEIGHT. @@ -1319,22 +1309,15 @@ bool construct::check_no_trap( const tripoint_bub_ms &p ) bool construct::check_ramp_high( const tripoint_bub_ms &p ) { - if( check_empty_stable( p ) && check_up_OK( p ) && check_nofloor_above( p ) ) { - for( const point &car_d : four_cardinal_directions ) { - // check adjacent points on the z-level above for a completed down ramp - if( get_map().has_flag( ter_furn_flag::TFLAG_RAMP_DOWN, p + car_d + tripoint_above ) ) { - return true; - } + map &here = get_map(); + for( const point &offset : four_adjacent_offsets ) { + if( here.has_flag( ter_furn_flag::TFLAG_RAMP_DOWN, p + offset + tripoint_above ) ) { + return true; } } return false; } -bool construct::check_ramp_low( const tripoint_bub_ms &p ) -{ - return check_empty_stable( p ) && check_up_OK( p ) && check_nofloor_above( p ); -} - bool construct::check_no_wiring( const tripoint_bub_ms &p ) { const optional_vpart_position vp = get_map().veh_at( p ); @@ -1941,14 +1924,11 @@ void load_construction( const JsonObject &jo ) { "check_support", construct::check_support }, { "check_support_below", construct::check_support_below }, { "check_stable", construct::check_stable }, - { "check_empty_stable", construct::check_empty_stable }, { "check_nofloor_above", construct::check_nofloor_above }, { "check_deconstruct", construct::check_deconstruct }, - { "check_empty_up_OK", construct::check_empty_up_OK }, { "check_up_OK", construct::check_up_OK }, { "check_down_OK", construct::check_down_OK }, { "check_no_trap", construct::check_no_trap }, - { "check_ramp_low", construct::check_ramp_low }, { "check_ramp_high", construct::check_ramp_high }, { "check_no_wiring", construct::check_no_wiring } } @@ -1989,12 +1969,32 @@ void load_construction( const JsonObject &jo ) { "deconstruct", construct::failure_deconstruct }, } }; - - const std::string failure_fallback = jo.get_string( "pre_special", "" ) == "check_deconstruct" - ? "deconstruct" : "standard"; - - assign_or_debugmsg( con.pre_special, jo.get_string( "pre_special", "" ), pre_special_map ); - assign_or_debugmsg( con.post_special, jo.get_string( "post_special", "" ), post_special_map ); + std::string failure_fallback = "standard"; + if( jo.has_array( "pre_special" ) ) { + JsonArray jarr = jo.get_array( "pre_special" ); + for( std::string special : jarr ) { + if( special == "check_deconstruct" ) { + failure_fallback = "deconstruct"; + } + assign_or_debugmsg( con.pre_special, special, pre_special_map ); + con.pre_specials.push_back( *con.pre_special ); + } + } else { + const std::string special = jo.get_string( "pre_special", "" ); + if( special == "check_deconstruct" ) { + failure_fallback = "deconstruct"; + } + assign_or_debugmsg( con.pre_special, special, pre_special_map ); + } + if( jo.has_array( "post_special" ) ) { + JsonArray jarr = jo.get_array( "post_special" ); + for( std::string special : jarr ) { + assign_or_debugmsg( con.post_special, special, post_special_map ); + con.post_specials.push_back( *con.post_special ); + } + } else { + assign_or_debugmsg( con.post_special, jo.get_string( "post_special", "" ), post_special_map ); + } assign_or_debugmsg( con.do_turn_special, jo.get_string( "do_turn_special", "" ), do_turn_special_map ); assign_or_debugmsg( con.explain_failure, jo.get_string( "explain_failure", failure_fallback ), diff --git a/src/construction.h b/src/construction.h index 420ed64741466..1a55e139babf8 100644 --- a/src/construction.h +++ b/src/construction.h @@ -83,9 +83,12 @@ struct construction { // Custom constructibility check bool ( *pre_special )( const tripoint_bub_ms & ); + std::vector pre_specials; + // Custom while constructing effects + void ( *do_turn_special )( const tripoint_bub_ms &, Character & ); // Custom after-effects void ( *post_special )( const tripoint_bub_ms &, Character & ); - void ( *do_turn_special )( const tripoint_bub_ms &, Character & ); + std::vector post_specials; // Custom error message display void ( *explain_failure )( const tripoint_bub_ms & ); // Whether it's furniture or terrain