diff --git a/data/json/construction.json b/data/json/construction.json index 52f2fcc95ec4c..2ab241d0c9d79 100644 --- a/data/json/construction.json +++ b/data/json/construction.json @@ -9126,5 +9126,88 @@ "pre_special": "check_empty", "post_terrain": "f_piano", "activity_level": "LIGHT_EXERCISE" + }, + { + "type": "construction", + "id": "constr_scaffolding_pipe_up", + "group": "build_scaffolding", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "30 m", + "qualities": [ [ { "id": "WRENCH", "level": 1 } ] ], + "components": [ + [ [ "pipe", 46 ] ], + [ [ "pipe_fittings", 55 ] ], + [ [ "2x4", 4 ], [ "wood_panel", 1 ] ], + [ [ "stick", 2 ] ], + [ [ "rope_natural", 2, "LIST" ] ] + ], + "pre_note": "Constructs scaffolding on the tile and provides a platform on the Z level above.", + "pre_special": [ "check_empty", "check_single_support", "check_up_OK", "check_nofloor_above" ], + "post_special": "add_roof", + "post_terrain": "t_scaffolding_pipe_up" + }, + { + "type": "construction", + "id": "constr_scaffolding_pipe_down", + "group": "build_scaffolding", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "10 m", + "qualities": [ [ { "id": "WRENCH", "level": 1 } ] ], + "components": [ + [ [ "pipe", 46 ] ], + [ [ "pipe_fittings", 55 ] ], + [ [ "2x4", 4 ], [ "wood_panel", 1 ] ], + [ [ "stick", 2 ] ], + [ [ "rope_natural", 2, "LIST" ] ] + ], + "pre_note": "Builds another scaffolding level.", + "pre_terrain": "t_scaffolding_pipe_down", + "pre_special": [ "check_up_OK", "check_nofloor_above" ], + "post_terrain": "t_scaffolding_pipe_updown", + "post_special": "add_matching_down_above" + }, + { + "type": "construction", + "id": "remove_scaffolding_pipe_up", + "group": "remove_scaffolding", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "30 m", + "qualities": [ [ { "id": "WRENCH", "level": 1 } ] ], + "pre_note": "Removes scaffolding.", + "pre_terrain": "t_scaffolding_pipe_up", + "pre_special": "check_matching_down_above", + "post_special": "remove_above", + "post_terrain": "t_dirt", + "byproducts": [ + { "item": "pipe", "count": 46 }, + { "item": "pipe_fittings", "count": 55 }, + { "item": "2x4", "count": 4 }, + { "item": "stick", "count": 2 }, + { "item": "rope_30", "count": 2 } + ] + }, + { + "type": "construction", + "id": "remove_scaffolding_pipe_down_above_updown", + "group": "remove_scaffolding", + "category": "CONSTRUCT", + "required_skills": [ [ "fabrication", 3 ] ], + "time": "30 m", + "qualities": [ [ { "id": "WRENCH", "level": 1 } ] ], + "pre_note": "Removes down scaffolding from directly above the construction tile.", + "pre_terrain": "t_scaffolding_pipe_updown", + "pre_special": "check_matching_down_above", + "post_special": "remove_above", + "post_terrain": "t_scaffolding_pipe_down", + "byproducts": [ + { "item": "pipe", "count": 46 }, + { "item": "pipe_fittings", "count": 55 }, + { "item": "2x4", "count": 4 }, + { "item": "stick", "count": 2 }, + { "item": "rope_30", "count": 2 } + ] } ] diff --git a/data/json/construction_group.json b/data/json/construction_group.json index e6759c63c87b0..761c4f36b7296 100644 --- a/data/json/construction_group.json +++ b/data/json/construction_group.json @@ -1978,5 +1978,15 @@ "type": "construction_group", "id": "place_piano", "name": "Place Piano" + }, + { + "type": "construction_group", + "id": "build_scaffolding", + "name": "Place Scaffolding" + }, + { + "type": "construction_group", + "id": "remove_scaffolding", + "name": "Remove Scaffolding" } ] diff --git a/data/json/furniture_and_terrain/terrain-zlevel-transitions.json b/data/json/furniture_and_terrain/terrain-zlevel-transitions.json index f1532c92a95fc..11696f272dacc 100644 --- a/data/json/furniture_and_terrain/terrain-zlevel-transitions.json +++ b/data/json/furniture_and_terrain/terrain-zlevel-transitions.json @@ -222,6 +222,68 @@ "items": [ { "item": "steel_chunk", "count": [ 1, 6 ] }, { "item": "scrap", "count": [ 3, 12 ] } ] } }, + { + "type": "terrain", + "id": "t_scaffolding_pipe_up", + "name": "scaffolding up", + "description": "Scaffolding leading up.", + "symbol": "<", + "looks_like": "t_ladder_up", + "color": "dark_gray", + "move_cost": 2, + "roof": "t_scaffolding_pipe_down", + "flags": [ "TRANSPARENT", "GOES_UP", "PLACE_ITEM", "DIFFICULT_Z", "SUPPORTS_ROOF", "SINGLE_SUPPORT" ], + "bash": { + "str_min": 20, + "str_max": 150, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_dirt", + "items": [ + { "item": "pipe", "count": [ 10, 46 ] }, + { "item": "pipe_fittings", "count": [ 10, 55 ] }, + { "item": "2x4", "count": [ 1, 4 ] }, + { "item": "stick", "count": [ 0, 2 ] }, + { "item": "rope_30", "count": [ 0, 2 ] } + ] + } + }, + { + "type": "terrain", + "id": "t_scaffolding_pipe_down", + "name": "scaffolding down", + "description": "Scaffolding leading down.", + "symbol": ">", + "looks_like": "t_ladder_down", + "color": "dark_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "GOES_DOWN", "PLACE_ITEM", "DIFFICULT_Z", "SINGLE_SUPPORT" ], + "bash": { "str_min": 20, "str_max": 150, "sound": "metal screeching!", "sound_fail": "clang!", "ter_set": "t_open_air" } + }, + { + "type": "terrain", + "id": "t_scaffolding_pipe_updown", + "name": "scaffolding up/down", + "description": "Scaffolding leading up and down.", + "symbol": "H", + "color": "dark_gray", + "move_cost": 2, + "flags": [ "TRANSPARENT", "GOES_UP", "GOES_DOWN", "PLACE_ITEM", "DIFFICULT_Z", "SUPPORTS_ROOF", "SINGLE_SUPPORT" ], + "bash": { + "str_min": 20, + "str_max": 150, + "sound": "metal screeching!", + "sound_fail": "clang!", + "ter_set": "t_scaffolding_pipe_down", + "items": [ + { "item": "pipe", "count": [ 10, 46 ] }, + { "item": "pipe_fittings", "count": [ 10, 55 ] }, + { "item": "2x4", "count": [ 1, 4 ] }, + { "item": "stick", "count": [ 0, 2 ] }, + { "item": "rope_30", "count": [ 0, 2 ] } + ] + } + }, { "type": "terrain", "id": "t_ramp_down_high", diff --git a/doc/JSON_INFO.md b/doc/JSON_INFO.md index e62d0b220d56a..fe945e4a7f85b 100644 --- a/doc/JSON_INFO.md +++ b/doc/JSON_INFO.md @@ -2447,10 +2447,11 @@ request](https://github.com/CleverRaven/Cataclysm-DDA/pull/36657) and the "vehicle_start": true, // Hardcoded check for construction recipe, that result into vehicle frame; Can be used only with `done_vehicle` "time": "30 m", // Time required to complete construction. Integers will be read as minutes or a time string can be used. "components": [ [ [ "spear_wood", 4 ], [ "pointy_stick", 4 ] ] ], // Items used in construction -"pre_special": "check_empty", // Required something that isn't terrain +"pre_special": [ "check_empty", "check_up_OK" ], // Required something that isn't terrain. The syntax also allows for a square bracket enclosed list of specials which all have to be fulfilled "pre_terrain": "t_pit", // Alternative to pre_special; Required terrain to build on "pre_flags": [ "WALL", { "flag": "DIGGABLE", "force_terrain": true } ], // Flags beginning furniture/terrain must have. force_ter forces the flag to apply to the underlying terrain "post_terrain": "t_pit_spiked", // Terrain type after construction is complete +"post_special": "done_mine_upstairs", // Required to do something beyond setting the post terrain. The syntax also allows for a square bracket enclosed list of specials which all have to be fulfilled "pre_note": "Build a spikes on a diggable terrain", // Create an annotation to this recipe "dark_craftable": true, // If true, you can construct it with lack of light "byproducts": [ { "item": "material_soil", "count": [ 2, 5 ] } } ], // Items, that would be left after construction @@ -2463,19 +2464,45 @@ request](https://github.com/CleverRaven/Cataclysm-DDA/pull/36657) and the | `check_channel` | Must be empty and have a current in at least one orthogonal tile | `check_empty` | Tile is empty (no furniture, trap, item, or vehicle) and flat terrain | `check_empty_lite` | Tile is empty (no furniture, trap, item, or vehicle) -| `check_support` | Must have at least two solid walls/obstructions nearby on orthogonals (non-diagonal directions only) to support the tile -| `check_support_below` | Must have at least two solid walls/obstructions at the Z level below on orthogonals (non-diagonal directions only) to support the tile and be empty lite but with a ledge trap acceptable, as well as open air +| `check_support` | Must have at least two solid walls/obstructions nearby on orthogonals (non-diagonal directions only) or solid support directly below to support the tile +| `check_support_below` | Must have at least two solid walls/obstructions at the Z level below on orthogonals (non-diagonal directions only) or solid support directly below to support the tile and be empty lite but with a ledge trap acceptable, as well as open air +| `check_single_support` | Must have solid support directly below to support the tile | `check_stable` | Tile on level below has a flag `SUPPORTS_ROOF` | `check_empty_stable` | Tile is empty and stable | `check_nofloor_above` | Tile on level above has a flag `NO_FLOOR` | `check_deconstruction` | The furniture (or tile, if no furniture) in the target tile must have a "deconstruct" entry -| `check_empty_up_OK` | Tile is empty and is below the maximum possible elevation (can build up here) | `check_up_OK` | Tile is below the maximum possible elevation (can build up here) | `check_down_OK` | Tile is above the lowest possible elevation (can dig down here) | `check_no_trap` | There is no trap object in this tile | `check_ramp_low` | Both this and the next level above can be built up one additional Z level | `check_ramp_high` | There is a complete downramp on the next higher level, and both this and next level above can be built up one additional Z level | `check_no_wiring` | The tile must either be free of a vehicle, or at least a vehicle that doesn't have the WIRING flag +| `check_matching_down_above`| The tile directly above must have the same base identifier but with a suffix of 'down' + +| post_special | Description +|--- |--- +| `done_trunk_plank` | Generate logs and then planks here (under the assumption the tile was a trunk or stump) +| `done_grave` | Finish grave digging by performing burial activities +| `done_vehicle` | Create a new vehicle and name it +| `done_appliance` | Finish the placement of a partially placed appliance +| `done_wiring` | Place a wiring "appliance" at the location +| `done_deconstruct` | Finish deconstruction of furniture or, if not present, terrain +| `done_dig_grave` | Finish digging up a grave and find what's inside of it +| `done_dig_grave_nospawn`| Finish digging up a grave and retrieve a coffin (which is not an option above) +| `done_dig_stair` | Finish diggins stairs downwards (with handling of what's beneath and how to get up) +| `done_mine_downstair` | Same as the previous one, but mining rather than digging +| `done_mine_upstair` | Finish mining stairs from below +| `done_wood_stairs` | Finish building stairs from below +| `done_window_curtains` | Finish boarding up window and get materials from curtains +| `done_extract_maybe_revert_to_dirt`| Finish sand/clay extraction, which may exhaust the resource +| `done_mark_firewood` | Sets a firewood source trap at the location +| `done_mark_practice_target`| Sets a target practice trap at the location +| `done_ramp_low` | Sets a t_ramp_down_low at the tile above the target +| `done_ramp_high` | Sets a t_ramp_down_high at the tile above the target +| `done_matching_down_above`| The terrain on the Z level above is set to the corresponding terrain at this level, but with the "down" suffix instead +| `remove_above` | Remove the terrain at the Z level above and replace it with t_open_air +| `add_roof` | Add the roof specified for the terrain at the site to the tile above + ### Scent_types diff --git a/src/construction.cpp b/src/construction.cpp index 237a29740bcfe..75ad49316aac1 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -157,9 +157,12 @@ static bool check_nothing( const tripoint_bub_ms & ) static bool check_channel( const tripoint_bub_ms & ); // tile has adjacent flowing water static bool check_empty_lite( const tripoint_bub_ms & ); static bool check_empty( const tripoint_bub_ms & ); // tile is empty -static bool check_support( const tripoint_bub_ms & ); // at least two orthogonal supports +static bool check_support( const tripoint_bub_ms + & ); // at least two orthogonal supports or from below static bool check_support_below( const tripoint_bub_ms - & ); // at least two orthogonal supports at the level below + & ); // at least two orthogonal supports at the level below or from below +static bool check_single_support( const tripoint_bub_ms + &p ); // Only support from directly below matters static bool check_stable( const tripoint_bub_ms & ); // 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 @@ -171,6 +174,8 @@ 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 +static bool check_matching_down_above( const tripoint_bub_ms + &p ); // tile above has the same base name but with the "down suffix // Special actions to be run post-terrain-mod static void done_nothing( const tripoint_bub_ms &, Character & ) {} @@ -193,6 +198,9 @@ static void done_mark_firewood( const tripoint_bub_ms &, Character & ); static void done_mark_practice_target( const tripoint_bub_ms &, Character & ); static void done_ramp_low( const tripoint_bub_ms &, Character & ); static void done_ramp_high( const tripoint_bub_ms &, Character & ); +static void add_matching_down_above( const tripoint_bub_ms &p, Character & ); +static void remove_above( const tripoint_bub_ms &p, Character & ); +static void add_roof( const tripoint_bub_ms &p, Character & ); static void do_turn_shovel( const tripoint_bub_ms &, Character & ); static void do_turn_exhume( const tripoint_bub_ms &, Character & ); @@ -1251,10 +1259,17 @@ bool construct::check_support( const tripoint_bub_ms &p ) } int num_supports = 0; for( const point &offset : four_adjacent_offsets ) { - if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + offset ) ) { + if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + offset ) && + !here.has_flag( ter_furn_flag::TFLAG_SINGLE_SUPPORT, p + offset ) ) { num_supports++; } } + // We want to find "walls" below (including windows and doors), but not open rooms and the like. + if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + tripoint_below ) && + ( here.has_flag( ter_furn_flag::TFLAG_WALL, p + tripoint_below ) || + here.has_flag( ter_furn_flag::TFLAG_CONNECT_WITH_WALL, p + tripoint_below ) ) ) { + num_supports += 2; + } return num_supports >= 2; } @@ -1283,13 +1298,29 @@ 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 point &offset : four_adjacent_offsets ) { - if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + offset + tripoint_below ) ) { + if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + offset + tripoint_below ) && + !here.has_flag( ter_furn_flag::TFLAG_SINGLE_SUPPORT, p + offset + tripoint_below ) ) { num_supports++; } } + // We want to find "walls" below (including windows and doors), but not open rooms and the like. + if( here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + tripoint_below ) && + ( here.has_flag( ter_furn_flag::TFLAG_WALL, p + tripoint_below ) || + here.has_flag( ter_furn_flag::TFLAG_CONNECT_WITH_WALL, p + tripoint_below ) ) ) { + num_supports += 2; + } return num_supports >= 2; } +bool construct::check_single_support( const tripoint_bub_ms &p ) +{ + map &here = get_map(); + if( here.impassable( p ) ) { + return false; + } + return here.has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + tripoint_below ); +} + bool construct::check_stable( const tripoint_bub_ms &p ) { return get_map().has_flag( ter_furn_flag::TFLAG_SUPPORTS_ROOF, p + tripoint_below ); @@ -1353,6 +1384,16 @@ bool construct::check_no_wiring( const tripoint_bub_ms &p ) return !veh_target.has_tag( flag_WIRING ); } +bool construct::check_matching_down_above( const tripoint_bub_ms &p ) +{ + map &here = get_map(); + const std::string ter_here = here.ter( p ).id().str(); + const std::string ter_above = here.ter( p + tripoint_above ).id().str(); + const size_t separation = ter_here.find_last_of( '_' ); + return separation > 0 && + ter_here.substr( 0, separation + 1 ) + "down" == ter_above; +} + void construct::done_trunk_plank( const tripoint_bub_ms &/*p*/, Character &/*who*/ ) { int num_logs = rng( 2, 3 ); @@ -1776,6 +1817,34 @@ void construct::done_ramp_high( const tripoint_bub_ms &p, Character &/*who*/ ) get_map().ter_set( top, ter_t_ramp_down_high ); } +void construct::add_matching_down_above( const tripoint_bub_ms &p, Character &/*who*/ ) +{ + map &here = get_map(); + const std::string ter_here = here.ter( p ).id().str(); + const std::string ter_above = here.ter( p + tripoint_above ).id().str(); + const size_t separation = ter_here.find_last_of( '_' ); + if( separation > 0 ) { + here.ter_set( p + tripoint_above, ter_id( ter_here.substr( 0, separation + 1 ) + "down" ) ); + } +} + +void construct::remove_above( const tripoint_bub_ms &p, Character &/*who*/ ) +{ + map &here = get_map(); + here.ter_set( p + tripoint_above, ter_t_open_air ); +} + +void construct::add_roof( const tripoint_bub_ms &p, Character &/*who*/ ) +{ + map &here = get_map(); + ter_id roof = here.ter( p ).obj().roof; + if( !roof ) { + debugmsg( "add_roof post_ter called on terrain lacking roof definition, %s.", + here.ter( p ).id().c_str() ); + } + here.ter_set( p + tripoint_above, roof ); +} + void construct::do_turn_shovel( const tripoint_bub_ms &p, Character &who ) { // TODO: fix point types @@ -1949,6 +2018,7 @@ void load_construction( const JsonObject &jo ) { "check_empty_lite", construct::check_empty_lite }, { "check_support", construct::check_support }, { "check_support_below", construct::check_support_below }, + { "check_single_support", construct::check_single_support }, { "check_stable", construct::check_stable }, { "check_nofloor_above", construct::check_nofloor_above }, { "check_deconstruct", construct::check_deconstruct }, @@ -1956,7 +2026,8 @@ void load_construction( const JsonObject &jo ) { "check_down_OK", construct::check_down_OK }, { "check_no_trap", construct::check_no_trap }, { "check_ramp_high", construct::check_ramp_high }, - { "check_no_wiring", construct::check_no_wiring } + { "check_no_wiring", construct::check_no_wiring }, + { "check_matching_down_above", construct::check_matching_down_above } } }; static const std::map @@ -1979,7 +2050,11 @@ void load_construction( const JsonObject &jo ) { "done_mark_firewood", construct::done_mark_firewood }, { "done_mark_practice_target", construct::done_mark_practice_target }, { "done_ramp_low", construct::done_ramp_low }, - { "done_ramp_high", construct::done_ramp_high } + { "done_ramp_high", construct::done_ramp_high }, + { "add_matching_down_above", construct::add_matching_down_above }, + { "remove_above", construct::remove_above }, + { "add_roof", construct::add_roof } + } }; static const std::map