CleverRaven / Cataclysm-DDA

Cataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world.
http://cataclysmdda.org
Other
10.62k stars 4.17k forks source link

Introduce scaffolding #73207

Closed PatrikLundell closed 6 months ago

PatrikLundell commented 6 months ago

Is your feature request related to a problem? Please describe.

I'd like to have scaffolding that allows me to get to a higher Z level in order to interact with whatever is in adjacent tile, in particular in order to perform construction activities on those tiles.

Solution you would like.

  1. The introduction of a scaffolding furniture that can be deployed and then climbed to stand on the Z level straight above (i.e. not just reach up and be able to climb to the side, as provided by step ladders). That, unfortunately, would mean multi tile furniture, so it's probably not possible in the near term. 2a. The introduction of easily constructed and removed scaffolding terrain that also provide scaffolding on the Z level above. If you had this "terrain" you could reach any height if you had two sets of them, where you could stand on one to extend the other one upward. Ideally you'd be able to construct it standing on the same tile as well. 2b. The scaffolding terrain covered a single Z level, but if it had the property that it could be constructed from below when the character stands on scaffolding terrain we'd achieve the same thing, possibly easier.

Describe alternatives you have considered.

It would work to change the construction logic to allow construction on adjacent tiles at the Z level above either if the character doing construction has a stepladder (of some sort), or a stepladder has been placed at the tile construction is performed from. In both cases the code determine legal character construction locations would have to recognize the stepladder as a suitable tool/furniture. It would also work if anything that can be climbed to provide access to the Z level above would work (such as e.g. furniture used to get out of a basement with a destroyed staircase).

Additional context

Note that the end goal is to disconnect roofs from the rooms below and the magic that plonks a roof onto terrain supporting it most of the time. The scaffolding would then provide a means for players to place roofs (of their choosing) on top of walls when constructing buildings. Also note that this means scaffolding construction mustn't rely on roof adding magic, as the aim is to remove it and replace it with explicit placement of roofs.

IdleSol commented 6 months ago

I don't know what I'm doing. Just along the lines of done_wood_stairs.

Add to src/construction.cpp

...
static const ter_str_id ter_t_ladder_down( "t_ladder_down" );
...
static void done_ladder( const tripoint_bub_ms &, Character & );
...
void construct::done_ladder( const tripoint_bub_ms &p, Character &/*who*/ )
{
    const tripoint_bub_ms top = p + tripoint_above;
    get_map().ter_set( top, ter_t_ladder_down );
}

https://github.com/CleverRaven/Cataclysm-DDA/blob/a60d305954dc305990b83df1c521790bc245be8f/src/construction.cpp#L1962-L1968

            { "done_ladder", construct::done_ladder },

add to data/json/construction_group.json

 {
    "type": "construction_group",
    "id": "build_ladder",
    "name": "test build ladder"
  },

add to data/json/construction.json

  {
    "type": "construction",
    "id": "constr_ladder_up",
    "group": "build_ladder",
    "category": "BULK",
    "difficulty": 0,
    "time": "5 m",
    "components": [ [ [ "pipe", 8 ] ] ],
    "dark_craftable": true,
    "pre_special": [ "check_empty", "check_up_OK" ],
    "post_terrain": "t_ladder_up",
    "post_special": "done_ladder"
    "activity_level": "LIGHT_EXERCISE"
  },
  {
    "type": "construction",
    "id": "constr_ladder_up_down",
    "group": "build_ladder",
    "category": "BULK",
    "difficulty": 0,
    "time": "15 m",
    "components": [ [ [ "pipe", 8 ] ] ],
    "dark_craftable": true,
    "pre_special": [ "check_up_OK" ],
    "pre_terrain": "t_ladder_down",
    "post_terrain": "t_ladder_up_down",
    "post_special": "done_ladder"
    "activity_level": "LIGHT_EXERCISE"
  },

Might work as a basis

UPD. Add to src/construction.cpp

