Files
Bubberstation/code/game/turfs/baseturfs.dm
Y0SH1M4S73RandGitHub 6979f2b374 Fixes interactions between shuttles and trapdoors (#93970)
## About The Pull Request

This PR makes several changes to trapdoors to remove wrong interactions
that occur should one be built on a shuttle:
- Trapdoors built on a shuttle will be carried along with the shuttle
when it moves. Even when they are open.
- If a shuttle lands on a trapdoor without breaking it, the trapdoor
will not function while the shuttle's floor lies on top of it.
- Shuttles with open trapdoors inside of them will not magically bring
open space into transit.
- A trapdoor moved on top of a non-openspace tile using a shuttle will
open to the turf that was originally under the shuttle.

## Why It's Good For The Game

Fixes #93924, and also adds a new feature to what is possible with
custom shuttles on multi-z maps.

## Changelog

🆑
add: Trapdoors built inside of a shuttle will move along with the
shuttle.
fix: Open trapdoors will not cause shuttles containing them to bring
open space into transit.
/🆑
2025-11-28 16:15:18 +13:00

196 lines
7.2 KiB
Plaintext

/// Take off the top layer turf and replace it with the next baseturf down
/turf/proc/ScrapeAway(amount=1, flags)
if(!amount)
return
if(length(baseturfs))
var/list/new_baseturfs = baseturfs.Copy()
var/turf_type = new_baseturfs[max(1, new_baseturfs.len - amount + 1)]
while(ispath(turf_type, /turf/baseturf_skipover))
amount++
if(amount > new_baseturfs.len)
CRASH("The bottommost baseturf of a turf is a skipover [src]([type])")
turf_type = new_baseturfs[max(1, new_baseturfs.len - amount + 1)]
new_baseturfs.len -= min(amount, new_baseturfs.len - 1) // No removing the very bottom
if(new_baseturfs.len == 1)
new_baseturfs = new_baseturfs[1]
return ChangeTurf(turf_type, new_baseturfs, flags)
if(baseturfs == type)
return src
return ChangeTurf(baseturfs, baseturfs, flags) // The bottom baseturf will never go away
/// Places the given turf on the bottom of the turf stack.
/turf/proc/place_on_bottom(turf/bottom_turf)
baseturfs = baseturfs_string_list(
list(initial(bottom_turf.baseturfs), bottom_turf) + baseturfs,
src
)
/// Places a turf at the top of the stack
/turf/proc/place_on_top(turf/added_layer, flags)
var/list/turf/new_baseturfs = list()
new_baseturfs.Add(baseturfs)
if(isopenturf(src))
new_baseturfs.Add(type)
var/area/our_area = get_area(src)
flags = our_area.place_on_top_react(new_baseturfs, added_layer, flags)
return ChangeTurf(added_layer, new_baseturfs, flags)
/// Places a turf on top - for map loading
/turf/proc/load_on_top(turf/added_layer, flags)
var/area/our_area = get_area(src)
flags = our_area.place_on_top_react(list(baseturfs), added_layer, flags)
if(flags & CHANGETURF_SKIP) // We haven't been initialized
if(flags_1 & INITIALIZED_1)
stack_trace("CHANGETURF_SKIP was used in a PlaceOnTop call for a turf that's initialized. This is a mistake. [src]([type])")
assemble_baseturfs()
var/turf/new_turf
if(!length(baseturfs))
baseturfs = list(baseturfs)
var/list/old_baseturfs = baseturfs.Copy()
if(!isclosedturf(src))
old_baseturfs += type
new_turf = ChangeTurf(added_layer, null, flags)
new_turf.assemble_baseturfs(initial(added_layer.baseturfs)) // The baseturfs list is created like roundstart
if(!length(new_turf.baseturfs))
new_turf.baseturfs = list(baseturfs)
// The old baseturfs are put underneath, and we sort out the unwanted ones
new_turf.baseturfs = baseturfs_string_list(old_baseturfs + (new_turf.baseturfs - GLOB.blacklisted_automated_baseturfs), new_turf)
return new_turf
// Copy an existing turf and put it on top
// Returns the new turf
/turf/proc/CopyOnTop(turf/copytarget, ignore_bottom = 1, depth = INFINITY, copy_air = FALSE, flags = null)
var/list/new_baseturfs = list()
new_baseturfs += baseturfs
new_baseturfs += type
if(depth)
var/list/target_baseturfs
if(length(copytarget.baseturfs))
// with default inputs this would be Copy(clamp(2, -INFINITY, baseturfs.len))
// Don't forget a lower index is lower in the baseturfs stack, the bottom is baseturfs[1]
target_baseturfs = copytarget.baseturfs.Copy(clamp(1 + ignore_bottom, 1 + copytarget.baseturfs.len - depth, copytarget.baseturfs.len))
else if(!ignore_bottom)
target_baseturfs = list(copytarget.baseturfs)
if(target_baseturfs)
target_baseturfs -= new_baseturfs & GLOB.blacklisted_automated_baseturfs
new_baseturfs += target_baseturfs
var/turf/new_turf = copytarget.copyTurf(src, copy_air, flags)
new_turf.baseturfs = baseturfs_string_list(new_baseturfs, new_turf)
return new_turf
/// Tries to find the given type in baseturfs.
/// If found, returns how deep it is for use in other baseturf procs, or null if it cannot be found.
/// For example, this number can be passed into ScrapeAway to scrape everything until that point.
/turf/proc/depth_to_find_baseturf(baseturf_type)
if(!islist(baseturfs))
return baseturfs == baseturf_type ? 1 : null
var/index = baseturfs.Find(baseturf_type)
if (index == 0)
return null
return baseturfs.len - index + 1
/// Similar to depth_to_find_baseturf, but directly returns the index of the found baseturf.
/// This number can be passed into insert_baseturf to insert a baseturf before the found baseturf.
/turf/proc/level_to_find_baseturf(baseturf_type)
if(!islist(baseturfs))
return baseturfs == baseturf_type ? 1 : null
return baseturfs.Find(baseturf_type) || null
/// Returns the baseturf at the given depth.
/// For example, baseturf_at_depth(1) will give the baseturf that would show up when scraping once.
/turf/proc/baseturf_at_depth(index)
TEST_ONLY_ASSERT(isnum(index), "baseturf_at_depth must be given a number, received [index]")
if (islist(baseturfs))
return LAZYACCESS(baseturfs, baseturfs.len - index + 1)
else if (index == 1)
return baseturfs
else
return null
/// Replaces all instances of needle_type in baseturfs with replacement_type
/turf/proc/replace_baseturf(needle_type, replacement_type)
if (islist(baseturfs))
var/list/new_baseturfs = baseturfs.Copy()
for(var/base_i in 1 to length(new_baseturfs))
var/found_index = new_baseturfs.Find(needle_type)
if (found_index == 0)
break
new_baseturfs[found_index] = replacement_type
if (length(new_baseturfs))
baseturfs = baseturfs_string_list(new_baseturfs, src)
else if (baseturfs == needle_type)
baseturfs = replacement_type
/// Removes all baseturfs that are found in the given typecache.
/turf/proc/remove_baseturfs_from_typecache(list/typecache)
if (islist(baseturfs))
var/list/new_baseturfs
for (var/baseturf in baseturfs)
if (!typecache[baseturf])
continue
new_baseturfs ||= baseturfs.Copy()
new_baseturfs -= baseturf
if (!isnull(new_baseturfs))
baseturfs = baseturfs_string_list(new_baseturfs, src)
else if (typecache[baseturfs])
baseturfs = /turf/baseturf_bottom
/// Returns the total number of baseturfs
/turf/proc/count_baseturfs()
return islist(baseturfs) ? length(baseturfs) : 1
/// Inserts a baseturf at the given level.
/// "Level" here doesn't mean depth.
/// For example, `insert_baseturf(2, /turf/open/floor/plating)` will make it so
/// the 2nd to last turf in the list is plating.
/// This is different from *depth*, since depth is the level from the top.
/turf/proc/insert_baseturf(level, turf_type)
if (!islist(baseturfs))
assemble_baseturfs()
if(!islist(baseturfs))
baseturfs = list(baseturfs)
var/list/baseturfs_copy = baseturfs.Copy()
baseturfs_copy.Insert(level, turf_type)
baseturfs = baseturfs_string_list(baseturfs_copy, src)
/// Places a baseturf ontop of a searched for baseturf.
/turf/proc/stack_ontop_of_baseturf(floor, roof)
if (!islist(baseturfs))
baseturfs = list(baseturfs)
var/floor_position = baseturfs.Find(floor)
if(floor_position != 0)
insert_baseturf(floor_position + 1, roof)
/// Places a baseturf below a searched for baseturf.
/turf/proc/stack_below_baseturf(search_type, stack_type)
if(!islist(baseturfs))
baseturfs = list(baseturfs)
var/search_position = baseturfs.Find(search_type)
if(search_position != 0)
insert_baseturf(search_position, stack_type)
else if(type == search_type)
insert_baseturf(turf_type = stack_type)
/// Gets a copy of the baseturfs up to the specified depth
/turf/proc/get_baseturfs_to_depth(depth)
var/list/baseturf_list = islist(baseturfs) ? baseturfs : list(baseturfs)
return baseturf_list.Copy(baseturf_list.len - depth + 1)