diff --git a/code/__DEFINES/pipes.dm b/code/__DEFINES/pipes.dm index 76143979da7..2b0d4e630e6 100644 --- a/code/__DEFINES/pipes.dm +++ b/code/__DEFINES/pipes.dm @@ -40,6 +40,7 @@ #define PIPE_TEMPERATURE_GATE 40 #define PIPE_GAS_SENSOR 98 #define PIPE_METER 99 +#define PIPE_HIGH_VOLUME_PUMP 111 // MARK: Disposals pipes #define PIPE_DISPOSALS_STRAIGHT 100 diff --git a/code/datums/pipe_datums.dm b/code/datums/pipe_datums.dm index 71c43baa55e..df808f8a50e 100644 --- a/code/datums/pipe_datums.dm +++ b/code/datums/pipe_datums.dm @@ -249,6 +249,14 @@ GLOBAL_LIST_EMPTY(rpd_pipe_list) //Some pipes we don't want to be dispensable pipe_category = RPD_DEVICES rpd_dispensable = TRUE +/datum/pipes/atmospheric/high_volume_vent + pipe_name = "high volume vent pump" + pipe_id = PIPE_HIGH_VOLUME_PUMP + orientations = 4 + pipe_icon = "uvent" + pipe_category = RPD_DEVICES + rpd_dispensable = TRUE + //Heat exchange pipes /datum/pipes/atmospheric/simple/he diff --git a/code/game/machinery/airlock_control/airlock_button.dm b/code/game/machinery/airlock_control/airlock_button.dm index c0dd3c0fb4e..6c13f6cb4f0 100644 --- a/code/game/machinery/airlock_control/airlock_button.dm +++ b/code/game/machinery/airlock_control/airlock_button.dm @@ -15,12 +15,18 @@ GLOBAL_LIST_EMPTY(all_airlock_access_buttons) /// Command, whether this button cycles in or out. This is /tmp/ so mappers dont try and define it in a map. Its assigned at runtime. var/tmp/assigned_command -/obj/machinery/access_button/Initialize(mapload) +/obj/machinery/access_button/Initialize(mapload, direction) . = ..() GLOB.all_airlock_access_buttons += src if(assigned_command) stack_trace("A mapper tried to set assigned_command to [assigned_command] on [type] at [x],[y],[z]. This should not be mapped in.") + if(direction) + setDir(direction) + + if(!mapload) + set_pixel_offsets_from_dir(25, -25, 25, -25) + /obj/machinery/access_button/Destroy() GLOB.all_airlock_access_buttons -= src return ..() diff --git a/code/game/machinery/airlock_control/airlock_controllers.dm b/code/game/machinery/airlock_control/airlock_controllers.dm index 59a9f6c3d8e..aa36b1da346 100644 --- a/code/game/machinery/airlock_control/airlock_controllers.dm +++ b/code/game/machinery/airlock_control/airlock_controllers.dm @@ -37,6 +37,20 @@ // Program vars var/target_pressure +/obj/machinery/airlock_controller/Initialize(mapload, direction) + . = ..() + + if(direction) + setDir(direction) + + if(!mapload) + set_pixel_offsets_from_dir(25, -25, 25, -25) + vent_link_id = VENT_ID(UID()) + ext_door_link_id = EXT_DOOR_ID(UID()) + int_door_link_id = INT_DOOR_ID(UID()) + ext_button_link_id = EXT_BTN_ID(UID()) + int_button_link_id = INT_BTN_ID(UID()) + /obj/machinery/airlock_controller/proc/link_all_items() for(var/obj/machinery/door/airlock/A in GLOB.airlocks) if(A.id_tag == int_door_link_id) diff --git a/code/game/machinery/doors/airlock_electronics.dm b/code/game/machinery/doors/airlock_electronics.dm index 780c3372727..9fbc03a5a0d 100644 --- a/code/game/machinery/doors/airlock_electronics.dm +++ b/code/game/machinery/doors/airlock_electronics.dm @@ -105,6 +105,17 @@ if("clear_all") selected_accesses = list() +/obj/item/airlock_electronics/proc/apply_access_to(obj/target) + if(!istype(target)) + return + + if(one_access) + target.req_access = null + target.req_one_access = selected_accesses + else + target.req_one_access = null + target.req_access = selected_accesses + /obj/item/airlock_electronics/destroyed name = "burned-out airlock electronics" icon_state = "door_electronics_smoked" diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index cc0ed1ed065..98c0ba6aa96 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -297,6 +297,13 @@ doorOpen = 'sound/machines/airlock_ext_open.ogg' doorClose = 'sound/machines/airlock_ext_close.ogg' +/obj/machinery/door/airlock/external/item_interaction(mob/living/user, obj/item/used, list/modifiers) + // Snowflakey but we're not a tool and don't get first mover advantage in atom interaction so shruggles + if(istype(used, /obj/item/mounted/frame/airlock_controller)) + return + + return ..() + /obj/machinery/door/airlock/external/glass opacity = FALSE glass = TRUE diff --git a/code/game/machinery/pipe/pipe_construction.dm b/code/game/machinery/pipe/pipe_construction.dm index e5eda32fd7f..d32976b5336 100644 --- a/code/game/machinery/pipe/pipe_construction.dm +++ b/code/game/machinery/pipe/pipe_construction.dm @@ -40,6 +40,7 @@ GLOBAL_LIST_INIT(pipe_path2type, list( /obj/machinery/atmospherics/unary/outlet_injector = PIPE_INJECTOR, /obj/machinery/atmospherics/unary/passive_vent = PIPE_PASV_VENT, /obj/machinery/atmospherics/binary/circulator = PIPE_CIRCULATOR, + /obj/machinery/atmospherics/unary/vent_pump/high_volume = PIPE_HIGH_VOLUME_PUMP, "[PIPE_JUNCTION]" = /obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction, "[PIPE_HE_STRAIGHT]" = /obj/machinery/atmospherics/pipe/simple/heat_exchanging, "[PIPE_HE_BENT]" = /obj/machinery/atmospherics/pipe/simple/heat_exchanging, @@ -76,6 +77,7 @@ GLOBAL_LIST_INIT(pipe_path2type, list( "[PIPE_INJECTOR]" = /obj/machinery/atmospherics/unary/outlet_injector, "[PIPE_PASV_VENT]" = /obj/machinery/atmospherics/unary/passive_vent, "[PIPE_CIRCULATOR]" = /obj/machinery/atmospherics/binary/circulator, + "[PIPE_HIGH_VOLUME_PUMP]" = /obj/machinery/atmospherics/unary/vent_pump/high_volume, )) /obj/item/pipe @@ -255,7 +257,7 @@ GLOBAL_LIST_INIT(pipe_path2type, list( return flip if(PIPE_SIMPLE_BENT, PIPE_HE_BENT, PIPE_SUPPLY_BENT, PIPE_SCRUBBERS_BENT, - PIPE_UVENT, PIPE_PASV_VENT, PIPE_SCRUBBER, PIPE_INJECTOR) + PIPE_UVENT, PIPE_PASV_VENT, PIPE_SCRUBBER, PIPE_INJECTOR, PIPE_HIGH_VOLUME_PUMP) return dir if(PIPE_SIMPLE_STRAIGHT, PIPE_HE_STRAIGHT, PIPE_JUNCTION, diff --git a/code/game/objects/items/mountable_frames/airlock_chamber_frames.dm b/code/game/objects/items/mountable_frames/airlock_chamber_frames.dm new file mode 100644 index 00000000000..15a2326ba22 --- /dev/null +++ b/code/game/objects/items/mountable_frames/airlock_chamber_frames.dm @@ -0,0 +1,242 @@ +#define LINK_STAGE_NOT_STARTED 0 +#define LINK_STAGE_EXTERIOR_BUTTONS 1 +#define LINK_STAGE_EXTERIOR_AIRLOCKS 2 +#define LINK_STAGE_INTERIOR_BUTTONS 3 +#define LINK_STAGE_INTERIOR_AIRLOCKS 4 +#define LINK_STAGE_VENTS 5 +#define LINK_STAGE_COMPLETE 6 + +/obj/item/mounted/frame/airlock_button + name = "airlock button frame" + desc = "Used for building airlock buttons." + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "access_button_off" + + // external airlock buttons are expected to be placed in space + mount_requirements = MOUNTED_FRAME_SIMFLOOR + +/obj/item/mounted/frame/airlock_button/do_build(turf/on_wall, mob/user) + new /obj/machinery/access_button(get_turf(src), get_dir(user, on_wall)) + qdel(src) + +/obj/item/mounted/frame/airlock_controller + name = "airlock controller frame" + desc = ABSTRACT_TYPE_DESC + icon = 'icons/obj/airlock_machines.dmi' + icon_state = "access_control_off" + mount_requirements = MOUNTED_FRAME_SIMFLOOR | MOUNTED_FRAME_NOSPACE + + var/obj/item/airlock_electronics/access_electronics + var/link_stage = LINK_STAGE_NOT_STARTED + var/result_controller_type + + var/list/interior_airlocks = list() + var/list/interior_buttons = list() + var/list/exterior_airlocks = list() + var/list/exterior_buttons = list() + +/obj/item/mounted/frame/airlock_controller/Destroy() + . = ..() + + QDEL_NULL(access_electronics) + + interior_airlocks.Cut() + interior_buttons.Cut() + exterior_airlocks.Cut() + exterior_buttons.Cut() + +/obj/item/mounted/frame/airlock_controller/examine(mob/user) + . = ..() + + if(istype(access_electronics)) + . += SPAN_NOTICE("Airlock electronics have been inserted to configure access for all its airlocks and buttons.") + else + . += SPAN_NOTICE("Airlock electronics may be placed in it to configure access for all its airlocks and buttons.") + + switch(link_stage) + if(LINK_STAGE_NOT_STARTED) + . += SPAN_NOTICE("It requires its exterior buttons linked next.") + if(LINK_STAGE_EXTERIOR_BUTTONS) + . += SPAN_NOTICE("It requires its exterior airlocks linked next.") + if(LINK_STAGE_EXTERIOR_AIRLOCKS) + . += SPAN_NOTICE("It requires its interior buttons linked next.") + if(LINK_STAGE_INTERIOR_BUTTONS) + . += SPAN_NOTICE("It requires its interior airlocks linked next.") + +/obj/item/mounted/frame/airlock_controller/interact_with_atom(atom/target, mob/living/user, list/modifiers) + if(..()) + return ITEM_INTERACT_COMPLETE + + return attempt_item_link(user, target) + +/obj/item/mounted/frame/airlock_controller/try_build(turf/on_wall, mob/user) + . = ..() + var/list/missing_items = get_missing_items() + if(length(missing_items)) + to_chat(user, SPAN_NOTICE("[src] cannot be placed yet. It is missing at least one [english_list(missing_items)].")) + return FALSE + + return TRUE + +/obj/item/mounted/frame/airlock_controller/item_interaction(mob/living/user, obj/item/used, list/modifiers) + var/obj/item/airlock_electronics/airlock_electronics = used + if(istype(airlock_electronics)) + if(istype(access_electronics)) + to_chat(user, SPAN_NOTICE("There is already \a [access_electronics] in [src].")) + else + if(user.unequip(used)) + access_electronics = airlock_electronics + used.forceMove(src) + else + to_chat(user, SPAN_NOTICE("You can't put [airlock_electronics] in [src].")) + + return ..() + +/obj/item/mounted/frame/airlock_controller/do_build(turf/on_wall, mob/user) + var/obj/machinery/airlock_controller/controller = new result_controller_type(get_turf(src), get_dir(user, on_wall)) + setup_controller(controller) + controller.link_all_items() + qdel(src) + +/obj/item/mounted/frame/airlock_controller/crowbar_act(mob/living/user, obj/item/I) + if(access_electronics) + user.put_in_hands(access_electronics) + to_chat(user, SPAN_NOTICE("You remove [access_electronics] from [src] with [I].")) + access_electronics = null + +/obj/item/mounted/frame/airlock_controller/proc/get_missing_items() + . = list() + if(!length(exterior_buttons)) + . += "exterior button" + if(!length(exterior_airlocks)) + . += "exterior airlock" + if(!length(interior_buttons)) + . += "interior button" + if(!length(interior_airlocks)) + . += "interior airlock" + +/obj/item/mounted/frame/airlock_controller/proc/attempt_item_link(mob/user, atom/target) + SHOULD_CALL_PARENT(TRUE) + + var/obj/machinery/door/airlock/external/airlock = target + var/obj/machinery/access_button/button = target + + if(!istype(airlock) && !istype(button)) + return + + switch(link_stage) + if(LINK_STAGE_COMPLETE) + to_chat(user, SPAN_NOTICE("[src] has already been linked to its components.")) + return ITEM_INTERACT_COMPLETE + if(LINK_STAGE_NOT_STARTED) + if(!istype(button)) + to_chat(user, SPAN_NOTICE("[src] must have its exterior buttons linked first.")) + return ITEM_INTERACT_COMPLETE + link_stage = LINK_STAGE_EXTERIOR_BUTTONS + return attempt_item_link(user, target) + if(LINK_STAGE_EXTERIOR_BUTTONS) + if(istype(button)) + to_chat(user, SPAN_NOTICE("You link [button] to [src].")) + exterior_buttons |= button + return ITEM_INTERACT_COMPLETE + if(istype(airlock)) + link_stage = LINK_STAGE_EXTERIOR_AIRLOCKS + return attempt_item_link(user, target) + if(LINK_STAGE_EXTERIOR_AIRLOCKS) + if(istype(airlock)) + to_chat(user, SPAN_NOTICE("You link [airlock] to [src].")) + exterior_airlocks |= airlock + return ITEM_INTERACT_COMPLETE + if(istype(button)) + link_stage = LINK_STAGE_INTERIOR_BUTTONS + return attempt_item_link(user, target) + if(LINK_STAGE_INTERIOR_BUTTONS) + if(istype(button)) + to_chat(user, SPAN_NOTICE("You link [button] to [src].")) + interior_buttons |= airlock + return ITEM_INTERACT_COMPLETE + if(istype(airlock)) + link_stage = LINK_STAGE_INTERIOR_AIRLOCKS + return attempt_item_link(user, target) + if(LINK_STAGE_INTERIOR_AIRLOCKS) + if(istype(airlock)) + to_chat(user, SPAN_NOTICE("You link [airlock] to [src].")) + interior_airlocks |= airlock + return ITEM_INTERACT_COMPLETE + +/obj/item/mounted/frame/airlock_controller/proc/setup_controller(obj/machinery/airlock_controller/controller) + for(var/obj/machinery/door/airlock/airlock in interior_airlocks) + airlock.id_tag = controller.int_door_link_id + if(access_electronics) + access_electronics.apply_access_to(airlock) + for(var/obj/machinery/access_button/button in interior_buttons) + button.autolink_id = controller.int_button_link_id + if(access_electronics) + access_electronics.apply_access_to(button) + for(var/obj/machinery/door/airlock/airlock in exterior_airlocks) + airlock.id_tag = controller.ext_door_link_id + if(access_electronics) + access_electronics.apply_access_to(airlock) + for(var/obj/machinery/access_button/button in exterior_buttons) + button.autolink_id = controller.ext_button_link_id + if(access_electronics) + access_electronics.apply_access_to(button) + +/obj/item/mounted/frame/airlock_controller/access_controller + name = "airlock access controller frame" + desc = "Used for building airlock chambers." + result_controller_type = /obj/machinery/airlock_controller/access_controller + +/obj/item/mounted/frame/airlock_controller/air_cycler + name = "cycling airlock controller frame" + desc = "Used for building cycling airlocks." + icon_state = "airlock_control_off" + result_controller_type = /obj/machinery/airlock_controller/air_cycler + + var/list/vents = list() + +/obj/item/mounted/frame/airlock_controller/air_cycler/Destroy() + . = ..() + vents.Cut() + +/obj/item/mounted/frame/airlock_controller/air_cycler/examine(mob/user) + . = ..() + switch(link_stage) + if(LINK_STAGE_INTERIOR_AIRLOCKS) + . += SPAN_NOTICE("It requires its vents linked next.") + +/obj/item/mounted/frame/airlock_controller/air_cycler/setup_controller(obj/machinery/airlock_controller/air_cycler/controller) + . = ..() + for(var/obj/machinery/atmospherics/unary/vent_pump/vent in vents) + vent.autolink_id = controller.vent_link_id + +/obj/item/mounted/frame/airlock_controller/air_cycler/attempt_item_link(mob/user, atom/target) + . = ..() + + if(.) + return + + var/obj/machinery/atmospherics/unary/vent_pump/vent = target + switch(link_stage) + if(LINK_STAGE_INTERIOR_AIRLOCKS) + if(istype(vent)) + link_stage = LINK_STAGE_VENTS + return attempt_item_link(user, target) + if(LINK_STAGE_VENTS) + if(istype(vent)) + to_chat(user, SPAN_NOTICE("You link [vent] to [src].")) + vents |= vent + return ITEM_INTERACT_COMPLETE + +/obj/item/mounted/frame/airlock_controller/air_cycler/get_missing_items() + . = ..() + if(!length(vents)) + . += "vent" + +#undef LINK_STAGE_NOT_STARTED +#undef LINK_STAGE_EXTERIOR_BUTTONS +#undef LINK_STAGE_EXTERIOR_AIRLOCKS +#undef LINK_STAGE_INTERIOR_BUTTONS +#undef LINK_STAGE_INTERIOR_AIRLOCKS +#undef LINK_STAGE_VENTS +#undef LINK_STAGE_COMPLETE diff --git a/code/game/objects/items/mountable_frames/mountables.dm b/code/game/objects/items/mountable_frames/mountables.dm index 2d098a1a3e8..b1978fcc421 100644 --- a/code/game/objects/items/mountable_frames/mountables.dm +++ b/code/game/objects/items/mountable_frames/mountables.dm @@ -11,7 +11,7 @@ if(is_type_in_list(target, buildon_types)) if(try_build(target, user)) do_build(target, user) - return ITEM_INTERACT_COMPLETE + return ITEM_INTERACT_COMPLETE ..() /obj/item/mounted/proc/try_build(turf/on_wall, mob/user) //checks diff --git a/code/game/objects/items/rpd.dm b/code/game/objects/items/rpd.dm index b18348ef104..edf3c96c3ef 100644 --- a/code/game/objects/items/rpd.dm +++ b/code/game/objects/items/rpd.dm @@ -115,7 +115,7 @@ P = new(T, whatpipe, iconrotation) //Make the pipe, BUT WAIT! There's more! if(!iconrotation && P.is_bent_pipe()) //Automatically rotates dispensed pipes if the user selected auto-rotation P.dir = turn(user.dir, 135) - else if(!iconrotation && (P.pipe_type in list(PIPE_CONNECTOR, PIPE_UVENT, PIPE_SCRUBBER, PIPE_HEAT_EXCHANGE, PIPE_CAP, PIPE_SUPPLY_CAP, PIPE_SCRUBBERS_CAP, PIPE_INJECTOR, PIPE_PASV_VENT))) //Some pipes dispense oppositely to what you'd expect, but we don't want to do anything if they selected a direction + else if(!iconrotation && (P.pipe_type in list(PIPE_CONNECTOR, PIPE_UVENT, PIPE_SCRUBBER, PIPE_HEAT_EXCHANGE, PIPE_CAP, PIPE_SUPPLY_CAP, PIPE_SCRUBBERS_CAP, PIPE_INJECTOR, PIPE_PASV_VENT, PIPE_HIGH_VOLUME_PUMP))) //Some pipes dispense oppositely to what you'd expect, but we don't want to do anything if they selected a direction P.dir = turn(user.dir, -180) else if(iconrotation && P.is_bent_pipe()) //If user selected a rotation and the pipe is bent P.dir = turn(iconrotation, -45) diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index fbb72ef326b..0ca7f6557e9 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -75,7 +75,9 @@ GLOBAL_LIST_INIT(metal_recipes, list( new /datum/stack_recipe("extinguisher cabinet frame", /obj/item/mounted/frame/extinguisher, 2), new /datum/stack_recipe/barsign_frame("bar sign frame", /obj/machinery/barsign, 4), new /datum/stack_recipe("mass driver button frame", /obj/item/mounted/frame/driver_button, 1, time = 5 SECONDS, one_per_turf = FALSE, on_floor = TRUE), - + new /datum/stack_recipe("airlock access button frame", /obj/item/mounted/frame/airlock_button, 2), + new /datum/stack_recipe("airlock controller frame", /obj/item/mounted/frame/airlock_controller/access_controller, 2), + new /datum/stack_recipe("cycling airlock controller frame", /obj/item/mounted/frame/airlock_controller/air_cycler, 2), )), new /datum/stack_recipe_list("construction", list( new /datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 5 SECONDS, one_per_turf = TRUE, on_floor = TRUE), diff --git a/paradise.dme b/paradise.dme index 646e29947fa..bddbcdc8037 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1400,6 +1400,7 @@ #include "code\game\objects\items\granters\crafting_granters\_crafting_granter.dm" #include "code\game\objects\items\granters\crafting_granters\combat_baking.dm" #include "code\game\objects\items\mountable_frames\air_alarm_frame.dm" +#include "code\game\objects\items\mountable_frames\airlock_chamber_frames.dm" #include "code\game\objects\items\mountable_frames\apc_frame.dm" #include "code\game\objects\items\mountable_frames\buttons_switches.dm" #include "code\game\objects\items\mountable_frames\extinguisher_frame.dm"