mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 09:42:29 +00:00
## About The Pull Request This incredibly detailed PR adds the ability to construct custom shuttles, which function similarly to whiteships. To construct a custom shuttle, you need the following items: - Shuttle frame rods These rods can be hand-crafted by using 5 rods on 1 sheet of titanium, or printed at a sci/engi/cargo lathe after researching the Shuttle Engineering techweb node. Lattices built with these rods, and catwalks/floors built on top of these lattices, are valid for shuttle construction. - Shuttle engines Did you know shuttle engines have boards that weren't normally obtainable? Well the board for one specific engine type is now available from the sci/engi/cargo lathe after researching Shuttle Engineering. Of course, the old options remain. You can steal engines from other shuttles, including escape pods (it's not like engines are strictly necessary for *those* shuttles anyways). Alternatively, the shuttle engine supply pack is no longer locked behind the purchase of the BYOS. - Flight Control & Navigation Console boards These boards are printed at the sci/engi/cargo lathe after researching the Shuttle Engineering techweb node. If built on a custom shuttle, it will automatically link to it, unless the shuttle already has such a console. If built on a turf that is valid for custom shuttle construction, it will automatically link to any shuttle constructed from or expanded with that turf. - Shuttle blueprints Standard shuttle blueprints can be printed at the sci/engi/cargo lathe after researching the Shuttle Engineering techweb node. A cyborg upgrade granting access to a shuttle blueprint database can be printed at the exofab after researching the aforementioned node. Crude shuttle blueprints can be crafted by hand with a sheet of paper and either a rainbow crayon or 10 uses of a blue crayon or spraycan. If Science won't research the tech, you can also buy a goody pack containing a flight control board, a docker board, two engine boards, and a set of shuttle blueprints for 1200 credits, if you have aux base access. A shuttle can be constructed atop any continuous region of turfs containing a shuttle rod lattice or a catwalk/tile built upon such. Currently, this region cannot intersect any area other than space, lavaland, the icemoon, or the station asteroid. Preexisting custom areas can be included in the construction of the shuttle, but only if every turf in the custom area is valid for shuttle construction. In the shuttle blueprint UI, you can toggle a visualizer to display which turfs fulfill all of the aforementioned conditions. The following video goes through the basic process of shuttle construction. https://github.com/user-attachments/assets/3283422e-a201-4978-972d-67527b5df4ee The blueprint used to construct the shuttle will be its master blueprint. The master blueprint can be copied to other blank shuttle blueprints (or to engiborgs with the shuttle database upgrade), and allows the holder to perform a christening ritual on the shuttle to rename it. If a shuttle's master blueprint ceases to exist, a blank blueprint can be linked to the shuttle to become the new master blueprint, or an existing blueprint associated with that shuttle can be promoted to the master blueprint. Once constructed, the following options are available from the blueprint UI to modify it: - Create Area Convert a continuous open area of the shuttle into a new area with the name written in the above text input. This operates very similarly to regular area construction. - Rename Area Change the name of the area you're currently in to the name written in the above text input. - Expand Area Add a continuous open area of the shuttle to the neighboring area selected from the dropdown to the left. This operates like regular area expansion. - Expand Shuttle Expand a shuttle with valid frame turfs as defined above. These turfs must be physically connected to the shuttle. - Remove Area Remove an area, giving its tiles to the default shuttle area. - Cleanup Empty Space (implemented after the above video was recorded) Removes all completely empty turfs from the shuttle. If all the turfs in one of the shuttle's areas were removed, that area is deleted. If absolutely no turfs of the shuttle remain, the shuttle itself is deleted. Due to the ability for this action to delete the shuttle, only the master blueprint can do it. As mentioned above, the shuttle's master blueprint can be used to christen its associated shuttle. To do this, fill a glass drink bottle with some amount of reagents, then hit it against one of the shuttle's walls from outside while holding the master blueprint. You will be prompted to enter a new name for the shuttle. The variety of things that can happen while inputting a new name can cause the christening rite to fail in one of several humorous ways. ### Optional (Unless specifically requested by a maintainer) Todo's - [x] A way for shuttle circuits to be obtainable without techweb nodes - [x] A more convenient way to carry around shuttle engines or the means to deploy them - [ ] A shuttle construction guide available as a reference book - [ ] Allow boards to be linked to shuttles before construction so they can be used outside the shuttle ## Why It's Good For The Game Shuttles have been part of the sandbox for an incredibly long time, but their limited accessibility has rendered them the exclusive territory of lucky space explorers or the few antagonists who get one off the bat (nukies and pirates). Giving players the means to construct shuttles to their liking opens up a variety of possibilities for gimmicks for antags and non-antags alike. Besides the applications for antaggery and crew-sided gimmicks, this provides side content for several departments to engage with during the relatively-frequent periods of time where they have little else to do as part of their intended roles. With respect to engineering, if the station isn't actively being damaged, the supermatter is in perfect working order, and nobody is clamoring for machine upgrades, engineers have little else to resort to other than construction projects. While the BSA station goal provides an incentive for engineers to construct dedicated rooms for the cannon, it will not necessarily be available every round. Custom shuttles not only provide such a construction project to pursue, but provide the rare opportunity, as well as a very good reason, to set up an independent power network, complete with its own power source. While atmos techs have a lot to do with gas mixing and the crystallizer, they rarely get the opportunity to set up working life support systems outside of repairing the ones that get blown up. Custom shuttles will frequently start with no air, and unless the design settled upon is an open floor plan, it will have several independent chambers that cannot so easily be profused with a proper airmix by just opening a canister. Furthermore, if the air in a custom shuttle gets messed up, a proper scrubber and distro network is a significantly less tedious method of rectifying the problem than cleaning the air manually with portable scrubbers and pumps. Scientists, it can be argued, with their access to RPDs through ordnance, have similar opportunities to atmos techs, even though the act in and of itself is not exactly part of their duties. But compared to the other job content they could be working with after they've completed most of their gameplay loop, custom shuttle construction is a substantially more active endeavor. And I know how much people complain about late-game science content just being sitting around at a console and making gamer gear. Roboticists can have a part to play in this too. They can put their mech RCDs to a use other than 2D topdown Fortnite, and with the shuttle database upgrade, they can help interested cyborgs get in on the action. Cargo is yet another department known for having significant amounts of downtime during a considerable number of rounds. If every other department has gone through their initial rounds of departmental orders, and there isn't an active need for cargo to order lots of one thing or another, cargo techs have little to do besides mail (at least on the days where there **is** mail to deliver). Usually, if cargo techs do, in fact, do something as a department when not presented with more pressing duties, they order guns and other contraband. As funny as this is, there's not a lot of variety in how this behavior manifests. With custom shuttles, cargo can use their free time to plan, and execute, a unique collective expression of design sensibilities, not limited by the size and shape constraints of the cargo bay itself. ## Changelog 🆑 Y0SH1_M4S73R (with special thanks to Vect0r, whose original PR inspired the implementation of these changes) add: Shuttle blueprints, the tool used to construct and modify custom shuttles. Print a set at a science, engineering, or cargo techfab after researching Shuttle Engineering, or craft a crude set from the crafting menu. add: Shuttle blueprint database upgrade for engineering cyborgs, printable from the Exosuit Fabricator after researching Shuttle Engineering. A version of shuttle blueprints designed for use by cyborgs. add: Shuttle frame rods, usable to construct custom shuttles. Hand-craft by using 5 rods on 1 titanium sheet, or by printing them at a science, engineering, or cargo techfab after researching Shuttle Engineering. add: Custom shuttle flight control and navigation boards, printable from a science, engineering, or cargo techfab after researching Shuttle Engineering. add: Shuttle engine boards can be printed from a science, engineering, or cargo techfab after researching shuttle engineering. add: The shuttle engine supply pack is no longer locked behind the purchase of the Build Your Own Shuttle kit. add: Shuttle Construction Starter Kit goodie pack, containing a set of shuttle blueprints, flight control and navigation console boards, and two engine boards, can be purchased from cargo for 1200 credits. Requires aux base access to purchase. refactor: Shuttles now keep track of what areas are underneath each of their individual turfs, so that the areas left behind on movement are consistent with what they were beforehand. refactor: Shuttle ceilings now place themselves down as baseturfs, instead of only appearing if the turf above is open space. /🆑 --------- Co-authored-by: vect0r <71346830+Vect0r2@users.noreply.github.com> Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Co-authored-by: necromanceranne <40847847+necromanceranne@users.noreply.github.com>
118 lines
4.5 KiB
Plaintext
118 lines
4.5 KiB
Plaintext
/**
|
|
* This component behaves similar to connect_loc_behalf but for all turfs in range, hooking into a signal on each of them.
|
|
* Just like connect_loc_behalf, It can react to that signal on behalf of a separate listener.
|
|
* Good for components, though it carries some overhead. Can't be an element as that may lead to bugs.
|
|
*/
|
|
/datum/component/connect_range
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
|
|
|
/// An assoc list of signal -> procpath to register to the loc this object is on.
|
|
var/list/connections
|
|
/// The turfs currently connected to this component
|
|
var/list/turfs = list()
|
|
/**
|
|
* The atom the component is tracking. The component will delete itself if the tracked is deleted.
|
|
* Signals will also be updated whenever it moves (if it's a movable).
|
|
*/
|
|
var/atom/tracked
|
|
|
|
/// The component will hook into signals only on turfs not farther from tracked than this.
|
|
var/range
|
|
/// Whether the component works when the movable isn't directly located on a turf.
|
|
var/works_in_containers
|
|
|
|
/datum/component/connect_range/Initialize(atom/tracked, list/connections, range, works_in_containers = TRUE)
|
|
if(!isatom(tracked) || isarea(tracked) || range < 0)
|
|
return COMPONENT_INCOMPATIBLE
|
|
src.connections = connections
|
|
src.range = range
|
|
set_tracked(tracked)
|
|
src.works_in_containers = works_in_containers
|
|
|
|
/datum/component/connect_range/Destroy()
|
|
set_tracked(null)
|
|
return ..()
|
|
|
|
/datum/component/connect_range/InheritComponent(datum/component/component, original, atom/tracked, list/connections, range, works_in_containers)
|
|
// Not equivalent. Checks if they are not the same list via shallow comparison.
|
|
if(!compare_list(src.connections, connections))
|
|
stack_trace("connect_range component attached to [parent] tried to inherit another connect_range component with different connections")
|
|
return
|
|
if(src.tracked != tracked)
|
|
set_tracked(tracked)
|
|
if(src.range == range && src.works_in_containers == works_in_containers)
|
|
return
|
|
//Unregister the signals with the old settings.
|
|
unregister_signals(isturf(tracked) ? tracked : tracked.loc, turfs)
|
|
src.range = range
|
|
src.works_in_containers = works_in_containers
|
|
//Re-register the signals with the new settings.
|
|
update_signals(src.tracked)
|
|
|
|
/datum/component/connect_range/proc/set_tracked(atom/new_tracked)
|
|
if(tracked) //Unregister the signals from the old tracked and its surroundings
|
|
unregister_signals(isturf(tracked) ? tracked : tracked.loc, turfs)
|
|
UnregisterSignal(tracked, list(
|
|
COMSIG_MOVABLE_MOVED,
|
|
COMSIG_QDELETING,
|
|
))
|
|
tracked = new_tracked
|
|
if(!tracked)
|
|
return
|
|
//Register signals on the new tracked atom and its surroundings.
|
|
RegisterSignal(tracked, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
|
RegisterSignal(tracked, COMSIG_QDELETING, PROC_REF(handle_tracked_qdel))
|
|
update_signals(tracked)
|
|
|
|
/datum/component/connect_range/proc/handle_tracked_qdel()
|
|
SIGNAL_HANDLER
|
|
qdel(src)
|
|
|
|
/datum/component/connect_range/proc/update_signals(atom/target, atom/old_loc)
|
|
var/turf/current_turf = get_turf(target)
|
|
if(isnull(current_turf))
|
|
unregister_signals(old_loc, turfs)
|
|
turfs = list()
|
|
return
|
|
|
|
var/loc_is_movable = ismovable(target.loc)
|
|
|
|
if(loc_is_movable)
|
|
if(!works_in_containers)
|
|
unregister_signals(old_loc, turfs)
|
|
turfs = list()
|
|
return
|
|
|
|
//Only register/unregister turf signals if it's moved to a new turf.
|
|
if(current_turf == get_turf(old_loc))
|
|
unregister_signals(old_loc, null)
|
|
return
|
|
var/list/old_turfs = turfs
|
|
turfs = RANGE_TURFS(range, current_turf)
|
|
unregister_signals(old_loc, old_turfs - turfs)
|
|
if(loc_is_movable)
|
|
//Keep track of possible movement of all movables the target is in.
|
|
for(var/atom/movable/container as anything in get_nested_locs(target))
|
|
RegisterSignal(container, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
|
for(var/turf/target_turf as anything in turfs - old_turfs)
|
|
for(var/signal in connections)
|
|
parent.RegisterSignal(target_turf, signal, connections[signal])
|
|
|
|
/datum/component/connect_range/proc/unregister_signals(atom/location, list/remove_from)
|
|
//The location is null or is a container and the component shouldn't have register signals on it
|
|
if(isnull(location) || (!works_in_containers && !isturf(location)))
|
|
return
|
|
|
|
if(ismovable(location))
|
|
for(var/atom/movable/target as anything in (get_nested_locs(location) + location))
|
|
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
|
|
|
|
if(!length(remove_from))
|
|
return
|
|
for(var/turf/target_turf as anything in remove_from)
|
|
parent.UnregisterSignal(target_turf, connections)
|
|
|
|
/datum/component/connect_range/proc/on_moved(atom/movable/movable, atom/old_loc)
|
|
SIGNAL_HANDLER
|
|
update_signals(movable, old_loc)
|