static const ter_str_id ter_t_ladder_down( "t_ladder_down" );
PatrikLundell commented 6 months ago

Ah, so there's the possibility to add code to post_special! Yes, that's probably better than the tangent I'm currently on (adding a new "post_terrain_above" field). The issue I see with a post_special is that it would result in a single, effectively hard coded, set of terrain where you might want to have a few different options based on your resources (e.g. bamboo/steel pipes/planks).

However, I also have the issue of how to dismantle the top level from below.

IdleSol commented 6 months ago

Similarly. Create a "nothing" and run "post_special" that will remove the top-level

  {
    "type": "construction",
    "id": "deconstr_ladder_up_down",
...
    "pre_terrain": "ladder_up_down",
    "post_terrain": "t_ladder_down",
    "post_special": "remove_ladder"
  },
void construct::remove_ladder( const tripoint_bub_ms &p, Character &/*who*/ )
{
    const tripoint_bub_ms top = p + tripoint_above;
    get_map().ter_set( top, ter_t_air );
}

Air, open space, or whatever this tile is called?

PatrikLundell commented 6 months ago

Won't quite work, as we'd have to verify that the tile above is a down scaffolding (not an up/down one, or empty space). It's called "t_open_air", by the way).

I'm considering the introduction of a pair of new pre/post_specials that would look at the tile above and match the name of the tile against the base name of the tile below (the one nominally selected for construction) plus a hard coded "down" suffix. Conversion of the nominally targeted terrain from up_down to down can be handled with post_terrain, as the construction of each variant would have to be separate anyway (different materials, etc.).

IdleSol commented 6 months ago

The issue I see with a post_special is that it would result in a single, effectively hard coded, set of terrain where you might want to have a few different options based on your resources (e.g. bamboo/steel pipes/planks).

I'm not quite sure what you're talking about.

For its material, there should be its own entry in the constructs.

But if we want one and the same construction to be created from different materials. What prevents us from checking the materials used in the same function? If-then.

But there is another problem here, what do you get if you parse deconstructing it? Do a memorization of what it is assembled from? (Perhaps this is already implemented?)

as we'd have to verify that the tile above is a down scaffolding

Or let it all fall on the player's head. This is true if he starts dismantling from the bottom level.

PatrikLundell commented 6 months ago

The problem with materials is that C:DDA doesn't keep track of what things are made of, and deconstruction has to be hard coded to provide a specific set of materials. It's been seen in the past where you were able to make e.g. makeshift heating elements to construct e.g. a kettle and then deconstruct the kettle to get regular heating elements. Thus, in order to ensure deconstruction products are at least somewhat consistent with the construction ones you'll have to define different items (copper pots and regular pots is another example where you want them to deconstruct into different materials even though the items are functionally equivalent).

The game mostly prevents the player from doing extremely stupid things, at least without asking.

Edit (edited again): After finally getting things to compile and parse JSON, I've got a few issues:

Procyonae commented 6 months ago

66785, my failed past attempt to add placeable ladder furniture is probably relevant here

Procyonae commented 6 months ago

The teleport thing is a "temporary" piece of code to deal with misaligned stairs primarily found in old labs though there are a few other occurrences.

Procyonae commented 6 months ago

You can only have a single pre_special value, but I want to check multiple things, and the multi checking value specified by the documentation doesn't actually exist... Considering whether to go with weaker checks or add new specific ones.

I added the ability to do that in #71115 what can't you get to work?

PatrikLundell commented 6 months ago

I've skimmed through the PR. I think I'll avoid most of the problem by making it terrain (although I still have to suffer the ugly "t_dirt" when removing it). The reason I failed to get multi checking to work was that I guessed at the wrong syntaxes. I'll expect to be able to deal with that tomorrow, thanks to your help.

Procyonae commented 6 months ago

Yeah it looks like I forgot to add documentation for it >_<

PatrikLundell commented 6 months ago

