[MIRROR] Airlock Seals 2: I'm dumb and a fool edition (#791)
* Airlock Seals 2: I'm dumb and a fool edition (#53114) Adds door seals to the game, inspired by the ones used in Alien Isolation and SOMA. Trivially easy for a human to remove, but makes it a nightmare to try and smash through if you're an alien, an evil robot, or don't have hands. I also slightly changed how airlock reinforcement works, as now there are two ways to increase the integrity, the previous way of just resetting the max_integrity after the removal of the plating wouldn't work. * Airlock Seals 2: I'm dumb and a fool edition Co-authored-by: Jimmius <huw4@btinternet.com>
@@ -34,6 +34,8 @@
|
||||
|
||||
#define AIRLOCK_INTEGRITY_N 300 // Normal airlock integrity
|
||||
#define AIRLOCK_INTEGRITY_MULTIPLIER 1.5 // How much reinforced doors health increases
|
||||
/// How much extra health airlocks get when braced with a seal
|
||||
#define AIRLOCK_SEAL_MULTIPLIER 2
|
||||
#define AIRLOCK_DAMAGE_DEFLECTION_N 21 // Normal airlock damage deflection
|
||||
#define AIRLOCK_DAMAGE_DEFLECTION_R 30 // Reinforced airlock damage deflection
|
||||
|
||||
@@ -70,6 +72,8 @@
|
||||
var/obj/item/electronics/airlock/electronics
|
||||
COOLDOWN_DECLARE(shockCooldown)
|
||||
var/obj/item/note //Any papers pinned to the airlock
|
||||
/// The seal on the airlock
|
||||
var/obj/item/seal
|
||||
var/detonated = FALSE
|
||||
var/abandoned = FALSE
|
||||
var/doorOpen = 'sound/machines/airlock.ogg'
|
||||
@@ -294,6 +298,7 @@
|
||||
for(var/obj/machinery/door_buttons/D in GLOB.machines)
|
||||
D.removeMe(src)
|
||||
QDEL_NULL(note)
|
||||
QDEL_NULL(seal)
|
||||
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
|
||||
diag_hud.remove_from_hud(src)
|
||||
return ..()
|
||||
@@ -302,6 +307,9 @@
|
||||
if(A == note)
|
||||
note = null
|
||||
update_icon()
|
||||
if(A == seal)
|
||||
seal = null
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/door/airlock/bumpopen(mob/living/user) //Airlocks now zap you when you 'bump' them open when they're electrified. --NeoFite
|
||||
if(!issilicon(usr))
|
||||
@@ -431,6 +439,7 @@
|
||||
var/mutable_appearance/damag_overlay
|
||||
var/mutable_appearance/sparks_overlay
|
||||
var/mutable_appearance/note_overlay
|
||||
var/mutable_appearance/seal_overlay
|
||||
var/notetype = note_type()
|
||||
|
||||
switch(state)
|
||||
@@ -447,6 +456,8 @@
|
||||
panel_overlay = get_airlock_overlay("panel_closed", overlays_file)
|
||||
if(welded)
|
||||
weld_overlay = get_airlock_overlay("welded", overlays_file)
|
||||
if(seal)
|
||||
seal_overlay = get_airlock_overlay("sealed", overlays_file)
|
||||
if(obj_integrity < integrity_failure * max_integrity)
|
||||
damag_overlay = get_airlock_overlay("sparks_broken", overlays_file)
|
||||
else if(obj_integrity < (0.75 * max_integrity))
|
||||
@@ -478,6 +489,8 @@
|
||||
damag_overlay = get_airlock_overlay("sparks_damaged", overlays_file)
|
||||
if(welded)
|
||||
weld_overlay = get_airlock_overlay("welded", overlays_file)
|
||||
if(seal)
|
||||
seal_overlay = get_airlock_overlay("sealed", overlays_file)
|
||||
lights_overlay = get_airlock_overlay("lights_denied", overlays_file)
|
||||
if(note)
|
||||
note_overlay = get_airlock_overlay(notetype, note_overlay_file)
|
||||
@@ -500,6 +513,8 @@
|
||||
damag_overlay = get_airlock_overlay("sparks_damaged", overlays_file)
|
||||
if(welded)
|
||||
weld_overlay = get_airlock_overlay("welded", overlays_file)
|
||||
if(seal)
|
||||
seal_overlay = get_airlock_overlay("sealed", overlays_file)
|
||||
if(note)
|
||||
note_overlay = get_airlock_overlay(notetype, note_overlay_file)
|
||||
|
||||
@@ -560,6 +575,7 @@
|
||||
add_overlay(sparks_overlay)
|
||||
add_overlay(damag_overlay)
|
||||
add_overlay(note_overlay)
|
||||
add_overlay(seal_overlay)
|
||||
check_unres()
|
||||
|
||||
/proc/get_airlock_overlay(icon_state, icon_file)
|
||||
@@ -618,7 +634,8 @@
|
||||
else
|
||||
. += "There's a [note.name] pinned to the front..."
|
||||
. += note.examine(user)
|
||||
|
||||
if(seal)
|
||||
. += "It's been braced with a pneumatic seal."
|
||||
if(panel_open)
|
||||
switch(security_level)
|
||||
if(AIRLOCK_SECURITY_NONE)
|
||||
@@ -813,7 +830,7 @@
|
||||
user.visible_message("<span class='notice'>[user] reinforces \the [src] with plasteel.</span>",
|
||||
"<span class='notice'>You reinforce \the [src] with plasteel.</span>")
|
||||
security_level = AIRLOCK_SECURITY_PLASTEEL
|
||||
modify_max_integrity(normal_integrity * AIRLOCK_INTEGRITY_MULTIPLIER)
|
||||
modify_max_integrity(max_integrity * AIRLOCK_INTEGRITY_MULTIPLIER)
|
||||
damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_R
|
||||
update_icon()
|
||||
return
|
||||
@@ -844,7 +861,7 @@
|
||||
user.visible_message("<span class='notice'>[user] remove \the [src]'s shielding.</span>",
|
||||
"<span class='notice'>You remove \the [src]'s inner shielding.</span>")
|
||||
security_level = AIRLOCK_SECURITY_NONE
|
||||
modify_max_integrity(normal_integrity)
|
||||
modify_max_integrity(max_integrity / AIRLOCK_INTEGRITY_MULTIPLIER)
|
||||
damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_N
|
||||
spawn_atom_to_turf(/obj/item/stack/sheet/plasteel, user.loc, 1)
|
||||
update_icon()
|
||||
@@ -922,6 +939,33 @@
|
||||
cable.plugin(src, user)
|
||||
else if(istype(C, /obj/item/airlock_painter))
|
||||
change_paintjob(C, user)
|
||||
else if(istype(C, /obj/item/door_seal)) //adding the seal
|
||||
var/obj/item/door_seal/airlockseal = C
|
||||
if(!density)
|
||||
to_chat(user, "<span class='warning'>[src] must be closed before you can seal it!</span>")
|
||||
return
|
||||
if(seal)
|
||||
to_chat(user, "<span class='warning'>[src] has already been sealed!</span>")
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user] begins sealing [src].</span>", "<span class='notice'>You begin sealing [src].</span>")
|
||||
playsound(src, 'sound/items/jaws_pry.ogg', 30, TRUE)
|
||||
if(!do_after(user, airlockseal.seal_time, target = src))
|
||||
return
|
||||
if(!density)
|
||||
to_chat(user, "<span class='warning'>[src] must be closed before you can seal it!</span>")
|
||||
return
|
||||
if(seal)
|
||||
to_chat(user, "<span class='warning'>[src] has already been sealed!</span>")
|
||||
return
|
||||
if(!user.transferItemToLoc(airlockseal, src))
|
||||
to_chat(user, "<span class='warning'>For some reason, you can't attach [airlockseal]!</span>")
|
||||
return
|
||||
playsound(src, 'sound/machines/airlockforced.ogg', 30, TRUE)
|
||||
user.visible_message("<span class='notice'>[user] finishes sealing [src].</span>", "<span class='notice'>You finish sealing [src].</span>")
|
||||
seal = airlockseal
|
||||
modify_max_integrity(max_integrity * AIRLOCK_SEAL_MULTIPLIER)
|
||||
update_icon()
|
||||
|
||||
else if(istype(C, /obj/item/paper) || istype(C, /obj/item/photo))
|
||||
if(note)
|
||||
to_chat(user, "<span class='warning'>There's already something pinned to this airlock! Use wirecutters to remove it.</span>")
|
||||
@@ -938,6 +982,9 @@
|
||||
|
||||
/obj/machinery/door/airlock/try_to_weld(obj/item/weldingtool/W, mob/user)
|
||||
if(!operating && density)
|
||||
if(seal)
|
||||
to_chat(user, "<span class='warning'>[src] is blocked by a seal!</span>")
|
||||
return
|
||||
if(user.a_intent != INTENT_HELP)
|
||||
if(!W.tool_start_check(user, amount=0))
|
||||
return
|
||||
@@ -968,6 +1015,36 @@
|
||||
/obj/machinery/door/airlock/proc/weld_checks(obj/item/weldingtool/W, mob/user)
|
||||
return !operating && density
|
||||
|
||||
/**
|
||||
* Used when attempting to remove a seal from an airlock
|
||||
*
|
||||
* Called when attacking an airlock with an empty hand, returns TRUE (there was a seal and we removed it, or failed to remove it)
|
||||
* or FALSE (there was no seal)
|
||||
* Arguments:
|
||||
* * user - Whoever is attempting to remove the seal
|
||||
*/
|
||||
/obj/machinery/door/airlock/try_remove_seal(mob/living/user)
|
||||
if(!seal)
|
||||
return FALSE
|
||||
var/obj/item/door_seal/airlockseal = seal
|
||||
if(!ishuman(user))
|
||||
to_chat(user, text("<span class='warning'>You don't have the dexterity to remove the seal!</span>"))
|
||||
return TRUE
|
||||
user.visible_message("<span class='notice'>[user] begins removing the seal from [src].</span>", "<span class='notice'>You begin removing [src]'s pneumatic seal.</span>")
|
||||
playsound(src, 'sound/machines/airlockforced.ogg', 30, TRUE)
|
||||
if(!do_after(user, airlockseal.unseal_time, target = src))
|
||||
return TRUE
|
||||
if(!seal)
|
||||
return TRUE
|
||||
playsound(src, 'sound/items/jaws_pry.ogg', 30, TRUE)
|
||||
airlockseal.forceMove(get_turf(user))
|
||||
user.visible_message("<span class='notice'>[user] finishes removing the seal from [src].</span>", "<span class='notice'>You finish removing [src]'s pneumatic seal.</span>")
|
||||
seal = null
|
||||
modify_max_integrity(max_integrity / AIRLOCK_SEAL_MULTIPLIER)
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/machinery/door/airlock/try_to_crowbar(obj/item/I, mob/living/user, forced = FALSE)
|
||||
if(I)
|
||||
var/beingcrowbarred = (I.tool_behaviour == TOOL_CROWBAR)
|
||||
@@ -977,6 +1054,9 @@
|
||||
if(I.use_tool(src, user, 40, volume=100))
|
||||
deconstruct(TRUE, user)
|
||||
return
|
||||
if(seal)
|
||||
to_chat(user, "<span class='warning'>Remove the seal first!</span>")
|
||||
return
|
||||
if(locked)
|
||||
to_chat(user, "<span class='warning'>The airlock's bolts prevent it from being forced!</span>")
|
||||
return
|
||||
@@ -1018,7 +1098,7 @@
|
||||
|
||||
|
||||
/obj/machinery/door/airlock/open(forced=0)
|
||||
if( operating || welded || locked )
|
||||
if( operating || welded || locked || seal )
|
||||
return FALSE
|
||||
if(!forced)
|
||||
if(!hasPower() || wires.is_cut(WIRE_OPEN))
|
||||
@@ -1060,7 +1140,7 @@
|
||||
|
||||
|
||||
/obj/machinery/door/airlock/close(forced=0)
|
||||
if(operating || welded || locked)
|
||||
if(operating || welded || locked || seal)
|
||||
return
|
||||
if(density)
|
||||
return TRUE
|
||||
@@ -1175,7 +1255,7 @@
|
||||
return
|
||||
if(!density) //Already open
|
||||
return ..()
|
||||
if(locked || welded) //Extremely generic, as aliens only understand the basics of how airlocks work.
|
||||
if(locked || welded || seal) //Extremely generic, as aliens only understand the basics of how airlocks work.
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return ..()
|
||||
to_chat(user, "<span class='warning'>[src] refuses to budge!</span>")
|
||||
@@ -1294,6 +1374,9 @@
|
||||
/obj/machinery/door/airlock/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
|
||||
switch(the_rcd.mode)
|
||||
if(RCD_DECONSTRUCT)
|
||||
if(seal)
|
||||
to_chat(user, "<span class='notice'>[src]'s seal needs to be removed first.</span>")
|
||||
return FALSE
|
||||
if(security_level != AIRLOCK_SECURITY_NONE)
|
||||
to_chat(user, "<span class='notice'>[src]'s reinforcement needs to be removed first.</span>")
|
||||
return FALSE
|
||||
@@ -1499,6 +1582,7 @@
|
||||
|
||||
#undef AIRLOCK_INTEGRITY_N
|
||||
#undef AIRLOCK_INTEGRITY_MULTIPLIER
|
||||
#undef AIRLOCK_SEAL_MULTIPLIER
|
||||
#undef AIRLOCK_DAMAGE_DEFLECTION_N
|
||||
#undef AIRLOCK_DAMAGE_DEFLECTION_R
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
var/safety_mode = FALSE ///Whether or not the airlock can be opened with bare hands while unpowered
|
||||
var/can_crush = TRUE /// Whether or not the door can crush mobs.
|
||||
|
||||
|
||||
/obj/machinery/door/examine(mob/user)
|
||||
. = ..()
|
||||
if(red_alert_access)
|
||||
@@ -97,6 +98,17 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Called when attempting to remove the seal from an airlock
|
||||
*
|
||||
* Here because we need to call it and return if there was a seal so we don't try to open the door
|
||||
* or try its safety lock while it's sealed
|
||||
* Arguments:
|
||||
* * user - the mob attempting to remove the seal
|
||||
*/
|
||||
/obj/machinery/door/proc/try_remove_seal(mob/user)
|
||||
return
|
||||
|
||||
/obj/machinery/door/Bumped(atom/movable/AM)
|
||||
. = ..()
|
||||
if(operating || (obj_flags & EMAGGED))
|
||||
@@ -159,6 +171,8 @@
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(try_remove_seal(user))
|
||||
return
|
||||
if(try_safety_unlock(user))
|
||||
return
|
||||
return try_to_activate_door(user)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/obj/item/door_seal
|
||||
name = "pneumatic seal"
|
||||
desc = "A brace used to seal and reinforce an airlock. Useful for making areas inaccessible to those without opposable thumbs."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "pneumatic_seal"
|
||||
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
flags_1 = CONDUCT_1
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
force = 5
|
||||
throwforce = 5
|
||||
throw_speed = 2
|
||||
throw_range = 1
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
custom_materials = list(/datum/material/iron=5000,/datum/material/plasma=500)
|
||||
/// how long the seal takes to place on the door
|
||||
var/seal_time = 3 SECONDS
|
||||
/// how long it takes to remove the seal from a door
|
||||
var/unseal_time = 2 SECONDS
|
||||
|
||||
/obj/item/door_seal/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is sealing [user.p_them()]self off from the world with [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
playsound(src, 'sound/items/jaws_pry.ogg', 30, TRUE)
|
||||
return(BRUTELOSS)
|
||||
|
||||
@@ -324,6 +324,15 @@
|
||||
build_path = /obj/item/bikehorn/rubberducky/plasticducky
|
||||
category = list("Equipment")
|
||||
|
||||
/datum/design/pneumatic_seal
|
||||
name = "Pneumatic Seal"
|
||||
desc = "A heavy brace used to seal doors. Useful for keeping out people without the dexterity to remove it."
|
||||
id = "pneumatic_seal"
|
||||
build_type = PROTOLATHE
|
||||
materials = list(/datum/material/iron = 20000, /datum/material/plasma = 10000)
|
||||
build_path = /obj/item/door_seal
|
||||
category = list("Equipment")
|
||||
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING | DEPARTMENTAL_FLAG_SECURITY
|
||||
|
||||
/////////////////////////////////////////
|
||||
////////////Janitor Designs//////////////
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
design_ids = list("solarcontrol", "recharger", "powermonitor", "rped", "pacman", "adv_capacitor", "adv_scanning", "w-recycler" , "emitter", "high_cell", "adv_matter_bin", "scanner_gate",
|
||||
"atmosalerts", "atmos_control", "recycler", "autolathe", "high_micro_laser", "nano_mani", "mesons", "welding_goggles", "thermomachine", "rad_collector", "tesla_coil", "grounding_rod",
|
||||
"apc_control", "cell_charger", "power control", "airlock_board", "firelock_board", "airalarm_electronics", "firealarm_electronics", "cell_charger", "stack_console", "stack_machine",
|
||||
"oxygen_tank", "plasma_tank", "emergency_oxygen", "emergency_oxygen_engi", "plasmaman_tank_belt", "electrolyzer", "adv_electrolite")
|
||||
"oxygen_tank", "plasma_tank", "emergency_oxygen", "emergency_oxygen_engi", "plasmaman_tank_belt", "electrolyzer", "adv_electrolite", "pneumatic_seal")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 7500)
|
||||
|
||||
/datum/techweb_node/adv_engi
|
||||
|
||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
@@ -984,6 +984,7 @@
|
||||
#include "code\game\objects\items\dice.dm"
|
||||
#include "code\game\objects\items\dna_injector.dm"
|
||||
#include "code\game\objects\items\documents.dm"
|
||||
#include "code\game\objects\items\door_seal.dm"
|
||||
#include "code\game\objects\items\dualsaber.dm"
|
||||
#include "code\game\objects\items\eightball.dm"
|
||||
#include "code\game\objects\items\emags.dm"
|
||||
|
||||