mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 09:42:29 +00:00
## About The Pull Request This PR adds some tweaks to make custom shuttles a bit easier to use, and more useful. - The station blueprints can be used to allow/forbid custom shuttle docking in station/custom areas. Custom areas allow shuttle docking by default, while station areas (apart from the asteroid) forbid it. - A station area that allows shuttle docking can have a shuttle built/expanded in it, as long as the area's APC isn't contained within the frame used to construct/expand the shuttle. - A shuttle frame does not need to contain the entirety of a custom area, unless that frame contains the area's APC. If the frame doesn't contain the entirety of the custom area, that section of the frame becomes part of the default area, instead of a separate area. - Custom shuttles will go off into the sunset at the end of the round, as long as they have a welded engine. - I think I saw a bug that caused engines to contribute twice the intended power to the attached shuttle, possibly creating an exploit in the case where the engine was broken while welded. I fixed that. - Custom shuttle docking computers can cross over to any z-level adjacent to the shuttle's z-level (or vertically-connected z-levels, because docking computers can traverse stacked z-levels freely). This is based on the new `zlink_range` var on all shuttle docking consoles, which can be var-edited to provide the same functionality. - Shuttle engines constructed from circuits now link to shuttles without needing to be unanchored and reanchored. ## Why It's Good For The Game The tweaks to shuttle construction and docking serve to address several gripes I heard about players not being able to build/dock custom shuttles in station areas. The means to do this have been locked behind possession of the station blueprints. I don't see what problem there would be with allowing custom shuttles to leave the station at the end of the round, but I could lock it behind a particular action (antag-exclusive or otherwise). Custom shuttles don't quite have as much utility if you have to manually travel to z-levels to drop off gigabeacons. Jumping to adjacent z-levels one at a time is a bit more useful for space exploration. ## Changelog 🆑 add: The station blueprints can be used to toggle whether custom shuttles can be built/expanded/docked within station areas. qol: Custom areas do not have to be completely contained within shuttle frames, as long as the APC isn't attached to the frame. add: Custom shuttles with functioning engines will fly off into the sunset when the emergency shuttle leaves. add: Custom shuttle navigation computers can view space levels adjacent to the one the shuttle is currently docked at. fix: Constructed shuttle engines no longer contribute twice as much engine power to shuttles, nor can they be used to add unlimited shuttle power. fix: Constructed shuttle engines now connect to shuttles when build, rather than needing to be unachored and then reanchored. /🆑
114 lines
4.0 KiB
Plaintext
114 lines
4.0 KiB
Plaintext
/**
|
|
* - is_valid_z_level
|
|
*
|
|
* Checks if source_loc and checking_loc is both on the station, or on the same z level.
|
|
* This is because the station's several levels aren't considered the same z, so multi-z stations need this special case.
|
|
*
|
|
* Args:
|
|
* source_loc - turf of the source we're comparing.
|
|
* checking_loc - turf we are comparing to source_loc.
|
|
*
|
|
* returns TRUE if connection is valid, FALSE otherwise.
|
|
*/
|
|
/proc/is_valid_z_level(turf/source_loc, turf/checking_loc)
|
|
// if we're both on "station", regardless of multi-z, we'll pass by.
|
|
if(is_station_level(source_loc.z) && is_station_level(checking_loc.z))
|
|
return TRUE
|
|
if(source_loc.z == checking_loc.z)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/**
|
|
* Checks if the passed non-area atom is on a "planet".
|
|
*
|
|
* A planet is defined as anything with planetary atmos that has gravity, with some hardcoded exceptions.
|
|
*
|
|
* * Nullspace counts as "not a planet", so you may want to check that separately.
|
|
* * The mining z-level (Lavaland) is always considered a planet.
|
|
* * The station z-level is considered a planet if the map config says so.
|
|
* * Central Command is always not a planet.
|
|
* * Syndicate recon outpost is always on a planet.
|
|
*
|
|
* Returns TRUE if we are on a planet.
|
|
* Returns FALSE if we are not in a planet, or otherwise, "in space".
|
|
*/
|
|
/proc/is_on_a_planet(atom/what)
|
|
ASSERT(!isarea(what))
|
|
|
|
var/turf/open/what_turf = get_turf(what)
|
|
if(isnull(what_turf))
|
|
// Nullspace is, well, not a planet?
|
|
return FALSE
|
|
|
|
if(is_mining_level(what_turf.z))
|
|
// Always assume Lavaland / mining level is a planet. (Asteroid mining crying right now)
|
|
return TRUE
|
|
|
|
if(is_station_level(what_turf.z))
|
|
// Station levels rely on the map config, I.E. Icebox is planetary but Meta is not
|
|
return SSmapping.is_planetary()
|
|
|
|
if(is_centcom_level(what_turf.z))
|
|
// Central Command is definitely in space
|
|
return FALSE
|
|
|
|
if(what.onSyndieBase())
|
|
// Syndicate recon outpost is on some moon or something
|
|
return TRUE
|
|
|
|
// Finally, more specific checks are ran for edge cases, such as lazily loaded map templates or away missions. Not perfect.
|
|
return istype(what_turf) && what_turf.planetary_atmos && what_turf.has_gravity()
|
|
|
|
/**
|
|
* Gets the angle between two linked z-levels.
|
|
* Returns an angle (in degrees) if the z-levels are crosslinked/neighbors,
|
|
* or null if they are not.
|
|
*
|
|
* Arguments:
|
|
* * start: The starting Z level. Can either be a numeric z-level, or a [/datum/space_level].
|
|
* * end: The destination Z level. Can either be a numeric z-level, or a [/datum/space_level].
|
|
*/
|
|
/proc/get_linked_z_angle(datum/space_level/start, datum/space_level/end)
|
|
if(isnum(start))
|
|
start = SSmapping.get_level(start)
|
|
if(isnum(end))
|
|
end = SSmapping.get_level(end)
|
|
// Check the neighbors first, and return the appropiate angle if it is a neighbor.
|
|
for(var/direction in start.neigbours)
|
|
var/datum/space_level/neighbor = start.neigbours[direction]
|
|
if(neighbor == end)
|
|
var/angle = GLOB.cardinal_angles[direction]
|
|
if(!isnull(angle))
|
|
return angle
|
|
// Otherwise, if they're both crosslinked, calculate the angle using their grid coordinates.
|
|
if(start.linkage == CROSSLINKED && end.linkage == CROSSLINKED)
|
|
var/dx = end.xi - start.xi
|
|
var/dy = end.yi - start.yi
|
|
return round(delta_to_angle(dy, dx))
|
|
return null
|
|
|
|
/**
|
|
* Gets all connected z-levels within a given manhattan distance of center.
|
|
*
|
|
* Arguments:
|
|
* * center: The starting Z level. Can either be a numeric z-level, or a [/datun/space_level].
|
|
* * dist: The maximum distance to search.
|
|
*/
|
|
/proc/get_linked_z_levels_in_range(datum/space_level/center, dist)
|
|
if(isnum(center))
|
|
center = SSmapping.get_level(center)
|
|
var/list/to_check = list(center)
|
|
var/list/checked = list()
|
|
var/total_search_distance = 0
|
|
while(to_check.len && total_search_distance <= dist)
|
|
var/list/current_pass = to_check.Copy()
|
|
to_check.Cut()
|
|
for(var/datum/space_level/level as anything in current_pass)
|
|
checked[level] = TRUE
|
|
for(var/direction in level.neigbours)
|
|
var/datum/space_level/neighbor = level.neigbours[direction]
|
|
if(!checked[neighbor])
|
|
to_check |= neighbor
|
|
total_search_distance++
|
|
return checked
|