mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-27 23:27:34 +01:00
Custom Shuttles Redux: Allows for the construction of custom shuttles. (#88493)
## 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>
This commit is contained in:
co-authored by
vect0r
Jeremiah
necromanceranne
parent
7cb34ef9a8
commit
cbc3350224
@@ -6,6 +6,8 @@
|
||||
#define CRAFTING_MACHINERY_USE 0
|
||||
///If the structure is only "used" i.e. it checks to see if it's nearby and allows crafting, but doesn't delete it
|
||||
#define CRAFTING_STRUCTURE_USE 0
|
||||
///If the ingredient is only "used" i.e. it checks to see if it's nearby and allows crafting, but doesn't delete it
|
||||
#define CRAFTING_INGREDIENT_USE 0
|
||||
|
||||
//stack recipe placement check types
|
||||
/// Checks if there is an object of the result type in any of the cardinal directions
|
||||
|
||||
@@ -38,3 +38,9 @@
|
||||
|
||||
///From base of area/update_beauty()
|
||||
#define COMSIG_AREA_BEAUTY_UPDATED "area_beauty_updated"
|
||||
|
||||
/// From base of turf/change_area(area/old_area)
|
||||
#define COMSIG_AREA_TURF_ADDED "area_turf_added"
|
||||
|
||||
/// From base of turf/change_area(area/new_area)
|
||||
#define COMSIG_AREA_TURF_REMOVED "area_turf_removed"
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
//From base of /obj/structure/lattice/proc/replace_with_catwalk() : (list/post_replacement_callbacks)
|
||||
/// `post_replacement_callbacks` is a list that signal handlers can mutate to append `/datum/callback` objects.
|
||||
/// They will be called with the new catwalk after it has been initialized.
|
||||
#define COMSIG_LATTICE_PRE_REPLACE_WITH_CATWALK "lattice_pre_replace_with_catwalk"
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
// Shuttle signals. this file is empty because shuttle code is ancient, feel free to
|
||||
// add more signals where its appropriate to have them
|
||||
|
||||
@@ -5,3 +6,6 @@
|
||||
#define COMSIG_SHUTTLE_SHOULD_MOVE "shuttle_should_move"
|
||||
/// Return this when the shuttle move should be blocked.
|
||||
#define BLOCK_SHUTTLE_MOVE (1<<0)
|
||||
|
||||
//from base of /proc/expand_shuttle() : (list/turfs)
|
||||
#define COMSIG_SHUTTLE_EXPANDED "shuttle_expanded"
|
||||
|
||||
@@ -43,3 +43,14 @@
|
||||
|
||||
///Called when turf no longer blocks light from passing through
|
||||
#define COMSIG_TURF_NO_LONGER_BLOCK_LIGHT "turf_no_longer_block_light"
|
||||
|
||||
///from /turf/proc/attempt_lattice_replacement() : (list/post_successful_replacement_callbacks)
|
||||
/// `post_successful_replacement_callbacks` is a list that signal handlers can mutate to append `/datum/callback` objects.
|
||||
/// They will be called with the new catwalk if it is actually created.
|
||||
#define COMSIG_TURF_ATTEMPT_LATTICE_REPLACEMENT "turf_replaced_with_lattice"
|
||||
|
||||
///from /turf/proc/change_area() : (area/old_area)
|
||||
#define COMSIG_TURF_AREA_CHANGED "turf_area_changed"
|
||||
|
||||
///from /proc/create_shuttle() and /obj/docking_port/mobile/proc/add_turf() : (obj/docking_port/mobile/shuttle)
|
||||
#define COMSIG_TURF_ADDED_TO_SHUTTLE "turf_added_to_shuttle"
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
#define TECHWEB_NODE_SANITATION "sanitation"
|
||||
#define TECHWEB_NODE_SEC_EQUIP "sec_equip"
|
||||
#define TECHWEB_NODE_SELECTION "selection"
|
||||
#define TECHWEB_NODE_SHUTTLE_ENG "shuttle_eng"
|
||||
#define TECHWEB_NODE_SPEC_ENG "spec_eng"
|
||||
#define TECHWEB_NODE_STICKY_ADVANCED "sticky_advanced"
|
||||
#define TECHWEB_NODE_SURGERY "surgery"
|
||||
|
||||
@@ -130,3 +130,21 @@
|
||||
#define HIJACK_STAGE_3 3
|
||||
#define HIJACK_STAGE_4 4
|
||||
#define HIJACK_COMPLETED 5
|
||||
|
||||
// Custom shuttle construction errors
|
||||
#define ORIGIN_NOT_ON_SHUTTLE 1 << 0
|
||||
|
||||
// The following two errors occur in mutually exclusive contexts, so they can share the same bitflag
|
||||
#define TOO_MANY_SHUTTLES 1 << 1
|
||||
#define FRAME_NOT_ADJACENT_TO_LINKED_SHUTTLE 1 << 1
|
||||
|
||||
#define ABOVE_MAX_SHUTTLE_SIZE 1 << 2
|
||||
#define CUSTOM_AREA_NOT_COMPLETELY_CONTAINED 1 << 3
|
||||
#define INTERSECTS_NON_WHITELISTED_AREA 1 << 4
|
||||
|
||||
// Custom shuttle engine defines
|
||||
#define CUSTOM_ENGINE_COEFF_MIN 0.5
|
||||
#define CUSTOM_ENGINE_COEFF_MAX 10
|
||||
|
||||
#define CUSTOM_ENGINE_POWER_MULTIPLIER 25
|
||||
#define CUSTOM_ENGINE_POWER_TURF_COUNT_OFFSET 5
|
||||
|
||||
@@ -1438,4 +1438,18 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
|
||||
/// Prevents fishing achievement from being granted by catching one of these
|
||||
#define TRAIT_NO_FISHING_ACHIEVEMENT "no_fishing_achievement"
|
||||
|
||||
/**
|
||||
* This trait is given to turfs that have had shuttle frame parts built on them, but are not yet part of a shuttle.
|
||||
* When attempting custom shuttle creation, a flood fill algorithm
|
||||
* checks for turfs with this trait to determine the turfs
|
||||
* that will constitute the created shuttle.
|
||||
*/
|
||||
#define TRAIT_SHUTTLE_CONSTRUCTION_TURF "shuttle_construction_turf"
|
||||
|
||||
// Trait given to areas with a shuttle construction turf in them
|
||||
#define TRAIT_HAS_SHUTTLE_CONSTRUCTION_TURF "has_shuttle_construction_turf"
|
||||
|
||||
///A trait given to users as a mutex to prevent repeated unresolved attempts to christen a shuttle
|
||||
#define TRAIT_ATTEMPTING_CHRISTENING "attempting_christening"
|
||||
|
||||
// END TRAIT DEFINES
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#define CHANGETURF_INHERIT_AIR (1<<4) // Inherit air from previous turf. Implies CHANGETURF_IGNORE_AIR
|
||||
#define CHANGETURF_RECALC_ADJACENT (1<<5) //Immediately recalc adjacent atmos turfs instead of queuing.
|
||||
#define CHANGETURF_TRAPDOOR_INDUCED (1<<6) // Caused by a trapdoor, for trapdoor to know that this changeturf was caused by itself
|
||||
#define CHANGETURF_GENERATE_SHUTTLE_CEILING (1<<7) // Generate a shuttle ceiling on the above turf
|
||||
|
||||
#define IS_OPAQUE_TURF(turf) (turf.directional_opacity == ALL_CARDINALS)
|
||||
|
||||
|
||||
+34
-21
@@ -1,4 +1,6 @@
|
||||
#define BP_MAX_ROOM_SIZE 300
|
||||
#define EXTRA_ROOM_CHECK_SKIP 1
|
||||
#define EXTRA_ROOM_CHECK_FAIL 2
|
||||
|
||||
GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(list(
|
||||
/area/station/engineering/main,
|
||||
@@ -13,8 +15,9 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(list(
|
||||
// Returns an associative list of turf|dirs pairs
|
||||
// The dirs are connected turfs in the same space
|
||||
// break_if_found is a typecache of turf/area types to return false if found
|
||||
// extra_check is an optional callback to invoke on each turf checked, and can specify whether to skip processing the turf or return false
|
||||
// Please keep this proc type agnostic. If you need to restrict it do it elsewhere or add an arg.
|
||||
/proc/detect_room(turf/origin, list/break_if_found = list(), max_size=INFINITY)
|
||||
/proc/detect_room(turf/origin, list/break_if_found = list(), max_size=INFINITY, datum/callback/extra_check)
|
||||
if(origin.blocks_air)
|
||||
return list(origin)
|
||||
|
||||
@@ -35,6 +38,11 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(list(
|
||||
continue
|
||||
checked_turfs[sourceT] |= dir
|
||||
checked_turfs[checkT] |= REVERSE_DIR(dir)
|
||||
switch(extra_check?.Invoke(checkT))
|
||||
if(EXTRA_ROOM_CHECK_SKIP)
|
||||
continue
|
||||
if(EXTRA_ROOM_CHECK_FAIL)
|
||||
return FALSE
|
||||
.[sourceT] |= dir
|
||||
.[checkT] |= REVERSE_DIR(dir)
|
||||
if(break_if_found[checkT.type] || break_if_found[checkT.loc.type])
|
||||
@@ -81,6 +89,28 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(list(
|
||||
return
|
||||
counter += 1 //increment by one so the next loop will start at the next position in the list
|
||||
|
||||
/proc/set_turfs_to_area(list/turf/turfs, area/new_area, list/area/affected_areas = list())
|
||||
for(var/turf/the_turf as anything in turfs)
|
||||
var/area/old_area = the_turf.loc
|
||||
|
||||
//keep rack of all areas affected by turf changes
|
||||
affected_areas[old_area.name] = old_area
|
||||
|
||||
//move the turf to its new area and unregister it from the old one
|
||||
the_turf.change_area(old_area, new_area)
|
||||
|
||||
//inform atoms on the turf that their area has changed
|
||||
for(var/atom/stuff as anything in the_turf)
|
||||
//unregister the stuff from its old area
|
||||
SEND_SIGNAL(stuff, COMSIG_EXIT_AREA, old_area)
|
||||
|
||||
//register the stuff to its new area. special exception for apc as its not registered to this signal
|
||||
if(istype(stuff, /obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/area_apc = stuff
|
||||
area_apc.assign_to_area()
|
||||
else
|
||||
SEND_SIGNAL(stuff, COMSIG_ENTER_AREA, new_area)
|
||||
|
||||
/proc/create_area(mob/creator, new_area_type = /area)
|
||||
// Passed into the above proc as list/break_if_found
|
||||
var/static/list/area_or_turf_fail_types = typecacheof(list(
|
||||
@@ -135,8 +165,10 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(list(
|
||||
if(!str)
|
||||
return
|
||||
newA = new area_choice
|
||||
newA.AddComponent(/datum/component/custom_area)
|
||||
newA.setup(str)
|
||||
newA.default_gravity = oldA.default_gravity
|
||||
GLOB.custom_areas[newA] = TRUE
|
||||
require_area_resort() //new area registered. resort the names
|
||||
else
|
||||
newA = area_choice
|
||||
@@ -151,26 +183,7 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(list(
|
||||
* we use this to keep track of what areas are affected by the blueprints & what machinery of these areas needs to be reconfigured accordingly
|
||||
*/
|
||||
var/list/area/affected_areas = list()
|
||||
for(var/turf/the_turf as anything in turfs)
|
||||
var/area/old_area = the_turf.loc
|
||||
|
||||
//keep rack of all areas affected by turf changes
|
||||
affected_areas[old_area.name] = old_area
|
||||
|
||||
//move the turf to its new area and unregister it from the old one
|
||||
the_turf.change_area(old_area, newA)
|
||||
|
||||
//inform atoms on the turf that their area has changed
|
||||
for(var/atom/stuff as anything in the_turf)
|
||||
//unregister the stuff from its old area
|
||||
SEND_SIGNAL(stuff, COMSIG_EXIT_AREA, old_area)
|
||||
|
||||
//register the stuff to its new area. special exception for apc as its not registered to this signal
|
||||
if(istype(stuff, /obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/area_apc = stuff
|
||||
area_apc.assign_to_area()
|
||||
else
|
||||
SEND_SIGNAL(stuff, COMSIG_ENTER_AREA, newA)
|
||||
set_turfs_to_area(turfs, newA, affected_areas)
|
||||
|
||||
newA.reg_in_areas_in_z()
|
||||
|
||||
|
||||
@@ -57,6 +57,9 @@
|
||||
/datum/proc/p_es(temp_gender)
|
||||
return "es"
|
||||
|
||||
/datum/proc/p_themselves(temp_gender)
|
||||
return "itself"
|
||||
|
||||
/datum/proc/plural_s(pluralize)
|
||||
switch(copytext_char(pluralize, -2))
|
||||
if ("ss")
|
||||
@@ -178,6 +181,19 @@
|
||||
if(temp_gender != PLURAL && temp_gender != NEUTER)
|
||||
return "es"
|
||||
|
||||
/client/p_themselves(temp_gender)
|
||||
if(!temp_gender)
|
||||
temp_gender = gender
|
||||
switch(temp_gender)
|
||||
if(FEMALE)
|
||||
return "herself"
|
||||
if(MALE)
|
||||
return "himself"
|
||||
if(PLURAL)
|
||||
return "themselves"
|
||||
else
|
||||
return "itself"
|
||||
|
||||
//mobs(and atoms but atoms don't really matter write your own proc overrides) also have gender!
|
||||
/mob/p_they(temp_gender)
|
||||
if(!temp_gender)
|
||||
@@ -271,6 +287,19 @@
|
||||
if(temp_gender != PLURAL)
|
||||
return "es"
|
||||
|
||||
/mob/p_themselves(temp_gender)
|
||||
if(!temp_gender)
|
||||
temp_gender = gender
|
||||
switch(temp_gender)
|
||||
if(FEMALE)
|
||||
return "herself"
|
||||
if(MALE)
|
||||
return "himself"
|
||||
if(PLURAL)
|
||||
return "themselves"
|
||||
else
|
||||
return "itself"
|
||||
|
||||
//humans need special handling, because they can have their gender hidden
|
||||
/mob/living/carbon/human/p_they(temp_gender)
|
||||
var/obscured = check_obscured_slots()
|
||||
@@ -342,6 +371,13 @@
|
||||
temp_gender = PLURAL
|
||||
return ..()
|
||||
|
||||
/mob/living/carbon/human/p_themselves(temp_gender)
|
||||
var/obscured = check_obscured_slots()
|
||||
var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
|
||||
if((obscured & ITEM_SLOT_ICLOTHING) && skipface)
|
||||
temp_gender = PLURAL
|
||||
return ..()
|
||||
|
||||
//clothing need special handling due to pairs of items, ie gloves vs a singular glove, shoes, ect.
|
||||
/obj/item/clothing/p_they(temp_gender)
|
||||
if(!temp_gender)
|
||||
@@ -411,6 +447,19 @@
|
||||
if(temp_gender != PLURAL)
|
||||
return "es"
|
||||
|
||||
/obj/item/clothing/p_themselves(temp_gender)
|
||||
if(!temp_gender)
|
||||
temp_gender = gender
|
||||
switch(temp_gender)
|
||||
if(FEMALE)
|
||||
return "herself"
|
||||
if(MALE)
|
||||
return "himself"
|
||||
if(PLURAL)
|
||||
return "themselves"
|
||||
else
|
||||
return "itself"
|
||||
|
||||
/datum/mind/p_they(temp_gender)
|
||||
return current?.p_they(temp_gender) || ..()
|
||||
|
||||
@@ -440,3 +489,6 @@
|
||||
|
||||
/datum/mind/p_es(temp_gender)
|
||||
return current?.p_es(temp_gender) || ..()
|
||||
|
||||
/datum/mind/p_themselves(temp_gender)
|
||||
return current?.p_themselves(temp_gender) || ..()
|
||||
|
||||
@@ -443,6 +443,16 @@
|
||||
)
|
||||
list_clear_nulls(.)
|
||||
|
||||
///Returns a list of all turfs that are adjacent to the center atom's turf, clear the list of nulls at the end.
|
||||
/proc/get_adjacent_turfs(atom/center)
|
||||
. = list(
|
||||
get_step(center, NORTH),
|
||||
get_step(center, SOUTH),
|
||||
get_step(center, EAST),
|
||||
get_step(center, WEST)
|
||||
)
|
||||
list_clear_nulls(.)
|
||||
|
||||
///Checks if the mob provided (must_be_alone) is alone in an area
|
||||
/proc/alone_in_area(area/the_area, mob/must_be_alone, check_type = /mob/living/carbon)
|
||||
var/area/our_area = get_area(the_area)
|
||||
|
||||
@@ -22,6 +22,7 @@ GLOBAL_LIST_EMPTY(string_lists)
|
||||
stack_trace("The baseturfs list of [baseturf_holder] at [baseturf_holder.x], [baseturf_holder.y], [baseturf_holder.x] is [length(values)], it should never be this long, investigate. I've set baseturfs to a flashing wall as a visual queue")
|
||||
baseturf_holder.ChangeTurf(/turf/closed/indestructible/baseturfs_ded, list(/turf/closed/indestructible/baseturfs_ded), flags = CHANGETURF_FORCEOP)
|
||||
return string_list(list(/turf/closed/indestructible/baseturfs_ded)) //I want this reported god damn it
|
||||
|
||||
return string_list(values)
|
||||
|
||||
/turf/closed/indestructible/baseturfs_ded
|
||||
|
||||
@@ -147,6 +147,8 @@ GLOBAL_LIST_EMPTY(areas)
|
||||
GLOBAL_LIST_EMPTY(sortedAreas)
|
||||
/// An association from typepath to area instance. Only includes areas with `unique` set.
|
||||
GLOBAL_LIST_EMPTY_TYPED(areas_by_type, /area)
|
||||
/// A list of player-created areas.
|
||||
GLOBAL_LIST_EMPTY_TYPED(custom_areas, /area)
|
||||
|
||||
GLOBAL_LIST_EMPTY(all_abstract_markers)
|
||||
|
||||
|
||||
@@ -88,6 +88,9 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_WAS_RENAMED" = TRAIT_WAS_RENAMED,
|
||||
"TRAIT_WEATHER_IMMUNE" = TRAIT_WEATHER_IMMUNE,
|
||||
),
|
||||
/area = list(
|
||||
"TRAIT_HAS_SHUTTLE_CONSTRUCTION_TURF" = TRAIT_HAS_SHUTTLE_CONSTRUCTION_TURF,
|
||||
),
|
||||
/datum/controller/subsystem/economy = list(
|
||||
"TRAIT_MARKET_CRASHING" = TRAIT_MARKET_CRASHING,
|
||||
),
|
||||
@@ -157,6 +160,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_ANTIMAGIC" = TRAIT_ANTIMAGIC,
|
||||
"TRAIT_ANTIMAGIC_NO_SELFBLOCK" = TRAIT_ANTIMAGIC_NO_SELFBLOCK,
|
||||
"TRAIT_ANXIOUS" = TRAIT_ANXIOUS,
|
||||
"TRAIT_ATTEMPTING_CHRISTENING" = TRAIT_ATTEMPTING_CHRISTENING,
|
||||
"TRAIT_BADDNA" = TRAIT_BADDNA,
|
||||
"TRAIT_BADTOUCH" = TRAIT_BADTOUCH,
|
||||
"TRAIT_BALD" = TRAIT_BALD,
|
||||
@@ -740,6 +744,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
|
||||
"TRAIT_IMMERSE_STOPPED" = TRAIT_IMMERSE_STOPPED,
|
||||
"TRAIT_LAVA_STOPPED" = TRAIT_LAVA_STOPPED,
|
||||
"TRAIT_NO_TERRAFORM" = TRAIT_NO_TERRAFORM,
|
||||
"TRAIT_SHUTTLE_CONSTRUCTION_TURF" = TRAIT_SHUTTLE_CONSTRUCTION_TURF,
|
||||
"TRAIT_SPINNING_WEB_TURF" = TRAIT_SPINNING_WEB_TURF,
|
||||
"TRAIT_TURF_IGNORE_SLIPPERY" = TRAIT_TURF_IGNORE_SLIPPERY,
|
||||
"TRAIT_TURF_IGNORE_SLOWDOWN" = TRAIT_TURF_IGNORE_SLOWDOWN,
|
||||
|
||||
@@ -494,3 +494,12 @@
|
||||
integer = FALSE
|
||||
default = 1
|
||||
min_val = 0.05
|
||||
|
||||
|
||||
//Custom Shuttles
|
||||
//Shuttle size limiter
|
||||
/datum/config_entry/number/max_shuttle_count
|
||||
default = 6
|
||||
|
||||
/datum/config_entry/number/max_shuttle_size
|
||||
default = 250
|
||||
|
||||
@@ -17,6 +17,8 @@ SUBSYSTEM_DEF(shuttle)
|
||||
var/list/mobile_docking_ports = list()
|
||||
/// A list of all the stationary docking ports.
|
||||
var/list/stationary_docking_ports = list()
|
||||
/// A list of all the custom shuttles.
|
||||
var/list/custom_shuttles = list()
|
||||
/// A list of all the beacons that can be docked to.
|
||||
var/list/beacon_list = list()
|
||||
/// A list of all the transit docking ports.
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
/datum/component/connect_containers/proc/set_tracked(atom/movable/new_tracked)
|
||||
if(tracked)
|
||||
UnregisterSignal(tracked, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING))
|
||||
unregister_signals(tracked.loc)
|
||||
unregister_signals(tracked)
|
||||
tracked = new_tracked
|
||||
if(!tracked)
|
||||
return
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/// Behaves similar to connect_loc_behalf, but hooks into signals on items in the user's inventory
|
||||
/datum/component/connect_inventory
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
|
||||
var/list/connections
|
||||
|
||||
var/mob/living/tracked
|
||||
|
||||
var/allowed_slots
|
||||
|
||||
/datum/component/connect_inventory/Initialize(mob/living/tracked, connections, allowed_slots = ALL)
|
||||
. = ..()
|
||||
if(!istype(tracked))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
src.connections = connections
|
||||
src.tracked = tracked
|
||||
src.allowed_slots = allowed_slots
|
||||
|
||||
/datum/component/connect_inventory/RegisterWithParent()
|
||||
RegisterSignal(tracked, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(on_equipped_item))
|
||||
RegisterSignal(tracked, COMSIG_QDELETING, PROC_REF(handle_tracked_qdel))
|
||||
update_signals()
|
||||
|
||||
/datum/component/connect_inventory/UnregisterFromParent()
|
||||
unregister_signals()
|
||||
UnregisterSignal(tracked, list(COMSIG_MOB_EQUIPPED_ITEM, COMSIG_MOB_UNEQUIPPED_ITEM))
|
||||
|
||||
/datum/component/connect_inventory/proc/handle_tracked_qdel()
|
||||
SIGNAL_HANDLER
|
||||
qdel(src)
|
||||
|
||||
/datum/component/connect_inventory/proc/update_signals()
|
||||
unregister_signals()
|
||||
|
||||
for(var/obj/item/item as anything in tracked.get_equipped_items(INCLUDE_POCKETS | INCLUDE_HELD))
|
||||
if(!(allowed_slots & tracked.get_slot_by_item(item)))
|
||||
continue
|
||||
RegisterSignal(item, COMSIG_ITEM_DROPPED, PROC_REF(on_unequipped_item))
|
||||
for(var/signal in connections)
|
||||
parent.RegisterSignal(item, signal, connections[signal])
|
||||
|
||||
/datum/component/connect_inventory/proc/unregister_signals()
|
||||
for(var/obj/item/item as anything in tracked.get_equipped_items(INCLUDE_POCKETS | INCLUDE_HELD))
|
||||
UnregisterSignal(item, COMSIG_ITEM_DROPPED)
|
||||
parent.UnregisterSignal(item, connections)
|
||||
|
||||
/datum/component/connect_inventory/proc/on_equipped_item(datum/source, obj/item/equipped, slot)
|
||||
SIGNAL_HANDLER
|
||||
if(!(allowed_slots & slot))
|
||||
return
|
||||
// This handler has to be registered on the component itself because users may have their own COMSIG_ITEM_DROPPED handler for the equipped item
|
||||
RegisterSignal(equipped, COMSIG_ITEM_DROPPED, PROC_REF(on_unequipped_item))
|
||||
for(var/signal in connections)
|
||||
parent.RegisterSignal(equipped, signal, connections[signal])
|
||||
|
||||
/datum/component/connect_inventory/proc/on_unequipped_item(obj/item/unequipped)
|
||||
SIGNAL_HANDLER
|
||||
UnregisterSignal(unequipped, COMSIG_ITEM_DROPPED)
|
||||
parent.UnregisterSignal(unequipped, connections)
|
||||
@@ -75,14 +75,13 @@
|
||||
turfs = list()
|
||||
return
|
||||
|
||||
if(ismovable(target.loc))
|
||||
var/loc_is_movable = ismovable(target.loc)
|
||||
|
||||
if(loc_is_movable)
|
||||
if(!works_in_containers)
|
||||
unregister_signals(old_loc, turfs)
|
||||
turfs = list()
|
||||
return
|
||||
//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))
|
||||
|
||||
//Only register/unregister turf signals if it's moved to a new turf.
|
||||
if(current_turf == get_turf(old_loc))
|
||||
@@ -91,6 +90,10 @@
|
||||
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])
|
||||
|
||||
@@ -78,3 +78,34 @@
|
||||
reqs = list(/obj/item/stack/sheet/bone = 1)
|
||||
time = 2 SECONDS
|
||||
category = CAT_TOOLS
|
||||
|
||||
/datum/crafting_recipe/shuttle_blueprints
|
||||
name = "Crude Shuttle Blueprints"
|
||||
result = /obj/item/shuttle_blueprints/crude
|
||||
reqs = list(
|
||||
/obj/item/paper = 1,
|
||||
/obj/item/toy/crayon = CRAFTING_INGREDIENT_USE,
|
||||
)
|
||||
steps = list(
|
||||
"You must use either a a blue crayon, a rainbow crayon, or a spray can.",
|
||||
"The crayon or spray can you use must have at least 10 uses remaining."
|
||||
)
|
||||
time = 10 SECONDS
|
||||
category = CAT_TOOLS
|
||||
|
||||
/datum/crafting_recipe/shuttle_blueprints/check_requirements(mob/user, list/collected_requirements)
|
||||
var/list/crayons = collected_requirements[/obj/item/toy/crayon]
|
||||
for(var/obj/item/toy/crayon/crayon as anything in crayons)
|
||||
if(!is_type_in_list(crayon, list(/obj/item/toy/crayon/blue, /obj/item/toy/crayon/rainbow, /obj/item/toy/crayon/spraycan)))
|
||||
continue
|
||||
if(!crayon.check_empty(user, 10))
|
||||
return TRUE
|
||||
|
||||
/datum/crafting_recipe/shuttle_blueprints/on_craft_completion(mob/user, atom/result)
|
||||
var/static/list/valid_types = list(/obj/item/toy/crayon/blue, /obj/item/toy/crayon/rainbow, /obj/item/toy/crayon/spraycan)
|
||||
for(var/valid_type in valid_types)
|
||||
var/obj/item/toy/crayon/crayon = locate(valid_type) in range(1)
|
||||
if(!crayon)
|
||||
continue
|
||||
if(crayon.use_charges(user, 10))
|
||||
return
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Container for data necessary to track custom areas.
|
||||
* Currently this is just the areas this area was created on top of, in case the area is used to create a custom shuttle.
|
||||
*/
|
||||
/datum/component/custom_area
|
||||
var/list/previous_areas = list()
|
||||
|
||||
/datum/component/custom_area/Initialize(...)
|
||||
if(!isarea(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
/datum/component/custom_area/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_AREA_TURF_ADDED, PROC_REF(on_turf_added))
|
||||
RegisterSignal(parent, COMSIG_AREA_TURF_REMOVED, PROC_REF(on_turf_removed))
|
||||
|
||||
/datum/component/custom_area/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_AREA_TURF_ADDED, COMSIG_AREA_TURF_REMOVED))
|
||||
|
||||
/datum/component/custom_area/proc/on_turf_added(area/source, turf/turf, area/old_area)
|
||||
previous_areas[turf] = old_area
|
||||
|
||||
/datum/component/custom_area/proc/on_turf_removed(area/source, turf/turf)
|
||||
previous_areas -= turf
|
||||
@@ -0,0 +1,55 @@
|
||||
/// Element used to specify that a lattice is part of an incomplete shuttle frame
|
||||
/datum/element/shuttle_construction_lattice
|
||||
element_flags = ELEMENT_DETACH_ON_HOST_DESTROY
|
||||
var/list/lattices_by_turf = list()
|
||||
|
||||
/datum/element/shuttle_construction_lattice/Attach(obj/structure/lattice/target)
|
||||
. = ..()
|
||||
if(!istype(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
var/turf/target_turf = target.loc
|
||||
if(!istype(target_turf))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
target_turf.AddElementTrait(TRAIT_SHUTTLE_CONSTRUCTION_TURF, REF(target), eletype = /datum/element/shuttle_construction_turf)
|
||||
lattices_by_turf[target_turf] = target
|
||||
RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examined))
|
||||
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
||||
RegisterSignal(target, COMSIG_LATTICE_PRE_REPLACE_WITH_CATWALK, PROC_REF(on_replacing_with_catwalk))
|
||||
RegisterSignal(target_turf, COMSIG_TURF_ADDED_TO_SHUTTLE, PROC_REF(on_turf_added_to_shuttle))
|
||||
|
||||
/datum/element/shuttle_construction_lattice/Detach(obj/source, ...)
|
||||
. = ..()
|
||||
var/turf/source_turf = source.loc
|
||||
if(istype(source_turf))
|
||||
REMOVE_TRAIT(source_turf, TRAIT_SHUTTLE_CONSTRUCTION_TURF, REF(source))
|
||||
lattices_by_turf -= source_turf
|
||||
UnregisterSignal(source_turf, COMSIG_TURF_ADDED_TO_SHUTTLE)
|
||||
UnregisterSignal(source, list(COMSIG_ATOM_EXAMINE, COMSIG_MOVABLE_MOVED, COMSIG_LATTICE_PRE_REPLACE_WITH_CATWALK))
|
||||
|
||||
/datum/element/shuttle_construction_lattice/proc/on_examined(obj/source, mob/user, list/examine_list)
|
||||
SIGNAL_HANDLER
|
||||
examine_list += span_notice("Cutting this [source.name] will <i>ruin the treatment that makes it suitable for shuttle construction</i>.")
|
||||
|
||||
/datum/element/shuttle_construction_lattice/proc/on_moved(obj/source, atom/old_loc)
|
||||
SIGNAL_HANDLER
|
||||
var/trait_source = REF(source)
|
||||
if(isturf(old_loc))
|
||||
REMOVE_TRAIT(old_loc, TRAIT_SHUTTLE_CONSTRUCTION_TURF, trait_source)
|
||||
UnregisterSignal(old_loc, COMSIG_TURF_ADDED_TO_SHUTTLE)
|
||||
lattices_by_turf -= old_loc
|
||||
var/turf/new_turf = source.loc
|
||||
if(istype(new_turf))
|
||||
new_turf.AddElementTrait(TRAIT_SHUTTLE_CONSTRUCTION_TURF, trait_source, /datum/element/shuttle_construction_turf)
|
||||
RegisterSignal(new_turf, COMSIG_TURF_ADDED_TO_SHUTTLE, PROC_REF(on_turf_added_to_shuttle))
|
||||
lattices_by_turf[new_turf] = source
|
||||
|
||||
/datum/element/shuttle_construction_lattice/proc/on_replacing_with_catwalk(obj/source, list/callbacks)
|
||||
SIGNAL_HANDLER
|
||||
callbacks += CALLBACK(src, PROC_REF(register_catwalk))
|
||||
|
||||
/datum/element/shuttle_construction_lattice/proc/register_catwalk(obj/structure/lattice/catwalk/new_catwalk)
|
||||
new_catwalk.AddElement(/datum/element/shuttle_construction_lattice)
|
||||
|
||||
/datum/element/shuttle_construction_lattice/proc/on_turf_added_to_shuttle(turf/source)
|
||||
var/obj/structure/lattice/turf_lattice = lattices_by_turf[source]
|
||||
turf_lattice?.RemoveElement(/datum/element/shuttle_construction_lattice)
|
||||
@@ -0,0 +1,43 @@
|
||||
/// Element used to track the conditions for a turf being part of an incomplete shuttle frame
|
||||
/datum/element/shuttle_construction_turf
|
||||
element_flags = ELEMENT_DETACH_ON_HOST_DESTROY
|
||||
|
||||
/datum/element/shuttle_construction_turf/Attach(turf/target)
|
||||
. = ..()
|
||||
if(!istype(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
RegisterSignal(target, COMSIG_TURF_CHANGE, PROC_REF(pre_turf_changed))
|
||||
RegisterSignal(target, COMSIG_TURF_ATTEMPT_LATTICE_REPLACEMENT, PROC_REF(pre_lattice_replacement))
|
||||
RegisterSignal(target, COMSIG_TURF_ADDED_TO_SHUTTLE, PROC_REF(on_turF_added_to_shuttle))
|
||||
ADD_TRAIT((get_area(target)), TRAIT_HAS_SHUTTLE_CONSTRUCTION_TURF, REF(target))
|
||||
|
||||
/datum/element/shuttle_construction_turf/Detach(turf/source, ...)
|
||||
. = ..()
|
||||
UnregisterSignal(source, list(COMSIG_TURF_CHANGE, COMSIG_TURF_ATTEMPT_LATTICE_REPLACEMENT, COMSIG_TURF_ADDED_TO_SHUTTLE, SIGNAL_REMOVETRAIT(TRAIT_SHUTTLE_CONSTRUCTION_TURF)))
|
||||
REMOVE_TRAIT((get_area(source)), TRAIT_HAS_SHUTTLE_CONSTRUCTION_TURF, REF(source))
|
||||
|
||||
///Changing or destroying the turf detaches the element, also we need to reapply the traits since they don't get passed down.
|
||||
/datum/element/shuttle_construction_turf/proc/pre_turf_changed(turf/source, path, list/new_baseturfs, flags, list/post_change_callbacks)
|
||||
SIGNAL_HANDLER
|
||||
var/list/old_trait_sources = GET_TRAIT_SOURCES(source, TRAIT_SHUTTLE_CONSTRUCTION_TURF)
|
||||
old_trait_sources = old_trait_sources.Copy()
|
||||
post_change_callbacks += CALLBACK(src, PROC_REF(post_turf_changed), old_trait_sources)
|
||||
|
||||
/datum/element/shuttle_construction_turf/proc/pre_lattice_replacement(turf/source, list/post_successful_replacement_callbacks)
|
||||
SIGNAL_HANDLER
|
||||
post_successful_replacement_callbacks += CALLBACK(src, PROC_REF(register_lattice))
|
||||
|
||||
/datum/element/shuttle_construction_turf/proc/post_turf_changed(list/trait_sources, turf/new_turf)
|
||||
if(isfloorturf(new_turf) || iswallturf(new_turf))
|
||||
trait_sources |= ELEMENT_TRAIT(type)
|
||||
else
|
||||
trait_sources -= ELEMENT_TRAIT(type)
|
||||
if(length(trait_sources))
|
||||
for(var/source in trait_sources)
|
||||
new_turf.AddElementTrait(TRAIT_SHUTTLE_CONSTRUCTION_TURF, source, type)
|
||||
|
||||
/datum/element/shuttle_construction_turf/proc/register_lattice(obj/structure/lattice/new_lattice)
|
||||
new_lattice.AddElement(/datum/element/shuttle_construction_lattice)
|
||||
|
||||
/datum/element/shuttle_construction_turf/proc/on_turF_added_to_shuttle(turf/source)
|
||||
REMOVE_TRAIT(source, TRAIT_SHUTTLE_CONSTRUCTION_TURF, ELEMENT_TRAIT(type))
|
||||
@@ -53,12 +53,6 @@
|
||||
who_can_purchase = list(ACCESS_CAPTAIN, ACCESS_CE)
|
||||
occupancy_limit = "Flexible"
|
||||
|
||||
/datum/map_template/shuttle/emergency/construction/post_load()
|
||||
. = ..()
|
||||
//enable buying engines from cargo
|
||||
var/datum/supply_pack/P = SSshuttle.supply_packs[/datum/supply_pack/engineering/shuttle_engine]
|
||||
P.special_enabled = TRUE
|
||||
|
||||
/datum/map_template/shuttle/emergency/asteroid
|
||||
suffix = "asteroid"
|
||||
name = "Asteroid Station Emergency Shuttle"
|
||||
|
||||
@@ -355,6 +355,8 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
//just for sanity sake cause why not
|
||||
if(!isnull(GLOB.areas))
|
||||
GLOB.areas -= src
|
||||
if(!isnull(GLOB.custom_areas))
|
||||
GLOB.custom_areas -= src
|
||||
//machinery cleanup
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_NULL(alarm_manager)
|
||||
|
||||
@@ -21,10 +21,17 @@
|
||||
. = ..()
|
||||
if(ispath(added_layer, /turf/open/floor/plating))
|
||||
new_baseturfs.Add(/turf/baseturf_skipover/shuttle)
|
||||
. |= CHANGETURF_GENERATE_SHUTTLE_CEILING
|
||||
else if(ispath(new_baseturfs[1], /turf/open/floor/plating))
|
||||
new_baseturfs.Insert(1, /turf/baseturf_skipover/shuttle)
|
||||
. |= CHANGETURF_GENERATE_SHUTTLE_CEILING
|
||||
|
||||
////////////////////////////Multi-area shuttles////////////////////////////
|
||||
////////////////////////////Custom Shuttles////////////////////////////
|
||||
|
||||
/area/shuttle/custom
|
||||
requires_power = TRUE
|
||||
|
||||
////////////////////////////Multi-area shuttles//////////////////////////////
|
||||
|
||||
////////////////////////////Syndicate infiltrator////////////////////////////
|
||||
|
||||
|
||||
@@ -650,3 +650,24 @@
|
||||
/obj/item/circuitboard/computer/exodrone_console
|
||||
name = "Exploration Drone Control Console"
|
||||
build_path = /obj/machinery/computer/exodrone_control_console
|
||||
|
||||
/obj/item/circuitboard/computer/shuttle
|
||||
var/shuttle_id
|
||||
|
||||
/obj/item/circuitboard/computer/shuttle/configure_machine(obj/machinery/machine)
|
||||
var/obj/docking_port/mobile/custom/shuttle = shuttle_id ? SSshuttle.getShuttle(shuttle_id) : SSshuttle.get_containing_shuttle(machine)
|
||||
if(!shuttle)
|
||||
var/on_shuttle_frame = HAS_TRAIT((get_turf(machine)), TRAIT_SHUTTLE_CONSTRUCTION_TURF)
|
||||
machine.say(on_shuttle_frame ? "Console will automatically link on shuttle completion." : "No shuttle available for linking.")
|
||||
else if(!istype(shuttle))
|
||||
machine.say("Cannot link to this kind of shuttle!")
|
||||
else
|
||||
machine.connect_to_shuttle(TRUE, shuttle)
|
||||
|
||||
/obj/item/circuitboard/computer/shuttle/flight_control
|
||||
name = "Shuttle Flight Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/custom_shuttle
|
||||
|
||||
/obj/item/circuitboard/computer/shuttle/docker
|
||||
name = "Shuttle Navigation Computer (Computer Board)"
|
||||
build_path = /obj/machinery/computer/camera_advanced/shuttle_docker/custom
|
||||
|
||||
@@ -251,10 +251,11 @@
|
||||
///Apparatus to allow Engineering/Sabo borgs to manipulate any material sheets.
|
||||
/obj/item/borg/apparatus/sheet_manipulator
|
||||
name = "material manipulation apparatus"
|
||||
desc = "An apparatus for carrying, deploying, and manipulating sheets of material. The device can also carry custom floor tiles."
|
||||
desc = "An apparatus for carrying, deploying, and manipulating sheets of material. The device can also carry custom floor tiles and shuttle frame rods."
|
||||
icon_state = "borg_stack_apparatus"
|
||||
storable = list(/obj/item/stack/sheet,
|
||||
/obj/item/stack/tile)
|
||||
/obj/item/stack/tile,
|
||||
/obj/item/stack/rods/shuttle)
|
||||
|
||||
/obj/item/borg/apparatus/sheet_manipulator/Initialize(mapload)
|
||||
update_appearance()
|
||||
|
||||
@@ -803,6 +803,16 @@
|
||||
|
||||
items_to_add = list(/obj/item/storage/bag/plants/cyborg, /obj/item/borg/cyborg_omnitool/botany, /obj/item/plant_analyzer)
|
||||
|
||||
/obj/item/borg/upgrade/shuttle_blueprints
|
||||
name = "Engineering Cyborg Shuttle Blueprint Database"
|
||||
desc = "An upgrade to the engineering model cyborg allowing for the construction and expansion of shuttles."
|
||||
icon_state = "module_engineer"
|
||||
require_model = TRUE
|
||||
model_type = list(/obj/item/robot_model/engineering, /obj/item/robot_model/saboteur)
|
||||
model_flags = BORG_MODEL_ENGINEERING
|
||||
|
||||
items_to_add = list(/obj/item/shuttle_blueprints/borg)
|
||||
|
||||
|
||||
///This isn't an upgrade or part of the same path, but I'm gonna just stick it here because it's a tool used on cyborgs.
|
||||
//A reusable tool that can bring borgs back to life. They gotta be repaired first, though.
|
||||
|
||||
@@ -145,3 +145,22 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
|
||||
|
||||
/obj/item/stack/rods/lava/thirty
|
||||
amount = 30
|
||||
|
||||
/obj/item/stack/rods/shuttle
|
||||
name = "shuttle frame rods"
|
||||
desc = "Treated, specialized iron rods suitable for the construction of shuttle frames or the expansion of existing shuttles."
|
||||
singular_name = "shuttle frame rod"
|
||||
mats_per_unit = list(/datum/material/iron=HALF_SHEET_MATERIAL_AMOUNT, /datum/material/titanium=SMALL_MATERIAL_AMOUNT)
|
||||
merge_type = /obj/item/stack/rods/shuttle
|
||||
|
||||
/obj/item/stack/rods/shuttle/five
|
||||
amount = 5
|
||||
|
||||
/obj/item/stack/rods/shuttle/ten
|
||||
amount = 10
|
||||
|
||||
/obj/item/stack/rods/shuttle/twentyfive
|
||||
amount = 25
|
||||
|
||||
/obj/item/stack/rods/shuttle/fifty
|
||||
amount = 50
|
||||
|
||||
@@ -296,6 +296,26 @@ GLOBAL_LIST_INIT(titanium_recipes, list ( \
|
||||
. = ..()
|
||||
. += GLOB.titanium_recipes
|
||||
|
||||
/obj/item/stack/sheet/mineral/titanium/attackby(obj/item/W, mob/user, params)
|
||||
add_fingerprint(user)
|
||||
if(istype(W, /obj/item/stack/rods))
|
||||
var/obj/item/stack/rods/old_rods = W
|
||||
if(old_rods.merge_type != /obj/item/stack/rods)
|
||||
to_chat(user, span_warning("You can't craft shuttle frame rods with this type of rod!"))
|
||||
if (old_rods.get_amount() >= 5 && get_amount() >= 1)
|
||||
var/obj/item/stack/rods/shuttle/five/new_rods = new (get_turf(user))
|
||||
if(!QDELETED(new_rods))
|
||||
new_rods.add_fingerprint(user)
|
||||
var/replace = user.get_inactive_held_item() == src
|
||||
old_rods.use(5)
|
||||
use(1)
|
||||
if(QDELETED(src) && replace && !QDELETED(new_rods))
|
||||
user.put_in_hands(new_rods)
|
||||
else
|
||||
to_chat(user, span_warning("You need five rods and one sheet of titanium to make shuttle frame rods!"))
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/item/stack/sheet/mineral/titanium/fifty
|
||||
amount = 50
|
||||
|
||||
|
||||
@@ -76,16 +76,14 @@
|
||||
/obj/structure/lattice/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, list/rcd_data)
|
||||
if(rcd_data["[RCD_DESIGN_MODE]"] == RCD_TURF)
|
||||
var/design_structure = rcd_data["[RCD_DESIGN_PATH]"]
|
||||
if(design_structure == /turf/open/floor/plating)
|
||||
if(design_structure == /turf/open/floor/plating/rcd)
|
||||
var/turf/T = src.loc
|
||||
if(isgroundlessturf(T))
|
||||
T.place_on_top(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
|
||||
qdel(src)
|
||||
return TRUE
|
||||
if(design_structure == /obj/structure/lattice/catwalk)
|
||||
var/turf/turf = loc
|
||||
qdel(src)
|
||||
new /obj/structure/lattice/catwalk(turf)
|
||||
replace_with_catwalk()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -93,6 +91,15 @@
|
||||
if(current_size >= STAGE_FOUR)
|
||||
deconstruct()
|
||||
|
||||
/obj/structure/lattice/proc/replace_with_catwalk()
|
||||
var/list/post_replacement_callbacks = list()
|
||||
SEND_SIGNAL(src, COMSIG_LATTICE_PRE_REPLACE_WITH_CATWALK, post_replacement_callbacks)
|
||||
var/turf/turf = loc
|
||||
qdel(src)
|
||||
var/new_catwalk = new /obj/structure/lattice/catwalk(turf)
|
||||
for(var/datum/callback/callback as anything in post_replacement_callbacks)
|
||||
callback.Invoke(new_catwalk)
|
||||
|
||||
/obj/structure/lattice/catwalk
|
||||
name = "catwalk"
|
||||
desc = "A catwalk for easier EVA maneuvering and cable placement."
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
///The mobile ship we are connected to.
|
||||
var/datum/weakref/connected_ship_ref
|
||||
|
||||
var/static/list/connections = list(COMSIG_TURF_ADDED_TO_SHUTTLE = PROC_REF(on_turf_added_to_shuttle))
|
||||
|
||||
/datum/armor/power_shuttle_engine
|
||||
melee = 100
|
||||
bullet = 10
|
||||
@@ -35,6 +37,7 @@
|
||||
|
||||
/obj/machinery/power/shuttle_engine/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/simple_rotation)
|
||||
register_context()
|
||||
|
||||
/obj/machinery/power/shuttle_engine/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
|
||||
@@ -83,6 +86,7 @@
|
||||
port.engine_list -= src
|
||||
port.current_engine_power -= initial(engine_power)
|
||||
connected_ship_ref = null
|
||||
RemoveElement(/datum/element/connect_loc, connections)
|
||||
|
||||
//Ugh this is a lot of copypasta from emitters, welding need some boilerplate reduction
|
||||
/obj/machinery/power/shuttle_engine/can_be_unfasten_wrench(mob/user, silent)
|
||||
@@ -97,11 +101,17 @@
|
||||
if(. == SUCCESSFUL_UNFASTEN)
|
||||
if(anchored)
|
||||
connect_to_shuttle(port = SSshuttle.get_containing_shuttle(src)) //connect to a new ship, if needed
|
||||
if(!connected_ship_ref?.resolve())
|
||||
AddElement(/datum/element/connect_loc, connections)
|
||||
engine_state = ENGINE_WRENCHED
|
||||
else
|
||||
unsync_ship() //not part of the ship anymore
|
||||
engine_state = ENGINE_UNWRENCHED
|
||||
|
||||
/obj/machinery/power/shuttle_engine/proc/on_turf_added_to_shuttle(turf/source, obj/docking_port/mobile/port)
|
||||
SIGNAL_HANDLER
|
||||
connect_to_shuttle(port = port)
|
||||
|
||||
/obj/machinery/power/shuttle_engine/wrench_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
default_unfasten_wrench(user, tool)
|
||||
|
||||
@@ -171,3 +171,13 @@
|
||||
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)
|
||||
|
||||
@@ -128,6 +128,16 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
|
||||
if(!(flags & CHANGETURF_DEFER_CHANGE))
|
||||
new_turf.AfterChange(flags, old_type)
|
||||
|
||||
if(flags & CHANGETURF_GENERATE_SHUTTLE_CEILING)
|
||||
var/turf/above = get_step_multiz(src, UP)
|
||||
if(above)
|
||||
if(!(istype(above, /turf/open/floor/engine/hull/ceiling) || above.depth_to_find_baseturf(/turf/open/floor/engine/hull/ceiling)))
|
||||
if(istype(above, /turf/open/openspace) || istype(above, /turf/open/space/openspace))
|
||||
above.place_on_top(/turf/open/floor/engine/hull/ceiling)
|
||||
else
|
||||
above.stack_ontop_of_baseturf(/turf/open/openspace, /turf/open/floor/engine/hull/ceiling)
|
||||
above.stack_ontop_of_baseturf(/turf/open/space/openspace, /turf/open/floor/engine/hull/ceiling)
|
||||
|
||||
new_turf.blueprint_data = old_bp
|
||||
new_turf.rcd_memory = old_rcd_memory
|
||||
new_turf.explosion_throw_details = old_explosion_throw_details
|
||||
@@ -284,8 +294,12 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
|
||||
/// Attempts to replace a tile with lattice. Amount is the amount of tiles to scrape away.
|
||||
/turf/proc/attempt_lattice_replacement(amount = 2)
|
||||
if(lattice_underneath)
|
||||
var/list/successful_replacement_callbacks = list()
|
||||
SEND_SIGNAL(src, COMSIG_TURF_ATTEMPT_LATTICE_REPLACEMENT, successful_replacement_callbacks)
|
||||
var/turf/new_turf = ScrapeAway(amount, flags = CHANGETURF_INHERIT_AIR)
|
||||
if(!istype(new_turf, /turf/open/floor))
|
||||
new /obj/structure/lattice(src)
|
||||
var/new_lattice = new /obj/structure/lattice(src)
|
||||
for(var/datum/callback/callback as anything in successful_replacement_callbacks)
|
||||
callback.Invoke(new_lattice)
|
||||
else
|
||||
ScrapeAway(amount, flags = CHANGETURF_INHERIT_AIR)
|
||||
|
||||
@@ -434,10 +434,9 @@
|
||||
|
||||
if(catwalk_bait)
|
||||
if(used_rods.use(1))
|
||||
qdel(catwalk_bait)
|
||||
to_chat(user, span_notice("You construct a catwalk."))
|
||||
playsound(src, 'sound/items/weapons/genhit.ogg', 50, TRUE)
|
||||
new /obj/structure/lattice/catwalk(src)
|
||||
catwalk_bait.replace_with_catwalk()
|
||||
else
|
||||
to_chat(user, span_warning("You need two rods to build a catwalk!"))
|
||||
return
|
||||
@@ -445,7 +444,9 @@
|
||||
if(used_rods.use(1))
|
||||
to_chat(user, span_notice("You construct a lattice."))
|
||||
playsound(src, 'sound/items/weapons/genhit.ogg', 50, TRUE)
|
||||
new /obj/structure/lattice(src)
|
||||
var/obj/structure/lattice/new_lattice = new (src)
|
||||
if(istype(used_rods, /obj/item/stack/rods/shuttle) && !istype(loc, /area/shuttle))
|
||||
new_lattice.AddElement(/datum/element/shuttle_construction_lattice)
|
||||
else
|
||||
to_chat(user, span_warning("You need one rod to build a lattice."))
|
||||
|
||||
@@ -462,6 +463,8 @@
|
||||
|
||||
playsound(src, 'sound/items/weapons/genhit.ogg', 50, TRUE)
|
||||
var/turf/open/floor/plating/new_plating = place_on_top(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
|
||||
if(istype(loc, /area/shuttle))
|
||||
new_plating.insert_baseturf(turf_type = /turf/baseturf_skipover/shuttle)
|
||||
if(lattice)
|
||||
qdel(lattice)
|
||||
else
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
/turf/open/floor/engine/hull/ceiling
|
||||
name = "shuttle ceiling plating"
|
||||
var/old_turf_type
|
||||
|
||||
/turf/open/floor/engine/hull/ceiling/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -20,10 +19,6 @@
|
||||
///datum/unit_test/mapping_nearstation_test.dm SHOULD fail this case automatically
|
||||
//this is just here so the mapper responsible can easily see where the issues are directly on the map.
|
||||
|
||||
/turf/open/floor/engine/hull/ceiling/AfterChange(flags, oldType)
|
||||
. = ..()
|
||||
old_turf_type = oldType
|
||||
|
||||
/turf/open/floor/engine/hull/reinforced
|
||||
name = "exterior reinforced hull plating"
|
||||
desc = "Extremely sturdy exterior hull plating that separates you from the uncaring vacuum of space."
|
||||
|
||||
@@ -244,6 +244,9 @@ GLOBAL_LIST_EMPTY(station_turfs)
|
||||
old_area.turfs_to_uncontain_by_zlevel[z] += src
|
||||
new_area.turfs_by_zlevel[z] += src
|
||||
new_area.contents += src
|
||||
SEND_SIGNAL(src, COMSIG_TURF_AREA_CHANGED, old_area)
|
||||
SEND_SIGNAL(new_area, COMSIG_AREA_TURF_ADDED, src, old_area)
|
||||
SEND_SIGNAL(old_area, COMSIG_AREA_TURF_REMOVED, src, new_area)
|
||||
|
||||
//changes to make after turf has moved
|
||||
on_change_area(old_area, new_area)
|
||||
|
||||
@@ -366,3 +366,16 @@
|
||||
desc = "Many people consider mice to be vermin, or dirty lab animals for experimentation, or a culinary delicacy. That's why we're not asking any questions, here."
|
||||
cost = PAYCHECK_CREW * 1.5
|
||||
contains = list(/obj/item/pet_carrier/small/mouse)
|
||||
|
||||
/datum/supply_pack/goody/shuttle_construction_kit
|
||||
name = "Shuttle Construction Starter Kit"
|
||||
desc = "Contains a set of shuttle blueprints, and the circuitboards necessary for constructing your own shuttle. \
|
||||
Well at least the ones you can't source yourself without Science's help."
|
||||
cost = PAYCHECK_COMMAND * 12 //You assistants with shipwrighting ambitions can do a couple bounties, can't you?
|
||||
access_view = ACCESS_AUX_BASE //Engineers have it, QM can give it to whoever, and scientists can just research the tech.
|
||||
contains = list(
|
||||
/obj/item/shuttle_blueprints,
|
||||
/obj/item/circuitboard/computer/shuttle/flight_control,
|
||||
/obj/item/circuitboard/computer/shuttle/docker,
|
||||
/obj/item/circuitboard/machine/engine/propulsion = 2,
|
||||
)
|
||||
|
||||
@@ -106,7 +106,6 @@
|
||||
contains = list(/obj/machinery/power/shuttle_engine/propulsion/burst/cargo)
|
||||
crate_name = "shuttle engine crate"
|
||||
crate_type = /obj/structure/closet/crate/secure/engineering
|
||||
special = TRUE
|
||||
|
||||
/datum/supply_pack/engineering/tools
|
||||
name = "Toolbox Crate"
|
||||
|
||||
@@ -107,6 +107,8 @@
|
||||
var/image_layer = MOB_LAYER
|
||||
/// The plane of the image
|
||||
var/image_plane = GAME_PLANE
|
||||
/// Should this image holder persist if there are no seers for it?
|
||||
var/persist_without_seers = FALSE
|
||||
|
||||
/obj/effect/client_image_holder/Initialize(mapload, list/mobs_which_see_us)
|
||||
. = ..()
|
||||
@@ -121,10 +123,7 @@
|
||||
|
||||
who_sees_us = list()
|
||||
for(var/mob/seer as anything in mobs_which_see_us)
|
||||
RegisterSignal(seer, COMSIG_MOB_LOGIN, PROC_REF(show_image_to))
|
||||
RegisterSignal(seer, COMSIG_QDELETING, PROC_REF(remove_seer))
|
||||
who_sees_us += seer
|
||||
show_image_to(seer)
|
||||
add_seer(seer)
|
||||
|
||||
/obj/effect/client_image_holder/Destroy(force)
|
||||
if(shown_image)
|
||||
@@ -141,6 +140,12 @@
|
||||
return
|
||||
SET_PLANE(shown_image, PLANE_TO_TRUE(shown_image.plane), new_turf)
|
||||
|
||||
/obj/effect/client_image_holder/proc/add_seer(mob/new_seer)
|
||||
RegisterSignal(new_seer, COMSIG_MOB_LOGIN, PROC_REF(show_image_to))
|
||||
RegisterSignal(new_seer, COMSIG_QDELETING, PROC_REF(remove_seer))
|
||||
who_sees_us += new_seer
|
||||
show_image_to(new_seer)
|
||||
|
||||
/// Signal proc to clean up references if people who see us are deleted.
|
||||
/obj/effect/client_image_holder/proc/remove_seer(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
@@ -150,7 +155,7 @@
|
||||
who_sees_us -= source
|
||||
|
||||
// No reason to exist, anymore
|
||||
if(!QDELETED(src) && !length(who_sees_us))
|
||||
if(!QDELETED(src) && !length(who_sees_us) && !persist_without_seers)
|
||||
qdel(src)
|
||||
|
||||
/// Generates the image which we take on.
|
||||
|
||||
@@ -395,3 +395,19 @@
|
||||
RND_CATEGORY_COMPUTER + RND_SUBCATEGORY_COMPUTER_RECORDS
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_SERVICE
|
||||
|
||||
/datum/design/board/shuttle
|
||||
category = list("Computer Boards", "Shuttle Machinery")
|
||||
departmental_flags = DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_CARGO
|
||||
|
||||
/datum/design/board/shuttle/flight_control
|
||||
name = "Computer Design (Shuttle Flight Controls)"
|
||||
desc = "Allows for the construction of circuit boards used to build a console that enables shuttle flight"
|
||||
id = "shuttle_control"
|
||||
build_path = /obj/item/circuitboard/computer/shuttle/flight_control
|
||||
|
||||
/datum/design/board/shuttle/shuttle_docker
|
||||
name = "Computer Design (Shuttle Navigation Computer)"
|
||||
desc = "Allows for the construction of circuit boards used to build a console that enables the targetting of custom flight locations"
|
||||
id = "shuttle_docker"
|
||||
build_path = /obj/item/circuitboard/computer/shuttle/docker
|
||||
|
||||
@@ -1357,3 +1357,13 @@
|
||||
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_CARGO
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_ENGINEERING
|
||||
|
||||
/datum/design/board/propulsion_engine
|
||||
name = "Propulsion Engine Board"
|
||||
desc = "The circuit for a propulsion engine."
|
||||
id = "propulsion_engine"
|
||||
build_path = /obj/item/circuitboard/machine/engine/propulsion
|
||||
category = list(
|
||||
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_ENGINEERING
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING
|
||||
|
||||
@@ -1705,6 +1705,20 @@
|
||||
RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_SERVICE
|
||||
)
|
||||
|
||||
/datum/design/borg_upgrade_shuttle_blueprints
|
||||
name = "Engineering Shuttle Blueprints"
|
||||
id = "borg_upgrade_engineering_shuttle_blueprints"
|
||||
build_type = MECHFAB
|
||||
build_path = /obj/item/borg/upgrade/shuttle_blueprints
|
||||
materials = list(
|
||||
/datum/material/iron = SHEET_MATERIAL_AMOUNT*5,
|
||||
/datum/material/glass = SHEET_MATERIAL_AMOUNT*2.5,
|
||||
)
|
||||
construction_time = 4 SECONDS
|
||||
category = list(
|
||||
RND_CATEGORY_MECHFAB_CYBORG_MODULES + RND_SUBCATEGORY_MECHFAB_CYBORG_MODULES_ENGINEERING
|
||||
)
|
||||
|
||||
/datum/design/borg_upgrade_expand
|
||||
name = "Expand Module"
|
||||
id = "borg_upgrade_expand"
|
||||
|
||||
@@ -1116,6 +1116,17 @@
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_CARGO
|
||||
|
||||
/datum/design/shuttle_rods
|
||||
name = "Shuttle Frame Rods"
|
||||
id = "shuttlerods"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/iron =HALF_SHEET_MATERIAL_AMOUNT, /datum/material/titanium = SMALL_MATERIAL_AMOUNT)
|
||||
build_path = /obj/item/stack/rods/shuttle
|
||||
category = list(
|
||||
RND_CATEGORY_CONSTRUCTION + RND_SUBCATEGORY_CONSTRUCTION_MATERIALS
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_SCIENCE | DEPARTMENT_BITFLAG_ENGINEERING
|
||||
|
||||
// Experimental designs
|
||||
|
||||
/datum/design/polymorph_belt
|
||||
|
||||
@@ -425,3 +425,13 @@
|
||||
RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_ENGINEERING_ADVANCED
|
||||
)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
|
||||
|
||||
/datum/design/shuttle_blueprints
|
||||
name = "Shuttle Blueprints"
|
||||
desc = "Blueprints suitable for constructing shuttles"
|
||||
id = "shuttle_blueprints"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/plastic = HALF_SHEET_MATERIAL_AMOUNT)
|
||||
build_path = /obj/item/shuttle_blueprints
|
||||
category = list(RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_ENGINEERING)
|
||||
departmental_flags = DEPARTMENT_BITFLAG_CARGO | DEPARTMENT_BITFLAG_ENGINEERING | DEPARTMENT_BITFLAG_SCIENCE
|
||||
|
||||
@@ -182,6 +182,22 @@
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS)
|
||||
announce_channels = list(RADIO_CHANNEL_ENGINEERING)
|
||||
|
||||
/datum/techweb_node/shuttle_engineering
|
||||
id = TECHWEB_NODE_SHUTTLE_ENG
|
||||
display_name = "Shuttle Engineering"
|
||||
description = "Materials and equipment for constructing shuttles"
|
||||
prereq_ids = list(TECHWEB_NODE_ENERGY_MANIPULATION, TECHWEB_NODE_APPLIED_BLUESPACE)
|
||||
design_ids = list(
|
||||
"borg_upgrade_engineering_shuttle_blueprints",
|
||||
"propulsion_engine",
|
||||
"shuttle_blueprints",
|
||||
"shuttle_control",
|
||||
"shuttle_docker",
|
||||
"shuttlerods",
|
||||
)
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS)
|
||||
announce_channels = list(RADIO_CHANNEL_ENGINEERING, RADIO_CHANNEL_SCIENCE, RADIO_CHANNEL_SUPPLY)
|
||||
|
||||
/datum/techweb_node/holographics
|
||||
id = TECHWEB_NODE_HOLOGRAPHICS
|
||||
display_name = "Holographics"
|
||||
|
||||
@@ -56,7 +56,12 @@
|
||||
///List of shuttle events that can run or are running
|
||||
var/list/datum/shuttle_event/event_list = list()
|
||||
|
||||
/obj/docking_port/mobile/Initialize(mapload)
|
||||
var/list/underlying_areas_by_turf = list()
|
||||
|
||||
///How many turfs this shuttle has. Used to check against max shuttle size when expanding expandable shuttles.
|
||||
var/turf_count = 0
|
||||
|
||||
/obj/docking_port/mobile/Initialize(mapload, list/areas)
|
||||
. = ..()
|
||||
|
||||
if(!shuttle_id)
|
||||
@@ -71,12 +76,17 @@
|
||||
shuttle_id = "[tmp_id]_[counter]"
|
||||
name = "[tmp_name] [counter]"
|
||||
|
||||
var/list/all_turfs = return_ordered_turfs(x, y, z, dir)
|
||||
for(var/i in 1 to all_turfs.len)
|
||||
var/turf/curT = all_turfs[i]
|
||||
var/area/cur_area = curT.loc
|
||||
if(istype(cur_area, area_type))
|
||||
shuttle_areas[cur_area] = TRUE
|
||||
if(areas)
|
||||
for(var/area/area as anything in areas)
|
||||
shuttle_areas[area] = TRUE
|
||||
else
|
||||
var/list/all_turfs = return_ordered_turfs(x, y, z, dir)
|
||||
for(var/i in 1 to all_turfs.len)
|
||||
var/turf/curT = all_turfs[i]
|
||||
var/area/cur_area = curT.loc
|
||||
if(istype(cur_area, area_type))
|
||||
turf_count++
|
||||
shuttle_areas[cur_area] = TRUE
|
||||
|
||||
#ifdef TESTING
|
||||
highlight("#0f0")
|
||||
@@ -111,28 +121,28 @@
|
||||
if(!length(shuttle_areas))
|
||||
CRASH("Attempted to calculate a docking port's information without a template before it was assigned any areas!")
|
||||
// no template given, use shuttle_areas to calculate width and height
|
||||
var/min_x = -1
|
||||
var/min_y = -1
|
||||
var/max_x = WORLDMAXX_CUTOFF
|
||||
var/max_y = WORLDMAXY_CUTOFF
|
||||
var/min_x = WORLDMAXX_CUTOFF
|
||||
var/min_y = WORLDMAXY_CUTOFF
|
||||
var/max_x = -1
|
||||
var/max_y = -1
|
||||
for(var/area/shuttle_area as anything in shuttle_areas)
|
||||
for (var/list/zlevel_turfs as anything in shuttle_area.get_zlevel_turf_lists())
|
||||
for(var/turf/turf as anything in zlevel_turfs)
|
||||
min_x = max(turf.x, min_x)
|
||||
max_x = min(turf.x, max_x)
|
||||
min_y = max(turf.y, min_y)
|
||||
max_y = min(turf.y, max_y)
|
||||
min_x = min(turf.x, min_x)
|
||||
max_x = max(turf.x, max_x)
|
||||
min_y = min(turf.y, min_y)
|
||||
max_y = max(turf.y, max_y)
|
||||
CHECK_TICK
|
||||
|
||||
if(min_x == -1 || max_x == WORLDMAXX_CUTOFF)
|
||||
if(min_x == WORLDMAXX_CUTOFF || max_x == -1)
|
||||
CRASH("Failed to locate shuttle boundaries when iterating through shuttle areas, somehow.")
|
||||
if(min_y == -1 || max_y == WORLDMAXY_CUTOFF)
|
||||
if(min_y == WORLDMAXY_CUTOFF || max_y == -1)
|
||||
CRASH("Failed to locate shuttle boundaries when iterating through shuttle areas, somehow.")
|
||||
|
||||
width = (max_x - min_x) + 1
|
||||
height = (max_y - min_y) + 1
|
||||
port_x_offset = min_x - x
|
||||
port_y_offset = min_y - y
|
||||
port_x_offset = x - min_x + 1
|
||||
port_y_offset = y - min_y + 1
|
||||
|
||||
if(dir in list(EAST, WEST))
|
||||
src.width = height
|
||||
@@ -157,13 +167,19 @@
|
||||
#undef WORLDMAXX_CUTOFF
|
||||
#undef WORLDMAXY_CUTOFF
|
||||
|
||||
/obj/docking_port/mobile/is_in_shuttle_bounds(atom/A)
|
||||
. = ..()
|
||||
if(. && !shuttle_areas[get_area(A)])
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Actions to be taken after shuttle is loaded but before it has been moved out of transit z-level to its final location
|
||||
*
|
||||
* Arguments:
|
||||
* * replace - TRUE if this shuttle is replacing an existing one. FALSE by default.
|
||||
* * custom - TRUE if this shuttle should be added to the custom shuttle list. FALSE by default.
|
||||
*/
|
||||
/obj/docking_port/mobile/register(replace = FALSE)
|
||||
/obj/docking_port/mobile/register(replace = FALSE, custom = FALSE)
|
||||
. = ..()
|
||||
if(!shuttle_id)
|
||||
shuttle_id = "shuttle"
|
||||
@@ -185,6 +201,9 @@
|
||||
|
||||
SSshuttle.mobile_docking_ports += src
|
||||
|
||||
if(custom)
|
||||
SSshuttle.custom_shuttles += src
|
||||
|
||||
/**
|
||||
* Actions to be taken after shuttle is loaded and has been moved to its final location
|
||||
*
|
||||
@@ -197,6 +216,7 @@
|
||||
/obj/docking_port/mobile/unregister()
|
||||
. = ..()
|
||||
SSshuttle.mobile_docking_ports -= src
|
||||
SSshuttle.custom_shuttles -= src
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
|
||||
var/obj/docking_port/stationary/old_dock = get_docked()
|
||||
|
||||
// The area that gets placed under where the shuttle moved from
|
||||
var/underlying_area_type = SHUTTLE_DEFAULT_UNDERLYING_AREA
|
||||
// The area that gets placed under shuttle turfs that do not have their own area to place down
|
||||
var/fallback_area_type = SHUTTLE_DEFAULT_UNDERLYING_AREA
|
||||
|
||||
if(old_dock) //Dock overwrites
|
||||
underlying_area_type = old_dock.area_type
|
||||
fallback_area_type = old_dock.area_type
|
||||
|
||||
/**************************************************************************************************************
|
||||
Both lists are associative with a turf:bitflag structure. (new_turfs bitflag space unused currently)
|
||||
@@ -33,11 +33,11 @@
|
||||
CHECK_TICK
|
||||
/**************************************************************************************************************/
|
||||
|
||||
// The underlying old area is the area assumed to be under the shuttle's starting location
|
||||
// The fallback area is the area for shuttle turfs that have no area underneath them
|
||||
// If it no longer/has never existed it will be created
|
||||
var/area/underlying_old_area = GLOB.areas_by_type[underlying_area_type]
|
||||
if(!underlying_old_area)
|
||||
underlying_old_area = new underlying_area_type(null)
|
||||
var/area/fallback_area = GLOB.areas_by_type[fallback_area_type]
|
||||
if(!fallback_area)
|
||||
fallback_area = new fallback_area_type(null)
|
||||
|
||||
var/rotation = 0
|
||||
if(new_dock.dir != dir) //Even when the dirs are the same rotation is coming out as not 0 for some reason
|
||||
@@ -51,8 +51,9 @@
|
||||
|
||||
var/list/moved_atoms = list() //Everything not a turf that gets moved in the shuttle
|
||||
var/list/areas_to_move = list() //unique assoc list of areas on turfs being moved
|
||||
var/list/underlying_areas = list() //unique assoc list of areas beneath turfs being moved
|
||||
|
||||
. = preflight_check(old_turfs, new_turfs, areas_to_move, rotation)
|
||||
. = preflight_check(old_turfs, new_turfs, areas_to_move, underlying_areas, rotation)
|
||||
if(.)
|
||||
remove_ripples()
|
||||
return
|
||||
@@ -81,11 +82,11 @@
|
||||
// Moving to the new location will trample the ripples there at the exact
|
||||
// same time any mobs there are trampled, to avoid any discrepancy where
|
||||
// the ripples go away before it is safe.
|
||||
takeoff(old_turfs, new_turfs, moved_atoms, rotation, movement_direction, old_dock, underlying_old_area)
|
||||
takeoff(old_turfs, new_turfs, moved_atoms, rotation, movement_direction, old_dock, fallback_area)
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
cleanup_runway(new_dock, old_turfs, new_turfs, areas_to_move, moved_atoms, rotation, movement_direction, underlying_old_area)
|
||||
cleanup_runway(new_dock, old_turfs, new_turfs, areas_to_move, underlying_areas, moved_atoms, rotation, movement_direction, fallback_area)
|
||||
|
||||
CHECK_TICK
|
||||
|
||||
@@ -103,7 +104,7 @@
|
||||
remove_ripples()
|
||||
return DOCKING_SUCCESS
|
||||
|
||||
/obj/docking_port/mobile/proc/preflight_check(list/old_turfs, list/new_turfs, list/areas_to_move, rotation)
|
||||
/obj/docking_port/mobile/proc/preflight_check(list/old_turfs, list/new_turfs, list/areas_to_move, list/underlying_areas, rotation)
|
||||
for(var/i in 1 to length(old_turfs))
|
||||
CHECK_TICK
|
||||
var/turf/oldT = old_turfs[i]
|
||||
@@ -126,11 +127,14 @@
|
||||
move_mode = newT.toShuttleMove(oldT, move_mode, src) //turfs
|
||||
|
||||
if(move_mode & MOVE_AREA)
|
||||
var/area/underlying_area = underlying_areas_by_turf[oldT]
|
||||
if(underlying_area)
|
||||
underlying_areas[underlying_area] = TRUE
|
||||
areas_to_move[old_area] = TRUE
|
||||
|
||||
old_turfs[oldT] = move_mode
|
||||
|
||||
/obj/docking_port/mobile/proc/takeoff(list/old_turfs, list/new_turfs, list/moved_atoms, rotation, movement_direction, old_dock, area/underlying_old_area)
|
||||
/obj/docking_port/mobile/proc/takeoff(list/old_turfs, list/new_turfs, list/moved_atoms, rotation, movement_direction, old_dock, area/fallback_area)
|
||||
for(var/i in 1 to old_turfs.len)
|
||||
var/turf/oldT = old_turfs[i]
|
||||
var/turf/newT = new_turfs[i]
|
||||
@@ -141,7 +145,7 @@
|
||||
|
||||
if(move_mode & MOVE_AREA)
|
||||
var/area/shuttle_area = oldT.loc
|
||||
shuttle_area.onShuttleMove(oldT, newT, underlying_old_area) //areas
|
||||
shuttle_area.onShuttleMove(oldT, newT, src, fallback_area) //areas
|
||||
|
||||
if(move_mode & MOVE_CONTENTS)
|
||||
for(var/k in oldT)
|
||||
@@ -152,8 +156,12 @@
|
||||
moved_atoms[moving_atom] = oldT
|
||||
|
||||
|
||||
/obj/docking_port/mobile/proc/cleanup_runway(obj/docking_port/stationary/new_dock, list/old_turfs, list/new_turfs, list/areas_to_move, list/moved_atoms, rotation, movement_direction, area/underlying_old_area)
|
||||
underlying_old_area.afterShuttleMove(0)
|
||||
/obj/docking_port/mobile/proc/cleanup_runway(obj/docking_port/stationary/new_dock, list/old_turfs, list/new_turfs, list/areas_to_move, list/underlying_areas, list/moved_atoms, rotation, movement_direction, area/fallback_area)
|
||||
fallback_area.afterShuttleMove(0)
|
||||
for(var/i in 1 to underlying_areas.len)
|
||||
CHECK_TICK
|
||||
var/area/underlying_area = underlying_areas[i]
|
||||
underlying_area.afterShuttleMove(0)
|
||||
|
||||
// Parallax handling
|
||||
// This needs to be done before the atom after move
|
||||
@@ -167,24 +175,28 @@
|
||||
|
||||
for(var/i in 1 to old_turfs.len)
|
||||
CHECK_TICK
|
||||
if(!(old_turfs[old_turfs[i]] & MOVE_TURF))
|
||||
continue
|
||||
var/turf/old_turf = old_turfs[i]
|
||||
var/old_move_mode = old_turfs[old_turf]
|
||||
var/turf/old_ceiling = get_step_multiz(old_turf, UP)
|
||||
if(old_ceiling) // check if a ceiling was generated previously
|
||||
// remove old ceiling
|
||||
if(istype(old_ceiling, /turf/open/floor/engine/hull/ceiling))
|
||||
old_ceiling.ScrapeAway()
|
||||
else
|
||||
old_ceiling.remove_baseturfs_from_typecache(list(/turf/open/floor/engine/hull/ceiling = TRUE))
|
||||
if(!(old_move_mode & MOVE_TURF))
|
||||
continue
|
||||
var/turf/new_turf = new_turfs[i]
|
||||
new_turf.afterShuttleMove(old_turf, rotation) //turfs
|
||||
var/turf/new_ceiling = get_step_multiz(new_turf, UP) // check if a ceiling is needed
|
||||
if(new_ceiling)
|
||||
// generate ceiling
|
||||
if(istype(new_ceiling, /turf/open/openspace)) // why is this needed? because we have 2 different typepaths for openspace
|
||||
new_ceiling.ChangeTurf(/turf/open/floor/engine/hull/ceiling, list(/turf/open/openspace))
|
||||
else if (istype(new_ceiling, /turf/open/space/openspace))
|
||||
new_ceiling.ChangeTurf(/turf/open/floor/engine/hull/ceiling, list(/turf/open/space/openspace))
|
||||
var/turf/old_ceiling = get_step_multiz(old_turf, UP)
|
||||
if(old_ceiling && istype(old_ceiling, /turf/open/floor/engine/hull/ceiling)) // check if a ceiling was generated previously
|
||||
// remove old ceiling
|
||||
var/turf/open/floor/engine/hull/ceiling/old_shuttle_ceiling = old_ceiling
|
||||
old_shuttle_ceiling.ChangeTurf(old_shuttle_ceiling.old_turf_type)
|
||||
|
||||
if(!(istype(new_ceiling, /turf/open/floor/engine/hull/ceiling) || new_ceiling.depth_to_find_baseturf(/turf/open/floor/engine/hull/ceiling)))
|
||||
if(istype(new_ceiling, /turf/open/openspace) || istype(new_ceiling, /turf/open/space/openspace))
|
||||
new_ceiling.place_on_top(/turf/open/floor/engine/hull/ceiling)
|
||||
else
|
||||
new_ceiling.stack_ontop_of_baseturf(/turf/open/openspace, /turf/open/floor/engine/hull/ceiling)
|
||||
new_ceiling.stack_ontop_of_baseturf(/turf/open/space/openspace, /turf/open/floor/engine/hull/ceiling)
|
||||
for(var/i in 1 to moved_atoms.len)
|
||||
CHECK_TICK
|
||||
var/atom/movable/moved_object = moved_atoms[i]
|
||||
@@ -195,13 +207,18 @@
|
||||
|
||||
// lateShuttleMove (There had better be a really good reason for additional stages beyond this)
|
||||
|
||||
underlying_old_area.lateShuttleMove()
|
||||
fallback_area.lateShuttleMove()
|
||||
|
||||
for(var/i in 1 to areas_to_move.len)
|
||||
CHECK_TICK
|
||||
var/area/internal_area = areas_to_move[i]
|
||||
internal_area.lateShuttleMove()
|
||||
|
||||
for(var/i in 1 to underlying_areas.len)
|
||||
CHECK_TICK
|
||||
var/area/underlying_area = underlying_areas[i]
|
||||
underlying_area.lateShuttleMove()
|
||||
|
||||
for(var/i in 1 to old_turfs.len)
|
||||
CHECK_TICK
|
||||
if(!(old_turfs[old_turfs[i]] & MOVE_CONTENTS | MOVE_TURF))
|
||||
|
||||
@@ -89,6 +89,11 @@ All ShuttleMove procs go here
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Return the move_move (based on the old), without any side effects.
|
||||
// This is for checking what would be moved if src is on a shuttle being moved.
|
||||
/atom/movable/proc/hypotheticalShuttleMove(rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
return move_mode
|
||||
|
||||
// Called on every atom in shuttle turf contents before anything has been moved
|
||||
// returns the new move_mode (based on the old)
|
||||
// WARNING: Do not leave turf contents in beforeShuttleMove or dock() will runtime
|
||||
@@ -141,16 +146,19 @@ All ShuttleMove procs go here
|
||||
return MOVE_AREA
|
||||
|
||||
// Called on areas to move their turf between areas
|
||||
/area/proc/onShuttleMove(turf/oldT, turf/newT, area/underlying_old_area)
|
||||
/area/proc/onShuttleMove(turf/oldT, turf/newT, obj/docking_port/mobile/shuttle, area/fallback_area)
|
||||
if(newT == oldT) // In case of in place shuttle rotation shenanigans.
|
||||
return TRUE
|
||||
|
||||
oldT.change_area(src, underlying_old_area)
|
||||
var/area/underlying_area = shuttle.underlying_areas_by_turf[oldT]
|
||||
oldT.change_area(src, underlying_area || fallback_area)
|
||||
shuttle.underlying_areas_by_turf -= oldT
|
||||
//The old turf has now been given back to the area that turf originaly belonged to
|
||||
|
||||
var/area/old_dest_area = newT.loc
|
||||
parallax_movedir = old_dest_area.parallax_movedir
|
||||
newT.change_area(old_dest_area, src)
|
||||
shuttle.underlying_areas_by_turf[newT] = old_dest_area
|
||||
return TRUE
|
||||
|
||||
// Called on areas after everything has been moved
|
||||
@@ -218,6 +226,11 @@ All ShuttleMove procs go here
|
||||
break
|
||||
|
||||
|
||||
/obj/machinery/camera/hypotheticalShuttleMove(rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/machinery/camera/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
@@ -323,11 +336,21 @@ All ShuttleMove procs go here
|
||||
|
||||
/************************************Structure move procs************************************/
|
||||
|
||||
/obj/structure/grille/hypotheticalShuttleMove(rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/structure/grille/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/structure/lattice/hypotheticalShuttleMove(rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/structure/lattice/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
@@ -342,6 +365,11 @@ All ShuttleMove procs go here
|
||||
Connect_cable(TRUE)
|
||||
propagate_if_no_network()
|
||||
|
||||
/obj/machinery/power/shuttle_engine/hypotheticalShuttleMove(move_mode)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/machinery/power/shuttle_engine/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(. & MOVE_AREA)
|
||||
@@ -365,6 +393,11 @@ All ShuttleMove procs go here
|
||||
|
||||
/************************************Misc move procs************************************/
|
||||
|
||||
/obj/docking_port/mobile/hypotheticalShuttleMove(rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(moving_dock == src)
|
||||
. |= MOVE_CONTENTS
|
||||
|
||||
/obj/docking_port/mobile/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(moving_dock == src)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/docking_port/mobile/assault_pod/initiate_docking(obj/docking_port/stationary/S1)
|
||||
/obj/docking_port/mobile/assault_pod/initiate_docking(obj/docking_port/stationary/S1, force=FALSE)
|
||||
. = ..()
|
||||
if(!istype(S1, /obj/docking_port/stationary/transit))
|
||||
playsound(get_turf(src.loc), 'sound/effects/explosion/explosion1.ogg',50,TRUE)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
/obj/docking_port/mobile/custom
|
||||
name = "custom shuttle"
|
||||
shuttle_id = "custom"
|
||||
var/datum/weakref/master_blueprint
|
||||
var/area/default_area
|
||||
var/datum/weakref/control_console
|
||||
var/datum/weakref/navigation_console
|
||||
|
||||
/obj/docking_port/mobile/custom/Initialize(mapload, list/areas)
|
||||
. = ..()
|
||||
default_area = areas[1]
|
||||
|
||||
/obj/docking_port/mobile/custom/canMove()
|
||||
return ..() && (current_engine_power > 0)
|
||||
|
||||
/obj/docking_port/mobile/custom/get_engine_coeff()
|
||||
var/thrust_ratio = (current_engine_power * CUSTOM_ENGINE_POWER_MULTIPLIER)/(turf_count + CUSTOM_ENGINE_POWER_TURF_COUNT_OFFSET)
|
||||
var/calculated_multiplier = 2*(1-(NUM_E ** -thrust_ratio))
|
||||
return clamp(1/calculated_multiplier, CUSTOM_ENGINE_COEFF_MIN, CUSTOM_ENGINE_COEFF_MAX)
|
||||
@@ -0,0 +1,174 @@
|
||||
GLOBAL_LIST_INIT(custom_shuttle_station_area_whitelist, list(/area/station/asteroid))
|
||||
|
||||
/obj/machinery/computer/shuttle/custom_shuttle
|
||||
desc = "A shuttle control computer."
|
||||
icon_screen = "shuttle"
|
||||
icon_keyboard = "tech_key"
|
||||
shuttleId = ""
|
||||
light_color = LIGHT_COLOR_CYAN
|
||||
req_access = list()
|
||||
interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON
|
||||
possible_destinations = "whiteship_home;"
|
||||
var/static/list/connections = list(COMSIG_TURF_ADDED_TO_SHUTTLE = PROC_REF(on_loc_added_to_shuttle))
|
||||
|
||||
/obj/machinery/computer/shuttle/custom_shuttle/on_construction(mob/user)
|
||||
circuit.configure_machine(src)
|
||||
if(!shuttleId)
|
||||
AddElement(/datum/element/connect_loc, connections)
|
||||
|
||||
/obj/machinery/computer/shuttle/custom_shuttle/proc/on_loc_added_to_shuttle(turf/source, obj/docking_port/mobile/custom/port)
|
||||
SIGNAL_HANDLER
|
||||
if(!istype(port))
|
||||
say("Cannot link to this kind of shuttle!")
|
||||
else
|
||||
if(connect_to_shuttle(TRUE, port))
|
||||
RemoveElement(/datum/element/connect_loc, connections)
|
||||
|
||||
/obj/machinery/computer/shuttle/custom_shuttle/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
|
||||
var/obj/docking_port/mobile/custom/custom_port = port
|
||||
if(istype(custom_port))
|
||||
if(custom_port.control_console?.resolve())
|
||||
say("Control console already present!")
|
||||
return FALSE
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
if(istype(custom_port))
|
||||
custom_port.control_console = WEAKREF(src)
|
||||
name = "[port.name] console"
|
||||
|
||||
/obj/machinery/computer/shuttle/custom_shuttle/proc/linkShuttle(new_id)
|
||||
if(shuttleId=="")
|
||||
shuttleId = new_id
|
||||
possible_destinations = "whiteship_home;shuttle[new_id]_custom;"
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
//docking cam
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom
|
||||
lock_override = NONE
|
||||
jump_to_ports = list("whiteship_home" = 1)
|
||||
designate_time = 100
|
||||
circuit = /obj/item/circuitboard/computer/shuttle/docker
|
||||
var/static/list/connections = list(COMSIG_TURF_ADDED_TO_SHUTTLE = PROC_REF(on_loc_added_to_shuttle))
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/on_construction(mob/user)
|
||||
circuit.configure_machine(src)
|
||||
if(!shuttleId)
|
||||
AddElement(/datum/element/connect_loc, connections)
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/proc/on_loc_added_to_shuttle(turf/source, obj/docking_port/mobile/custom/port)
|
||||
SIGNAL_HANDLER
|
||||
if(!istype(port))
|
||||
say("Cannot link to this kind of shuttle!")
|
||||
else
|
||||
if(connect_to_shuttle(TRUE, port))
|
||||
RemoveElement(/datum/element/connect_loc, connections)
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/Initialize(mapload)
|
||||
. = ..()
|
||||
GLOB.jam_on_wardec += src
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/Destroy()
|
||||
GLOB.jam_on_wardec -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
|
||||
if(shuttleId) //We normally should only be connecting newly-created consoles to shuttles, but just in case...
|
||||
var/obj/docking_port/mobile/old_shuttle = SSshuttle.getShuttle(shuttleId)
|
||||
if(old_shuttle)
|
||||
UnregisterSignal(old_shuttle, COMSIG_SHUTTLE_EXPANDED)
|
||||
var/obj/docking_port/mobile/custom/custom_port = port
|
||||
if(istype(custom_port))
|
||||
if(custom_port.navigation_console?.resolve())
|
||||
say("Navigation console already present!")
|
||||
return FALSE
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
name = "[port.name] navigation computer"
|
||||
if(istype(custom_port))
|
||||
custom_port.navigation_console = WEAKREF(src)
|
||||
RegisterSignal(port, COMSIG_SHUTTLE_EXPANDED, PROC_REF(on_shuttle_expanded))
|
||||
recalculate_eye_view(port)
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/proc/on_shuttle_expanded(obj/docking_port/mobile/source, list/turfs)
|
||||
SIGNAL_HANDLER
|
||||
recalculate_eye_view(source)
|
||||
if(my_port)
|
||||
var/here_x = source.x
|
||||
var/here_y = source.y
|
||||
var/there_x = my_port.x
|
||||
var/there_y = my_port.y
|
||||
var/target_z = my_port.z
|
||||
var/rotation = angle2dir_cardinal(dir2angle(my_port.dir) - dir2angle(source.dir))
|
||||
var/docked = my_port.get_docked() == source
|
||||
for(var/turf/turf as anything in turfs)
|
||||
var/turf/checked_turf
|
||||
if(docked)
|
||||
checked_turf = turf
|
||||
else
|
||||
var/offset_x = turf.x - here_x
|
||||
var/offset_y = turf.y - here_y
|
||||
var/target_x = there_x
|
||||
var/target_y = there_y
|
||||
switch(rotation)
|
||||
if(NORTH)
|
||||
target_x += offset_x
|
||||
target_y += offset_y
|
||||
if(SOUTH)
|
||||
target_x -= offset_x
|
||||
target_y -= offset_y
|
||||
if(EAST)
|
||||
target_x -= offset_y
|
||||
target_y += offset_x
|
||||
if(WEST)
|
||||
target_x += offset_y
|
||||
target_y -= offset_x
|
||||
checked_turf = locate(target_x, target_y, target_z)
|
||||
if(checkLandingTurf(checked_turf) != SHUTTLE_DOCKER_LANDING_CLEAR)
|
||||
if(docked)
|
||||
my_port.unregister()
|
||||
my_port.delete_after = TRUE
|
||||
my_port.shuttle_id = null
|
||||
my_port.name = "Old [my_port.name]"
|
||||
my_port = null
|
||||
else
|
||||
QDEL_NULL(my_port)
|
||||
break
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/proc/recalculate_eye_view(obj/docking_port/mobile/shuttle)
|
||||
var/bigger_shuttle_dimension = max(shuttle.width, shuttle.height)
|
||||
var/list/viewsize = getviewsize(world.view)
|
||||
var/smaller_view_dimension = min(viewsize[1], viewsize[2])
|
||||
var/new_view_range = max(bigger_shuttle_dimension - smaller_view_dimension, 0)
|
||||
if(new_view_range != view_range)
|
||||
view_range = new_view_range
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/placeLandingSpot()
|
||||
if(!shuttleId)
|
||||
return //Only way this would happen is if someone else delinks the console while in use somehow
|
||||
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
|
||||
if(M?.mode != SHUTTLE_IDLE)
|
||||
to_chat(usr, "<span class='warning'>You cannot target locations while in transit.</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/checkLandingTurf(turf/T, list/overlappers)
|
||||
. = ..()
|
||||
var/area/area = get_area(T)
|
||||
if(!is_type_in_list(area, GLOB.custom_shuttle_station_area_whitelist) && is_type_in_list(area, GLOB.the_station_areas))
|
||||
return SHUTTLE_DOCKER_BLOCKED
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/attack_hand(mob/user)
|
||||
if(!shuttleId)
|
||||
to_chat(user, "<span class='warning'>You must link the console to a shuttle first.</span>")
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/proc/linkShuttle(new_id)
|
||||
if(shuttleId=="")
|
||||
shuttleId = new_id
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -119,7 +119,7 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list(
|
||||
message_admins("Blacklisted item found on in-transit Cargo Shuttle. See cargo logs for more details.")
|
||||
SSshuttle.centcom_message = "Contraband found on Cargo Shuttle. This has been returned via drop pod."
|
||||
|
||||
/obj/docking_port/mobile/supply/initiate_docking()
|
||||
/obj/docking_port/mobile/supply/initiate_docking(obj/docking_port/stationary/new_dock, force=FALSE)
|
||||
if(getDockedId() == "cargo_away") // Buy when we leave home.
|
||||
buy()
|
||||
create_mail()
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
var/x_offset = 0
|
||||
///y offset for where the camera eye will spawn. Starts from the shuttle's docking port
|
||||
var/y_offset = 0
|
||||
var/list/whitelist_turfs = list(/turf/open/space, /turf/open/floor/plating, /turf/open/lava, /turf/open/openspace)
|
||||
var/list/whitelist_turfs = list(/turf/open/space, /turf/open/floor/plating, /turf/open/lava, /turf/open/openspace, /turf/open/misc)
|
||||
var/see_hidden = FALSE
|
||||
var/designate_time = 0
|
||||
var/turf/designating_target_loc
|
||||
|
||||
@@ -239,6 +239,7 @@
|
||||
possible_destinations = replacetext(replacetextEx(possible_destinations, "[shuttleId]_custom", ""), ";;", ";")
|
||||
shuttleId = port.shuttle_id
|
||||
possible_destinations += ";[port.shuttle_id]_custom"
|
||||
return TRUE
|
||||
|
||||
#undef SHUTTLE_CONSOLE_ACCESSDENIED
|
||||
#undef SHUTTLE_CONSOLE_ENDGAME
|
||||
|
||||
@@ -560,3 +560,7 @@ MAX_POSITIVE_QUIRKS 6
|
||||
# If the value is lower than 1, it'll tend to even out the odds
|
||||
# If higher than 1, it'll lean toward common spawns even more.
|
||||
RANDOM_LOOT_WEIGHT_MODIFIER 1
|
||||
|
||||
## Custom shuttle spam prevention. Changine these numbers allows you to change the maxsize and amount of custom shuttles.
|
||||
MAX_SHUTTLE_COUNT 6
|
||||
MAX_SHUTTLE_SIZE 300
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -330,6 +330,7 @@
|
||||
#include "code\__DEFINES\dcs\signals\signals_janitor.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_key.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_ladder.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_lattice.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_lazy_templates.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_leash.dm"
|
||||
#include "code\__DEFINES\dcs\signals\signals_lift.dm"
|
||||
@@ -1098,6 +1099,7 @@
|
||||
#include "code\datums\components\combo_attacks.dm"
|
||||
#include "code\datums\components\combustible_flooder.dm"
|
||||
#include "code\datums\components\connect_containers.dm"
|
||||
#include "code\datums\components\connect_inventory.dm"
|
||||
#include "code\datums\components\connect_loc_behalf.dm"
|
||||
#include "code\datums\components\connect_mob_behalf.dm"
|
||||
#include "code\datums\components\connect_range.dm"
|
||||
@@ -1110,6 +1112,7 @@
|
||||
#include "code\datums\components\cult_ritual_item.dm"
|
||||
#include "code\datums\components\curse_of_hunger.dm"
|
||||
#include "code\datums\components\curse_of_polymorph.dm"
|
||||
#include "code\datums\components\custom_area.dm"
|
||||
#include "code\datums\components\customizable_reagent_holder.dm"
|
||||
#include "code\datums\components\damage_aura.dm"
|
||||
#include "code\datums\components\damage_chain.dm"
|
||||
@@ -1575,6 +1578,8 @@
|
||||
#include "code\datums\elements\selfknockback.dm"
|
||||
#include "code\datums\elements\series.dm"
|
||||
#include "code\datums\elements\shiny_bait.dm"
|
||||
#include "code\datums\elements\shuttle_construction_lattice.dm"
|
||||
#include "code\datums\elements\shuttle_construction_turf.dm"
|
||||
#include "code\datums\elements\sideway_movement.dm"
|
||||
#include "code\datums\elements\simple_flying.dm"
|
||||
#include "code\datums\elements\skill_reward.dm"
|
||||
@@ -5981,6 +5986,9 @@
|
||||
#include "code\modules\shuttle\mobile_port\variants\ferry.dm"
|
||||
#include "code\modules\shuttle\mobile_port\variants\infiltrator.dm"
|
||||
#include "code\modules\shuttle\mobile_port\variants\supply.dm"
|
||||
#include "code\modules\shuttle\mobile_port\variants\custom\blueprints.dm"
|
||||
#include "code\modules\shuttle\mobile_port\variants\custom\custom.dm"
|
||||
#include "code\modules\shuttle\mobile_port\variants\custom\custom_consoles.dm"
|
||||
#include "code\modules\shuttle\mobile_port\variants\emergency\emergency.dm"
|
||||
#include "code\modules\shuttle\mobile_port\variants\emergency\emergency_console.dm"
|
||||
#include "code\modules\shuttle\mobile_port\variants\emergency\emergency_types.dm"
|
||||
|
||||
@@ -69,6 +69,21 @@ export const CSS_COLORS = [
|
||||
'yellow',
|
||||
] as const;
|
||||
|
||||
export enum Direction {
|
||||
NONE = 0,
|
||||
NORTH = 1,
|
||||
SOUTH = 2,
|
||||
EAST = 4,
|
||||
WEST = 8,
|
||||
NORTHEAST = NORTH | EAST,
|
||||
NORTHWEST = NORTH | WEST,
|
||||
SOUTHEAST = SOUTH | EAST,
|
||||
SOUTHWEST = SOUTH | WEST,
|
||||
VERTICAL = NORTH | SOUTH,
|
||||
HORIZONTAL = EAST | WEST,
|
||||
ALL = NORTH | SOUTH | EAST | WEST,
|
||||
}
|
||||
|
||||
export type CssColor = (typeof CSS_COLORS)[number];
|
||||
|
||||
/* IF YOU CHANGE THIS KEEP IT IN SYNC WITH CHAT CSS */
|
||||
|
||||
@@ -0,0 +1,422 @@
|
||||
import { ReactNode, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Dropdown,
|
||||
Input,
|
||||
Section,
|
||||
Stack,
|
||||
Tooltip,
|
||||
} from 'tgui-core/components';
|
||||
import { BooleanLike } from 'tgui-core/react';
|
||||
|
||||
import { useBackend } from '../backend';
|
||||
import { Direction } from '../constants';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
type AreaData = { name: string; ref: string };
|
||||
|
||||
type VisualizationToggleProps = { visualizing: BooleanLike };
|
||||
|
||||
type ShuttleConstructionUnieuqData = {
|
||||
linkedShuttle: 0;
|
||||
tooManyShuttles: BooleanLike;
|
||||
onCustomShuttle: BooleanLike;
|
||||
};
|
||||
|
||||
type ShuttleConfigurationUniqueData = {
|
||||
linkedShuttle: string;
|
||||
onShuttle: BooleanLike;
|
||||
inDefaultArea: BooleanLike;
|
||||
currentArea: AreaData;
|
||||
defaultApc: BooleanLike;
|
||||
apcInMergeRegion: BooleanLike;
|
||||
apcs: Record<string, BooleanLike>;
|
||||
neighboringAreas: Record<string, string>;
|
||||
idle: BooleanLike;
|
||||
};
|
||||
|
||||
type ShuttleBlueprintsData = {
|
||||
shuttles?: Record<string, string>;
|
||||
visualizing: BooleanLike;
|
||||
onShuttleFrame: BooleanLike;
|
||||
masterExists: BooleanLike;
|
||||
isMaster: BooleanLike;
|
||||
} & (ShuttleConstructionUnieuqData | ShuttleConfigurationUniqueData);
|
||||
|
||||
type DirectionPadProps = {
|
||||
title: string;
|
||||
tooltip?: ReactNode;
|
||||
enabledDirections: Direction;
|
||||
selectedDirection: Direction;
|
||||
onSelect: (direction: Direction) => void;
|
||||
};
|
||||
|
||||
const directionData: [Direction, string][] = [
|
||||
[Direction.NORTH, 'up'],
|
||||
[Direction.SOUTH, 'down'],
|
||||
[Direction.EAST, 'right'],
|
||||
[Direction.WEST, 'left'],
|
||||
];
|
||||
|
||||
const DirectionPad = (props: DirectionPadProps) => {
|
||||
const { title, tooltip, enabledDirections, selectedDirection, onSelect } =
|
||||
props;
|
||||
const [north, south, east, west] = directionData.map(
|
||||
([direction, icon_suffix], i) => (
|
||||
<Stack.Item key={i}>
|
||||
<Button
|
||||
fluid
|
||||
m={0}
|
||||
icon={`arrow-${icon_suffix}`}
|
||||
selected={selectedDirection & direction}
|
||||
disabled={!(enabledDirections & direction)}
|
||||
onClick={() => onSelect(direction)}
|
||||
/>
|
||||
</Stack.Item>
|
||||
),
|
||||
);
|
||||
const titleNode = (
|
||||
<Box width="100%" textAlign="center">
|
||||
{title}
|
||||
</Box>
|
||||
);
|
||||
return (
|
||||
<Section
|
||||
fill
|
||||
title={
|
||||
tooltip ? <Tooltip content={tooltip}>{titleNode}</Tooltip> : titleNode
|
||||
}
|
||||
>
|
||||
<Stack fill vertical align="center" justify="center">
|
||||
{north}
|
||||
<Stack.Item>
|
||||
<Stack>
|
||||
{west}
|
||||
<Stack.Item width="1rem" mx={1} />
|
||||
{east}
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
{south}
|
||||
</Stack>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const VisualizationToggle = (props: VisualizationToggleProps) => {
|
||||
const { visualizing } = props;
|
||||
const { act } = useBackend<ShuttleBlueprintsData>();
|
||||
return (
|
||||
<Tooltip
|
||||
content="Toggle a visualization of shuttle frames you can use to construct a shuttle.
|
||||
Red tiles indicate frame parts built in invalid areas,
|
||||
or parts of suitable areas that need frame parts built on them."
|
||||
>
|
||||
<Box inline>
|
||||
Visualization:
|
||||
<Button
|
||||
color="transparent"
|
||||
icon={visualizing ? 'toggle-on' : 'toggle-off'}
|
||||
onClick={() => act('toggleVisualization')}
|
||||
/>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
const ShuttleConstruction = () => {
|
||||
const [shuttleDirection, setShuttleDirection] = useState<Direction>(
|
||||
Direction.NORTH,
|
||||
);
|
||||
const { act, data } = useBackend<ShuttleBlueprintsData>();
|
||||
if (data.linkedShuttle !== 0) {
|
||||
throw new Error('type guard failure - linkedShuttle must be 0');
|
||||
}
|
||||
const {
|
||||
onShuttleFrame,
|
||||
visualizing,
|
||||
tooManyShuttles,
|
||||
onCustomShuttle,
|
||||
masterExists,
|
||||
} = data;
|
||||
return (
|
||||
<Stack justify="space-around">
|
||||
<Stack.Item grow>
|
||||
<DirectionPad
|
||||
title="Shuttle Direction"
|
||||
tooltip="This specifies the direction that the shuttle being built is facing."
|
||||
enabledDirections={Direction.ALL}
|
||||
selectedDirection={shuttleDirection}
|
||||
onSelect={(dir) => setShuttleDirection(dir)}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Stack fill vertical align="end" justify="space-between">
|
||||
<Stack.Item>
|
||||
<VisualizationToggle visualizing={visualizing} />
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Stack vertical>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
disabled={!onShuttleFrame || tooManyShuttles}
|
||||
tooltip={
|
||||
tooManyShuttles
|
||||
? 'There are too many shuttles already.'
|
||||
: onShuttleFrame
|
||||
? null
|
||||
: 'You must be standing on a shuttle frame to do this.'
|
||||
}
|
||||
onClick={() =>
|
||||
act('tryBuildShuttle', { dir: shuttleDirection })
|
||||
}
|
||||
>
|
||||
Build New Shuttle
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
disabled={!onCustomShuttle || masterExists}
|
||||
tooltip={
|
||||
onCustomShuttle
|
||||
? masterExists
|
||||
? 'The master blueprint for this shuttle still exists. \
|
||||
Whoever has it can copy it to this set of blueprints.'
|
||||
: null
|
||||
: 'You must be on a custom shuttle to do this.'
|
||||
}
|
||||
onClick={() => act('tryLinkShuttle')}
|
||||
>
|
||||
Connect To Existing Shuttle
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
const ShuttleConfiguration = () => {
|
||||
const [name, setName] = useState('');
|
||||
const [mergeArea = { name: '', ref: '' }, setMergeArea] =
|
||||
useState<AreaData>();
|
||||
const { act, data } = useBackend<ShuttleBlueprintsData>();
|
||||
if (data.linkedShuttle === 0) {
|
||||
throw new Error('type guard failure - linkedShuttle must be non-zero');
|
||||
}
|
||||
const {
|
||||
visualizing,
|
||||
onShuttleFrame,
|
||||
onShuttle,
|
||||
inDefaultArea,
|
||||
currentArea = { name: '', ref: '' },
|
||||
neighboringAreas = {},
|
||||
apcs = {},
|
||||
defaultApc,
|
||||
apcInMergeRegion,
|
||||
idle,
|
||||
isMaster,
|
||||
} = data;
|
||||
const { name: currentAreaName, ref: currentAreaRef } = currentArea;
|
||||
const { name: mergeAreaName, ref: mergeAreaRef } = mergeArea;
|
||||
const removalApcConflict = defaultApc && apcs[currentAreaRef];
|
||||
const mergeApcConflict = apcInMergeRegion && apcs[mergeAreaRef];
|
||||
return (
|
||||
<Stack fill vertical align="center" justify="space-around">
|
||||
<Stack.Item textAlign="center">
|
||||
<h2>Current Area:</h2>
|
||||
<h3>
|
||||
{onShuttle
|
||||
? inDefaultArea
|
||||
? 'Default Area'
|
||||
: currentAreaName
|
||||
: 'Not on Shuttle'}
|
||||
</h3>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Input
|
||||
fluid
|
||||
placeholder="New Area Name"
|
||||
onChange={(_, value) => setName(value)}
|
||||
/>
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
disabled={!(onShuttle && inDefaultArea)}
|
||||
tooltip={
|
||||
onShuttle
|
||||
? inDefaultArea
|
||||
? null
|
||||
: 'You can only create a new area from the default area.'
|
||||
: 'You must be on the linked shuttle to do this.'
|
||||
}
|
||||
onClick={() => act('createNewArea', { name: name })}
|
||||
>
|
||||
Create New Area
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
disabled={!onShuttle || inDefaultArea}
|
||||
tooltip={
|
||||
onShuttle
|
||||
? inDefaultArea
|
||||
? 'You cannot rename the default area.'
|
||||
: null
|
||||
: 'You must be on the linked shuttle to do this.'
|
||||
}
|
||||
onClick={() => act('renameArea', { name: name })}
|
||||
>
|
||||
Rename Current Area
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item width="100%">
|
||||
<Stack fill justify="center">
|
||||
<Stack.Item>
|
||||
<Dropdown
|
||||
placeholder="Select Area"
|
||||
options={Object.entries(neighboringAreas).map(([ref, name]) => {
|
||||
return {
|
||||
displayText: name,
|
||||
value: ref,
|
||||
};
|
||||
})}
|
||||
selected={mergeAreaName}
|
||||
onSelected={(value) =>
|
||||
setMergeArea({ name: neighboringAreas[value], ref: value })
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
disabled={
|
||||
!(onShuttle && inDefaultArea && mergeArea) || mergeApcConflict
|
||||
}
|
||||
tooltip={
|
||||
'Expand the selected area with the connected section of the default area.' +
|
||||
(onShuttle
|
||||
? mergeArea
|
||||
? inDefaultArea
|
||||
? mergeApcConflict
|
||||
? '\nBoth the selected area and the region that it would expand into have APCs. You must remove one first.'
|
||||
: ''
|
||||
: '\nYou can only expand the selected area into the default area.'
|
||||
: ''
|
||||
: '\nYou must be on the linked shuttle to do this.')
|
||||
}
|
||||
onClick={() => act('mergeIntoArea', { area: mergeAreaRef })}
|
||||
>
|
||||
Expand Area
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
disabled={!(idle && onShuttleFrame)}
|
||||
tooltip={
|
||||
'Expand the linked shuttle with an incomplete shuttle frame.' +
|
||||
(idle
|
||||
? onShuttleFrame
|
||||
? ''
|
||||
: '\nYou must be on an incomplete shuttle frame to do this.'
|
||||
: '\nThe shuttle must be idle to do this.')
|
||||
}
|
||||
onClick={() => act('expandWithFrame')}
|
||||
>
|
||||
Expand With Shuttle Frame
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<VisualizationToggle visualizing={visualizing} />
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
disabled={!onShuttle || inDefaultArea || removalApcConflict}
|
||||
tooltip={
|
||||
'Merge the current area into the default area.' +
|
||||
(onShuttle
|
||||
? inDefaultArea
|
||||
? '\nYou are already in the default area.'
|
||||
: removalApcConflict
|
||||
? '\nBoth the current and default areas have APCs. You must remove one first.'
|
||||
: ''
|
||||
: '\nYou must be on the linked shuttle to do this.')
|
||||
}
|
||||
onClick={() => act('releaseArea')}
|
||||
>
|
||||
Remove Area
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
disabled={!idle || !isMaster}
|
||||
tooltip={
|
||||
'Remove all empty space from the shuttle.' + isMaster
|
||||
? idle
|
||||
? '\nThis will delete any areas left without any space, \
|
||||
and will decommission the shuttle entirely if there is nothing left of it.'
|
||||
: '\nThe shuttle must be idle to do this.'
|
||||
: '\nOnly the master blueprint can do this.'
|
||||
}
|
||||
onClick={() => act('cleanupEmptyTurfs')}
|
||||
>
|
||||
Clean Up Empty Space
|
||||
</Button.Confirm>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export const ShuttleBlueprints = (props) => {
|
||||
const { act, data } = useBackend<ShuttleBlueprintsData>();
|
||||
const { linkedShuttle, shuttles, masterExists, isMaster } = data;
|
||||
return (
|
||||
<Window width={450} height={340}>
|
||||
<Window.Content>
|
||||
<Section
|
||||
fill
|
||||
buttons={
|
||||
<>
|
||||
{shuttles && (
|
||||
<Dropdown
|
||||
options={[
|
||||
{ displayText: 'None', value: 0 },
|
||||
...Object.entries(shuttles).map(
|
||||
([ref, name]: [string, string]) => {
|
||||
return { displayText: name, value: ref };
|
||||
},
|
||||
),
|
||||
]}
|
||||
selected={linkedShuttle ? shuttles[linkedShuttle] : 'None'}
|
||||
onSelected={(value) => {
|
||||
if (value === 0) {
|
||||
act('unsetShuttle');
|
||||
} else {
|
||||
act('switchShuttle', { ref: value });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{!!linkedShuttle && !masterExists && !isMaster && (
|
||||
<Button.Confirm onClick={() => act('promoteToMaster')}>
|
||||
Promote To Master Blueprint
|
||||
</Button.Confirm>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
{linkedShuttle ? <ShuttleConfiguration /> : <ShuttleConstruction />}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user