I'll make a stab at it. It isn't the only thing missing (like the whole post_special section).

Procyonae commented 6 months ago

Ye that whole section could do with some work put into it, one line for each field isn't really enough

IdleSol commented 6 months ago

The concept of sliding stairs or cranes.

  {
    "type": "construction",
    "id": "constr_scaffolding_pipe_up_1",
    "group": "test_build_scaffolding",
...
    "pre_special": [ "check_empty", "check_single_support", "check_up_OK", "check_nofloor_above" ],
    "post_special": "add_roof",
    "post_terrain": "t_scaffolding_pipe_up_1"
  },

  {
    "type": "construction",
    "id": "constr_scaffolding_pipe_up_2",
    "group": "test_build_scaffolding",
...
    "pre_terrain": "t_scaffolding_pipe_up_1",
    "post_special": "test_add_roof",
    "post_terrain": "t_scaffolding_pipe_up_2"
  },

  {
    "type": "construction",
    "id": "constr_scaffolding_pipe_up_3",
    "group": "test_build_scaffolding",
...
    "pre_terrain": "t_scaffolding_pipe_up_2",
    "post_special": "test_add_roof",
    "post_terrain": "t_scaffolding_pipe_up_3"
  },

New test_add_roof function.

  1. The function takes the number from the end of id: t_scaffolding_pipe_up_N
  2. Creates a roof at z=N
  3. Creates up/down on z=N-1 & z!=0

Construction all the time starts from level z=0. You don't need a second scaffold to build higher. And everything is disassembled from the same level, just in reverse order. There is a height limit, how many levels are defined, so many will be built. For example, 5. But if you build this structure on a finished roof, you can go up to 6.

Problems: you have to check if there is something on all levels above.

Diggy diggy hole

What if you don't add the Z-axis coordinate? But subtract it from the coordinate. What if it's not Z coordinates, but X coordinates, for example?

Sounds like safe construction of underground bases.

PatrikLundell commented 6 months ago

Well, it would be possible, given some code support, to get stuff to extend upwards, downwards, or sideways, but now much of it would make sense to be available to a player? You'd really need use cases for these kind of things, I don't really see a case for underground bases, as you can use the existing mining functionality to expand sideways as well as mining/digging stairs.

IdleSol commented 6 months ago

New concept.

The "post_special" function has a completion timer. Or something similar. The point is that the player starts construction, after which he can be free. The construction ends by itself, after a certain time.

Automation of construction. Or at least tunnel digging.

You'd really need use cases for these kind of things

I'll divide it into two parts.

  1. Building the vertical shaft down.

If you use the suggested method.

What if it requires special transportation? Or a special item that will turn into a level 0 construct. A kind of automatic drill.

And if it's automated? What would you like more, to spend weeks drilling the ground or to spend the same time looking for someone who will do it for you?

  1. Building a horizontal mine.

Same problems with mined materials and followers. But you can also get a ceiling collapse, which will ruin all the work. I failed to build a base 3 cells wide, the ceiling was falling. (It was quite a long time ago, maybe something has changed).

With the proposed method, there will definitely be no collapse. You can build underground bases in a clear field and any width (24x24). But you still have to build a downhill slope.

Similarly, the possibility of adding special items for this method of construction. The possibility of combining digging the ground with concreting the floor and ceiling. And to receive finished concrete tiles.

Automation. Who should be killed for automation?

PatrikLundell commented 6 months ago

You can't put a timer in a function. It has to be called and then return promptly so the game can continue on. If you want timed activities you'll have to go through the normal process of performing activities one tick at a time.

It makes sense companions can't help you with digging while there is only room for one person. The only way to share the burden is to take shifts.

Performing tasks on the tile you're standing on might have some merit. That, however, would require modification of the code that determines where legal nearby tiles are (wherever that code is). It would also have to be guarded such that most activities can't be performed in place, as it doesn't make sense to stand where you're e.g. building a wall.

IdleSol commented 6 months ago

