Cataclysm-dda: A vehicle with a coil of frames surrounding it is invincible.

Created on 12 Mar 2018  路  23Comments  路  Source: CleverRaven/Cataclysm-DDA

Expected behavior

Smashing vehicles into things damages and eventually destroys them.

Actual behavior

A vehicle with a coil of frames surrounding it is invincible.

Steps to reproduce behavior

https://www.reddit.com/r/cataclysmdda/comments/830vz0/invincible_vehicle_and_how_does_it_work

Explanation

Vehicles in cdda cannot be split into two parts, which means if two parts of a vehicle is connected only by a frame, this frame will be unbreakable. Only one end of the strand of frames around this car is connected to it. If any frame in it breaks except the free end of it (the white v), the strand is split from the car, which is not allowed to happen. This makes all frames in it except the free end unbreakable. You can crash the largest car down to scrap with it without even getting a scratch on it.

<Bug> <Exploit> Balance Good First Issue Vehicles

Most helpful comment

As much hassle as it is to engineer this scenario though...honestly I'd see a general system for allowing vehicles to split/merge to be more useful in general, with fixing this as a side effect.

All 23 comments

Heh. Clever trick.

What would the preferred fix for this be? I considered the idea generating a new vehicle composed of the attached parts, but that could be rather complex and may cause issues. The obvious, simple option would be to just detach everything and break it down to parts(and apply some damage to them), but that would create an unrealistic explosion of parts and lead to salvaging exploits.

What about restricting the creation of spaghetti-framed vehicles?

@Wulfe813 "The obvious, simple option would be to just detach everything and break it down to parts(and apply some damage to them), but that would create an unrealistic explosion of parts and lead to salvaging exploits."

I guess people could start disassembling large vehicles by first carving a spiral of disassembly into them and then breaking it in half, causing half of the remaining spiral to disassemble spontaneously. Lets say you do this to some 7x7 vehicle. You'd only need to first remove 18 blocks manually, out of the 42 total. Then keep halving it to disassemble it. It could be balanced pretty easily though. If the parts always drop fully damaged, any time saved would basically be canceled out by how long it'd take to repair them to full?

As much hassle as it is to engineer this scenario though...honestly I'd see a general system for allowing vehicles to split/merge to be more useful in general, with fixing this as a side effect.

I thought this was already known simply because it is a pain to disassemble a whole car, Repeatedly pressing the disassemble key or holding it down will just remove everything in order, but it leaves this strand of frames hanging from it like the issue. Given this, perhaps there can be an option to split vehicles inside the menu. Draw a line through the car and require the user to have a saw, then drop very damaged parts along that line because you just saw the vehicle. It doesn't have to be a line, but you get my drift, select which tiles you want to saw to cut the car into two pieces. If you want to save all the parts, then you can just disassemble it manually and then have the option to split the two halves afterwards.

The most realistic thing in my opinion would be to just allow the vehicle to break into multiple vehicles. When you ram an obstacle for example, with the example vehicle, the frames would be destroyed immediately and reduced to scrap just because of the collision. Then the resulting vehicle fragments will be given the momentum of the original vehicle and so on. I see no issue with this other than the coding challenge. I am however against just dropping damaged parts.

@smolbird This is a good point. A proper vehicle cutting system is a "quick-release-lever" away from being able to add a bike rack to your cars.

I also agree that the most realistic course of action is to split the sever parts into a seperate vehicle.

I think allowing vehicles to split is a better solution, not only because it is more realistic, but also because it solves other existing problems such as dragging vehicles with vehicles

While allowing vehicles to split seems like the obvious solution it might also be a hard to implement one, Perhaps we can instead transfer damage that would be dealt to an indestructable part to all adjacent vehicle tiles instead and if this is an indestructible part again to all adjacent of the new one with some kind of loop prevention, basically resulting in transportation of the damage to damageable parts.

Splitting/merging is already something we can do, this has nothing to do with towing.