You can't put a timer in a function.

Is it possible to add a timer for the tiles? After a certain amount of time, it changes to something else. And then the player builds a temporary structure that turns into something else, after some time. Or is it simpler and use eoc?

Performing tasks on the tile you're standing on might have some merit

Why stand on the same tile?

PatrikLundell commented 6 months ago

No, the terrain data is extremely limited, with a fair bit of useful information not present. You can place fields on tiles and fields can decay and do something when timing out. I don't know if you can tie an EoC to that.

Stand on the same tile: You just brought it up: digging/building stairs straight down/up, but also erecting scaffolding from the top of scaffolding.

IdleSol commented 6 months ago

I see, I didn't make myself clear enough. I'll try again.

Step 1 Step 2 Step 3 Step 4 Step 5 Step 6
z=5 down
z=4 down up_down
z=3 down up_down up_down
z=2 down up_down up_down up_down
z=1 down up_down up_down up_down up_down
z=0 @ @ up_1 @ up_2 @ up_3 @ up_4 @ up_5

Step 1. The character is at level z=0. He builds

    "id": "constr_scaffolding_pipe_up_1",
    "pre_special": [ "check_empty", "check_single_support", "check_up_OK", "check_nofloor_above" ],
    "post_special": "add_roof",
    "post_terrain": "t_scaffolding_pipe_up_1"

Result:

Step 2. The character is at level z=0. He builds

    "id": "constr_scaffolding_pipe_up_2",

    "pre_terrain": "t_scaffolding_pipe_up_1",
    "post_special": "test_add_roof",
    "post_terrain": "t_scaffolding_pipe_up_2"

Result:

What does test_add_roof do?

  1. Takes the id of the construction (t_scaffolding_pipe_up_1)
  2. Looking at the number at the end (1)
  3. Takes the coordinates of the construction (z=0) and adds the number from step 2 (1)
  4. According to the calculated coordinates (z=0+1=1) set t_scaffolding_pipe_up_down
  5. Increases z coordinate level by 1 (z=1+1=2). And completes the construct by adding t_scaffolding_pipe_down

Step 3. The character is at level z=0. He builds

    "id": "constr_scaffolding_pipe_up_3",

    "pre_terrain": "t_scaffolding_pipe_up_2",
    "post_special": "test_add_roof",
    "post_terrain": "t_scaffolding_pipe_up_3"

Result:

What does test_add_roof do?

  1. Takes the id of the construction (t_scaffolding_pipe_up_2)
  2. Looking at the number at the end (2)
  3. Takes the coordinates of the construction (z=0) and adds the number from step 2 (2)
  4. According to the calculated coordinates (z=0+2=2) set t_scaffolding_pipe_up_down
  5. Increases z coordinate level by 1 (z=2+1=3). And completes the construct by adding t_scaffolding_pipe_down

And so on. Similarly, you can move underground. Character, always at z=0. Only from this level you can build. He stands on any tile, except the tile on which the construction is built.

Step 1 Step 2 Step 3 Step 4 Step 5 Step 6
z=0 @ @ down_1 @ down_2 @ down_3 @ down_4 @ down_5
z=-1 up up_down up_down up_down up_down
z=-2 up up_down up_down up_down
z=-3 up up_down up_down
z=-4 up up_down
z=-5 up
PatrikLundell commented 6 months ago

It would probably be technically possible to implement the thing described, but I don't think it would pass the reality check test of those who approve PRs. The thing is that you'd have to explain why a character standing on one level can build stuff several Z levels away (and I don't think convenience would cut it). Also, it suffers from the issue that you can ONLY change things from the start level: there's no way to change things from the level where the work would actually take place, which is weird.

IdleSol commented 6 months ago

Because it's a billet for sliding structures. Or mechanisms.

The character stands in one place because he's at the remote control. Or because the game is limited and doesn't allow you to build on tiles with the character.

GuardianDll commented 6 months ago

resolved by #73232