Splitting the vehicle isn't too difficult, the tricky part is what to do with the new vehicle.
The simplest thing is to spawn the new vehicle (The one that doesn't contain the current vehicles center of mass as a first guess) on the ground.
That's not a terrible fix in of itself, but then we could:

  1. Smash all the parts of the new vehicle with a strength scaled by the momentum of the vehicle.
  2. Check the new vehicles for wheels (and probably have it go out of control).
  3. Consider making the new vehicle "tumble" and suffer multiple impacts (possibly with monsters) as it bleeds off it's momentum.

Side note, I'm not in favor of arbitrary restrictions on construction, but there are non-arbitrary reasons the vehicle in the thread wouldn't work.
If we track load on vehicle frames, this kind of construction would quickly become untenable. The two connection points would be under an immense amount of strain. This is probably a fairly complex kind of thing to deal with reasonably.

If your vehicle breaks into two pieces when a zombie is just sitting there attacking a frame, then damaging all the parts on a randomly selected piece won't do. If the vehicle is moving but you are not currently seated and driving when it collides, you would need some way to know which piece is still the "main" vehicle.

Also, a vehicle moving without the control of a person or automated system should undoubtedly go out of control. However the tumble mechanic looks like it would be a hassle to implement. If the vehicle hits a building and happens to break into two pieces, the secondary piece shouldn't receive random damage. It will undoubtedly be damaged just because of the wall its going to hit. If the piece that breaks off is larger than the main vehicle, then smashing all the parts of the new vehicle shouldn't be considered as it would just be unrealistic.

If your vehicle breaks into two pieces when a zombie is just sitting there attacking a frame, then damaging all the parts on a randomly selected piece won't do.

That's why I said:

Smash all the parts of the new vehicle with a strength scaled by the momentum of the vehicle.

Breaking a chunk off of a stationary vehicle wouldn't have much impact. This is to represent vehicle pieces falling off and slamming into the ground at whatever speed they were already moving at. If it's < 10MPH or so it's no big deal, but once you get over 30MPH or so there's quite a lot of momentum to bleed off.

If the vehicle is moving but you are not currently seated and driving when it collides, you would need some way to know which piece is still the "main" vehicle.

I was unclear, I was assuming the new "vehicle" is relatively small and no longer "vehicle-worthy", i.e. it's not rolling on wheels anymore. Essentially, the chunk that doesn't contain the center of mass of the original vehicle is spawned as a new vehicle and set to have the same velocity as the old vehicle, then we'd proceed with the vehicle simulation, which will probably involve things like vehicle frames on one or both vehicles hitting the ground because they don't have enough wheels to stay upright anymore.

Damage should be applied as normal, if that damage results in the last part of a vehicle attaching it to other parts of the same vehicle, it should then break into multiple vehicle (at most 3 additional vehicles will be created) have the velocity of the original vehicle applied to them.

From then on the standard vehicle logic applies. A vehicle can move without a driver, and a vehicle can be moving at high speed without wheels. After all you can be driving at 100 mph and then suddenly lose all your wheels and the game is capable of handling that already.

Likely these vehicles will grind to a sudden and very spectacular halt, and if in front of the original vehicle (still with wheels), it will crash vehicle on vehicle, which is also already handled.

The only Non-Issue issue is a way to combine multiple vehicles. Which might be desirable if the tail end of your car gets ripped off and you want to reattach it.

Wouldn't a simple solution to this be to disable collision for destroyed parts on a vehicle? We wouldn't have to go to any more trouble to fix this if we did that.

This is simple, but would require code that would completely change how vehicles work. Something like if you disconnect all the frames on one half of a vehicle, it will split into two vehicles. This could help, but in an extreme scenario, that one car with a coil around it would be turned into seven to ten different vehicles in a crash, all of which being made up of one or two frames

I'm looking into fixing this.
Having destroyed parts break off, even when that would disconnect parts of the vehicle, is extremely easy.
Splitting a vehicle into 4 new vehicles is not at all easy.
Problems can roughly divided into two groups:

  1. Figuring out which parts go where without doing so many breadth first searches that the game stops.
  2. Having divided a vehicle into up to 4 new vehicle, putting the correct inventory, players grabbing it, etc. on the correct new vehicle.

If I'm wrong and splitting the vehicle is super hard, break it into chunks instead. Most of the time it should be a small number of pieces, and it's certainly better than the status quo.

I thought about it some more, and I realized I was getting overwhelmed by needless complexity.

New approach:

  1. Write unit test cases first, and work with them for development testing
  2. Write vehicle::split_vehicle( std::vector remove_parts ) FIRST.
    2a. split_vehicle creates a new empty vehicle called new_veh and then reassigns veh.parts[ remove_parts ] vehicle_part to new_veh.parts, then removes them from this.parts. Possibly by reassigning the pointers.
    2b. Start by splitting small, easy, arbitrary vehicles in the test cases, like two adjacent frames. Work up to larger, more complicated vehicles. At no point is the vector of remove_parts anything but obvious and statically counted.
    2c. Deal with special cases like cargo, passengers (need to transfer vehicle pointers iirc), grabs, and long activities.
  3. When split_vehicle() is complete, then do Oren's flood fill (or something? ) to generate remove_parts lists.
  4. finish this out.

Reassigning the pointers should make this very quick. Keep in mind that the vehicle:get_parts method only returns unbroken parts, getting the broken parts as well is likely desirable.

```original bike
part 0: extra light frame
part 1: saddle
part 2: bicycle horn
part 3: foot pedals
part 4: extra light frame
part 5: bicycle wheel (steerable)

parts of a bike
part 0: extra light frame
part 1: bicycle wheel
part 2: wire bike basket

vehicle split test completed successfully

All tests passed (6 assertions in 1 test case)
```
Still need to figure out which parts need to be split, splitting a vehicle into two out to be easy enough once I stopped panicking about it.

Figuring out which parts need to be split in some kind of reasonably speedy fashion is much trickier. How expensive is using parts_at_relative() on roughly every part in the vehicle, and if that's too expensive, what's an alternative to get a map of the vehicle?

[
  {
    "id": "split_test",
    "type": "vehicle",
    "name": "test cross",
    "//": "Don't remove this vehicle definition!",
    "blueprint": [
      " vvv ",
      "c v H",
      "cchHH",
      "c X H",
      "  X  ",
      "X X X",
      "XXXXX"
    ],
    "parts": [
      { "x": 0, "y": 0, "part": "frame_vertical_2" },
      { "x": 0, "y": 1, "part": "frame_vertical_2" },
      { "x": 0, "y": 2, "part": "folding_wooden_frame" },
      { "x": -1, "y": 2, "part": "hdframe_cross" },
      { "x": -2, "y": 2, "part": "hdframe_cross" },
      { "x": 1, "y": 2, "part": "frame_wood_horizontal" },
      { "x": 2, "y": 2, "part": "frame_wood_horizontal" },
      { "x": 0, "y": 3, "part": "xlframe_horizontal" },
      { "x": 0, "y": 4, "part": "xlframe_horizontal" },
      { "x": 0, "y": 5, "part": "xlframe_horizontal" },
      { "x": 0, "y": 6, "part": "xlframe_horizontal" },
      { "x": -1, "y": 0, "part": "frame_vertical_2" },
      { "x": 1, "y": 0, "part": "frame_vertical_2" },
      { "x": -2, "y": 1, "part": "hdframe_cross" },
      { "x": -2, "y": 3, "part": "hdframe_cross" },
      { "x": 2, "y": 1, "part": "frame_wood_horizontal" },
      { "x": 2, "y": 3, "part": "frame_wood_horizontal" },
      { "x": -1, "y": 6, "part": "xlframe_horizontal" },
      { "x": -2, "y": 6, "part": "xlframe_horizontal" },
      { "x": 1, "y": 6, "part": "xlframe_horizontal" },
      { "x": 2, "y": 6, "part": "xlframe_horizontal" },
      { "x": -2, "y": 5, "part": "xlframe_horizontal" },
      { "x": 2, "y": 5, "part": "xlframe_horizontal" }
    ]
  }
]

passes my vehicle split unit test case:

there are now 4 new vehicles
New vehicle consists of parts:  3  4 13 14 
New vehicle consists of parts:  5  6 15 16 
New vehicle consists of parts:  7  8  9 10 17 18 19 20 21 22 
original vehicle
    part 0: frame @ 61:61
    part 1: frame @ 62:61
    part 2: foldable wooden frame @ 63:61
    part 3: frame @ 61:62
    part 4: frame @ 61:60


parts of a vehicle
    part 0: heavy duty frame @ 63:62
    part 1: heavy duty frame @ 63:63
    part 2: heavy duty frame @ 62:63
    part 3: heavy duty frame @ 64:63


parts of a vehicle
    part 0: wooden frame @ 63:60
    part 1: wooden frame @ 63:59
    part 2: wooden frame @ 62:59
    part 3: wooden frame @ 64:59


parts of a vehicle
    part 0: extra light frame @ 64:61
    part 1: extra light frame @ 65:61
    part 2: extra light frame @ 66:61
    part 3: extra light frame @ 67:61
    part 4: extra light frame @ 67:62
    part 5: extra light frame @ 67:63
    part 6: extra light frame @ 67:60
    part 7: extra light frame @ 67:59
    part 8: extra light frame @ 66:63
    part 9: extra light frame @ 66:59

    vehicle split test completed successfully

See https://github.com/mlangsdorf/Cataclysm-DDA/pull/25 for the very raw code.

So currently, vehicle::part_removal_cleanup is only called as part of map::vehmove(). Is there a prohibition against calling part_removal_cleanup() from elsewhere or is just something that usually only needs to be done once per turn? I suspect that some of my issues with weird behavior might be partially resolved by calling part_removal_cleanup on the original vehicle after a split, but it could also be really processor intensive if part_removal_cleanup is called repeated while processing an explosion.

Was this page helpful?
0 / 5 - 0 ratings