Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Upstream 20.01.2025 #1755

Merged
merged 32 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
166b1d5
Migrates the hand labeler to the new attack chain (#27400)
Toastical Jan 16, 2025
fc3f10b
[FIX] SM monitoring console crash (#27971)
Erikos66 Jan 17, 2025
062fa17
Holopads now only activate on help intent (#27970)
Contrabang Jan 17, 2025
c231006
im lovin it (#27975)
ArcZelf Jan 17, 2025
55ea766
fluff items purged... (#28006)
haydenredacted Jan 17, 2025
d5b206c
Adds the handheld mirror to the base contractor loadout. (#27838)
adddfff33 Jan 17, 2025
6f77bf1
Attack Chain Migration: Wirecutters (#27567)
Toastical Jan 17, 2025
dac5700
[PORT] Add mantis blades (new traitor item) (#27594)
MiraHell Jan 17, 2025
93ed0f0
Refactors AI / camera eyes and slows holopad holograms to walk speed …
asciodev Jan 17, 2025
b1fa5f9
wrenching (#27564)
Toastical Jan 18, 2025
4815d1a
makes carp infestation less likely to happen (#27931)
haydenredacted Jan 18, 2025
f907e8a
Re-buff immovable rods (#27985)
FunnyMan3595 Jan 18, 2025
d0982f9
Cheeseboard Crate (#28000)
ExusA Jan 18, 2025
66c663b
poor borgs (#28013)
MiraHell Jan 18, 2025
4d7e14f
[FIX] Fix for a runtime error in deathsquad.dm (#28012)
Drsmail Jan 18, 2025
8e254c4
Makes Nanofrost Pretty (#28016)
PollardTheDragon Jan 18, 2025
a9d36a6
Bookcase rework/resprite (#28003)
McRamon Jan 18, 2025
a236b9c
Fix sword sheaths disappearing when clicked with telekinesis (#27998)
MiraHell Jan 18, 2025
b109c28
Fix cyborg arm sprite (#27997)
MiraHell Jan 18, 2025
db65295
Small device resprite (#27987)
McRamon Jan 18, 2025
c375e37
make hud permanent (#27992)
MiraHell Jan 18, 2025
a521827
get_out_of_the_closet (#27986)
McRamon Jan 18, 2025
9328128
Advertises double-examine lore blurbs on a single examine (#27974)
ExusA Jan 18, 2025
1491299
updated the engineering and service icons (#27967)
haydenredacted Jan 18, 2025
4af0352
Fix: Economy machinery now uses TGUI input + global bank pin range de…
Toastical Jan 18, 2025
97e99fe
make all sec clothing in the loadout menu available to the detective …
Kenionatus Jan 18, 2025
61802a7
fix random bookcase icon (#28034)
MiraHell Jan 19, 2025
fa333bb
Attack Chain Migration: Screwdriver (#27563)
Toastical Jan 19, 2025
8954a8e
"Dynamic" Gamemode using rulesets (#27600)
Contrabang Jan 19, 2025
fdbd2b2
Assorted atmos performance improvements. (#27966)
FunnyMan3595 Jan 20, 2025
ec19a38
Merge remote-tracking branch 'origin/master' into merge-upstream
m-dzianishchyts Jan 20, 2025
90e42e7
Build Rust library
paradisess13[bot] Jan 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion _maps/map_files/RandomRuins/SpaceRuins/rocky_motel.dmm
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@
/area/ruin/space/powered)
"lq" = (
/obj/structure/closet/cabinet,
/obj/item/clothing/suit/jacket/fluff,
/obj/item/clothing/under/color/random,
/obj/item/clothing/under/suit/navy,
/obj/item/clothing/under/pants/blackjeans,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@
/area/ruin/space/powered)
"nz" = (
/obj/structure/closet/cabinet,
/obj/item/clothing/suit/jacket/fluff,
/obj/item/clothing/under/color/random,
/obj/item/clothing/under/suit/navy,
/obj/item/clothing/under/pants/blackjeans,
Expand Down
12 changes: 12 additions & 0 deletions code/__DEFINES/dcs/datum_signals.dm
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
#define COMPONENT_TWOHANDED_BLOCK_WIELD (1<<0)
///from base of datum/component/two_handed/proc/unwield(mob/living/carbon/user): (/mob/user)
#define COMSIG_TWOHANDED_UNWIELD "twohanded_unwield"
///from base of /datum/component/forces_doors_open/proc/force_open_door(obj/item): (datum/source, mob/user, atom/target)
#define COMSIG_TWOHANDED_WIELDED_TRY_WIELD_INTERACT "twohanded_wielded_try_wield_interact"


// /datum/action
Expand Down Expand Up @@ -122,3 +124,13 @@
/// Sent when bodies transfer between shades/shards and constructs
/// from base of /datum/component/construct_held_body/proc/transfer_held_body()
#define COMSIG_SHADE_TO_CONSTRUCT_TRANSFER "shade_to_construct_transfer"


/// /datum/component/label
/// Called when a handlabeler is used on an item when off
#define COMSIG_LABEL_REMOVE "label_remove"

// /datum/ruleset

/// from base of /datum/ruleset/proc/can_apply()
#define COMSIG_RULESET_FAILED_SPECIES "failed_species"
2 changes: 2 additions & 0 deletions code/__DEFINES/directions.dm
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@
#define DIR_JUST_HORIZONTAL(dir) ((dir == EAST) || (dir == WEST))
/// returns TRUE if the direction is NORTH or SOUTH
#define DIR_JUST_VERTICAL(dir) ((dir == NORTH) || (dir == SOUTH))

#define EXCLUSIVE_OR(thing_one, thing_two) ((thing_one)^(thing_two))
11 changes: 11 additions & 0 deletions code/__DEFINES/gamemode.dm
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,14 @@
#define NUKE_SITE_OFF_STATION_ZLEVEL 2
/// The bomb's location cannot be found.
#define NUKE_SITE_INVALID 3

/**
* Dynamic Gamemode Defines
*/
#define DYNAMIC_RULESET_NORMAL "Normal"
#define DYNAMIC_RULESET_FORCED "<b>Forced</b>"
#define DYNAMIC_RULESET_BANNED "<b>Banned</b>"

#define RULESET_FAILURE_BUDGET "Not enough budget"
#define RULESET_FAILURE_NO_PLAYERS "No drafted players"
#define RULESET_FAILURE_CHANGELING_SECONDARY_RULESET "Needs a secondary ruleset in rotation"
4 changes: 4 additions & 0 deletions code/__DEFINES/misc_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,7 @@ do { \
#define LAVALAND_TENDRIL_COLLAPSE_RANGE 2 //! The radius of the chasm created by killed tendrils.

#define ALPHA_VISIBLE 255 // the max alpha

/// Economy account defines
#define BANK_PIN_MIN 10000
#define BANK_PIN_MAX 99999
4 changes: 2 additions & 2 deletions code/__DEFINES/mob_defines.dm
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@
#define ismorph(A) (istype((A), /mob/living/simple_animal/hostile/morph))

#define issilicon(A) (istype((A), /mob/living/silicon))
#define isAI(A) (istype((A), /mob/living/silicon/ai))
#define is_ai(A) (istype((A), /mob/living/silicon/ai))
#define isrobot(A) (istype((A), /mob/living/silicon/robot))
#define isdrone(A) (istype((A), /mob/living/silicon/robot/drone))
#define ispAI(A) (istype((A), /mob/living/silicon/pai))
Expand All @@ -273,7 +273,7 @@
#define ispathanimal(A) (ispath(A, /mob/living/simple_animal))

#define iscameramob(A) (istype((A), /mob/camera))
#define isAIEye(A) (istype((A), /mob/camera/ai_eye))
#define is_ai_eye(A) (istype((A), /mob/camera/eye))
#define isovermind(A) (istype((A), /mob/camera/blob))

#define isSpirit(A) (istype((A), /mob/spirit))
Expand Down
2 changes: 0 additions & 2 deletions code/__HELPERS/trait_helpers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_WIELDED "wielded"
/// Wires on this will have their titles randomized for those with SHOW_WIRES
#define TRAIT_OBSCURED_WIRES "obscured_wires"
/// Forces open doors after a delay specific to the item
#define TRAIT_FORCES_OPEN_DOORS_ITEM "forces_open_doors_item_varient"
/// Makes the item no longer spit out a visible message when thrown
#define TRAIT_NO_THROWN_MESSAGE "no_message_when_thrown"
/// Makes the item not display a message on storage insertion
Expand Down
2 changes: 1 addition & 1 deletion code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@ Returns 1 if the chain up to the area contains the given typepath
continue

O.loc.Exited(O)
O.setLoc(X)
O.set_loc(X)
O.loc.Entered(O)

for(var/mob/M in T)
Expand Down
1 change: 0 additions & 1 deletion code/_globalvars/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SUPERMATTER_IMMUNE" = TRAIT_SUPERMATTER_IMMUNE,
"TRAIT_BUTCHER_HUMANS" = TRAIT_BUTCHERS_HUMANS,
"TRAIT_CMAGGED" = TRAIT_CMAGGED,
"TRAIT_FORCES_OPEN_DOORS" = TRAIT_FORCES_OPEN_DOORS_ITEM,
"TRAIT_OBSCURED_WIRES" = TRAIT_OBSCURED_WIRES,
"TRAIT_XENO_INTERACTABLE" = TRAIT_XENO_INTERACTABLE,
"TRAIT_NO_THROWN_MESSAGE" = TRAIT_NO_THROWN_MESSAGE,
Expand Down
12 changes: 6 additions & 6 deletions code/_onclick/ai_onclick.dm
Original file line number Diff line number Diff line change
Expand Up @@ -102,20 +102,20 @@
add_attack_logs(src, src, "[key_name_admin(src)] might be running a modified client! (failed can_see on AI click of [A]([ADMIN_COORDJMP(pixel_turf)]))", ATKLOG_ALL)
var/message = "[key_name(src)] might be running a modified client! (failed can_see on AI click of [A]([COORD(pixel_turf)]))"
log_admin(message)
GLOB.discord_manager.send2discord_simple_noadmins("**\[Warning]** [key_name(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(pixel_turf)]))")
GLOB.discord_manager.send2discord_simple_noadmins("**\[Warning]** [key_name(src)] might be running a modified client! (failed check_turf_vis on AI click of [A]([COORD(pixel_turf)]))")
return FALSE

var/turf_visible
if(pixel_turf)
turf_visible = GLOB.cameranet.checkTurfVis(pixel_turf)
turf_visible = GLOB.cameranet.check_turf_vis(pixel_turf)
if(!turf_visible)
if((istype(loc, /obj/item/aicard) || ismecha(loc)) && (pixel_turf in range(client.view, loc)))
turf_visible = TRUE
else
if(pixel_turf.obscured)
log_admin("[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(pixel_turf)])")
add_attack_logs(src, src, "[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([ADMIN_COORDJMP(pixel_turf)]))", ATKLOG_ALL)
GLOB.discord_manager.send2discord_simple_noadmins("**\[Warning]** [key_name(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(pixel_turf)]))")
log_admin("[key_name_admin(src)] might be running a modified client! (failed check_turf_vis on AI click of [A]([COORD(pixel_turf)])")
add_attack_logs(src, src, "[key_name_admin(src)] might be running a modified client! (failed check_turf_vis on AI click of [A]([ADMIN_COORDJMP(pixel_turf)]))", ATKLOG_ALL)
GLOB.discord_manager.send2discord_simple_noadmins("**\[Warning]** [key_name(src)] might be running a modified client! (failed check_turf_vis on AI click of [A]([COORD(pixel_turf)]))")
return FALSE
return TRUE

Expand Down Expand Up @@ -184,7 +184,7 @@
return

/mob/living/silicon/ai/TurfAdjacent(turf/T)
return (GLOB.cameranet && GLOB.cameranet.checkTurfVis(T))
return (GLOB.cameranet && GLOB.cameranet.check_turf_vis(T))


// APC
Expand Down
4 changes: 2 additions & 2 deletions code/_onclick/hud/ai_hud.dm
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
/atom/movable/screen/ai/state_laws/Click()
if(..())
return
if(isAI(usr))
if(is_ai(usr))
var/mob/living/silicon/ai/AI = usr
AI.subsystem_law_manager()

Expand Down Expand Up @@ -156,7 +156,7 @@
/atom/movable/screen/ai/sensors/Click()
if(..())
return
if(isAI(usr))
if(is_ai(usr))
var/mob/living/silicon/ai/AI = usr
AI.sensor_mode()
else if(isrobot(usr))
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/hud/alert.dm
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ so as to remain in compliance with the most up-to-date laws."
var/mob/living/silicon/ai/AI = usr
var/turf/T = get_turf(target)
if(T)
AI.eyeobj.setLoc(T)
AI.eyeobj.set_loc(T)

//MECHS
/atom/movable/screen/alert/low_mech_integrity
Expand Down
38 changes: 23 additions & 15 deletions code/controllers/subsystem/SSair.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ SUBSYSTEM_DEF(air)
name = "Atmospherics"
init_order = INIT_ORDER_AIR
priority = FIRE_PRIORITY_AIR
wait = 2
flags = SS_BACKGROUND
// The MC really doesn't like it if we sleep (even though it's supposed to), and ends up running us continuously. Instead, we ask it to run us every tick, and "sleep" by skipping the current tick.
wait = 1
flags = SS_BACKGROUND | SS_TICKER
/// How long we actually wait between ticks. Will round up to the next server tick.
var/self_wait = 0.15 SECONDS
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
offline_implications = "Turfs will no longer process atmos, and all atmospheric machines (including cryotubes) will no longer function. Shuttle call recommended."
cpu_display = SS_CPUDISPLAY_HIGH

/// When did we last finish running a complete tick?
var/last_complete_tick = 0
/// When did we last start a tick?
var/last_tick_start = 0

/// How long we took for a full pass through the subsystem. Custom-tracked version of `cost`.
var/datum/resumable_cost_counter/cost_full = new()
/// How long we spent sleeping while waiting for MILLA to finish the last tick, shown in SS Info's C block as ZZZ.
Expand Down Expand Up @@ -178,26 +186,21 @@ SUBSYSTEM_DEF(air)
currentpart = SSair.currentpart
milla_idle = SSair.milla_idle

#define SLEEPABLE_TIMER (world.time + world.tick_usage * world.tick_lag / 100)
/datum/controller/subsystem/air/fire(resumed = 0)
// All atmos stuff assumes MILLA is synchronous. Ensure it actually is.
if(!milla_idle || length(sleepers) > 0)
var/timer = SLEEPABLE_TIMER

while(!milla_idle || length(sleepers) > 0)
// Sleep for 1ms.
sleep(0.01)
var/new_timer = SLEEPABLE_TIMER
time_slept.record_progress((new_timer - timer) * 100, FALSE)
timer = new_timer
var/now = world.timeofday + (world.tick_lag * world.tick_usage) / 100
var/elapsed = now - last_complete_tick
if(!milla_idle || (elapsed >= 0 && elapsed < self_wait))
return

time_slept.record_progress((SLEEPABLE_TIMER - timer) * 100, TRUE)
if(last_tick_start <= last_complete_tick)
last_tick_start = now
time_slept.record_progress(max(0, elapsed) * 100, TRUE)

// Run the sleepless callbacks again in case more showed up since on_milla_tick_finished()
run_sleepless_callbacks()

fire_sleepless(resumed)
#undef SLEEPABLE_TIMER

/datum/controller/subsystem/air/proc/fire_sleepless(resumed)
// Any proc that wants MILLA to be synchronous should not sleep.
Expand Down Expand Up @@ -317,13 +320,15 @@ SUBSYSTEM_DEF(air)
milla_idle = FALSE

cost_milla_tick = MC_AVERAGE(cost_milla_tick, get_milla_tick_time())
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING)
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
if(state == SS_PAUSED || state == SS_PAUSING)
in_milla_safe_code = FALSE
return
resumed = 0

currentpart = SSAIR_DEFERREDPIPENETS
last_complete_tick = world.timeofday + (world.tick_lag * world.tick_usage) / 100
cost_full.record_progress(0, TRUE)
in_milla_safe_code = FALSE

/datum/controller/subsystem/air/proc/build_pipenets(resumed = 0)
Expand Down Expand Up @@ -624,6 +629,9 @@ SUBSYSTEM_DEF(air)
for(var/turf/T as anything in block(low_corner, high_corner))
T.Initialize_Atmos(times_fired)
milla_load_turfs(low_corner, high_corner)
for(var/turf/T as anything in block(low_corner, high_corner))
T.milla_data.len = 0
T.milla_data = null

/datum/controller/subsystem/air/proc/setup_write_to_milla()
var/watch = start_watch()
Expand Down
2 changes: 1 addition & 1 deletion code/controllers/subsystem/SSshuttles.dm
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ SUBSYSTEM_DEF(shuttle)
var/callShuttle = 1

for(var/thing in GLOB.shuttle_caller_list)
if(isAI(thing))
if(is_ai(thing))
var/mob/living/silicon/ai/AI = thing
if(AI.stat || !AI.client)
continue
Expand Down
2 changes: 1 addition & 1 deletion code/controllers/subsystem/tickets/SStickets.dm
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ SUBSYSTEM_DEF(tickets)
if(M)
L += "([ADMIN_QUE(M,"?")]) ([ADMIN_PP(M,"PP")]) ([ADMIN_VV(M,"VV")]) ([ADMIN_TP(M,"TP")]) ([ADMIN_SM(M,"SM")]) ([admin_jump_link(M)])"
L += "(<a href='byond://?_src_=holder;openticket=[ticketNum][anchor_link_extra]'>TICKET</a>) "
L += "[isAI(M) ? "(<a href='byond://?_src_=holder;adminchecklaws=[M.UID()]'>CL</a>)" : ""] (<a href='byond://?_src_=holder;take_question=[ticketNum][anchor_link_extra]'>TAKE</a>) "
L += "[is_ai(M) ? "(<a href='byond://?_src_=holder;adminchecklaws=[M.UID()]'>CL</a>)" : ""] (<a href='byond://?_src_=holder;take_question=[ticketNum][anchor_link_extra]'>TAKE</a>) "
L += "(<a href='byond://?_src_=holder;resolve=[ticketNum][anchor_link_extra]'>RESOLVE</a>) (<a href='byond://?_src_=holder;autorespond=[ticketNum][anchor_link_extra]'>AUTO</a>) "
L += "(<a href='byond://?_src_=holder;convert_ticket=[ticketNum][anchor_link_extra]'>CONVERT</a>) :</span> <span class='[ticket_help_span]'>[one_line ? " " : "<br><br>"][msg]</span>"
return L.Join()
Expand Down
117 changes: 117 additions & 0 deletions code/datums/components/forces_doors_open.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* /datum/component/forces_doors_open
*
* This component allows item to pry open doors.
*
*/

/datum/component/forces_doors_open
/// The time it takes to open the airlock when forced
var/time_to_open
/// Whether the airlock can be forced open while powered.
var/can_force_open_while_powered
/// Whether the airlock can be forced open while unpowered.
var/can_force_open_while_unpowered
/// Whether the firedoor can be opened.
var/can_open_firedoors
/// The sound played when the airlock is forced open.
var/open_sound
/// Indicates whether no sound should be played when opening.
var/no_sound

/datum/component/forces_doors_open/Initialize(
time_to_open = 5 SECONDS,
can_force_open_while_powered = TRUE,
can_force_open_while_unpowered = TRUE,
can_open_firedoors = TRUE,
open_sound = 'sound/machines/airlock_alien_prying.ogg',
no_sound = FALSE)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE

src.time_to_open = time_to_open
src.can_force_open_while_powered = can_force_open_while_powered
src.can_force_open_while_unpowered = can_force_open_while_unpowered
src.can_open_firedoors = can_open_firedoors
src.open_sound = open_sound
src.no_sound = no_sound

RegisterSignal(parent, COMSIG_INTERACTING, PROC_REF(on_interact))

/datum/component/forces_doors_open/proc/on_interact(datum/source, mob/user, atom/target)
SIGNAL_HANDLER // COMSIG_INTERACTING

if(check_intent(user))
return

if(try_to_open_firedoor(target))
return ITEM_INTERACT_COMPLETE

if(try_to_force_open_airlock(user, target))
return ITEM_INTERACT_COMPLETE

/// check is user in harm intent
/datum/component/forces_doors_open/proc/check_intent(mob/user)
if(user.a_intent == INTENT_HARM)
return TRUE

/// try to open firedoor
/datum/component/forces_doors_open/proc/try_to_open_firedoor(atom/target)
if(can_open_firedoors && istype(target, /obj/machinery/door/firedoor)) // open firedoor and dont open blastdoors and windowdoors
INVOKE_ASYNC(src, PROC_REF(open_unpowered_door), target)
return TRUE

/// try to force open airlock
/datum/component/forces_doors_open/proc/try_to_force_open_airlock(mob/user, obj/machinery/door/airlock/airlock)
if(!istype(airlock, /obj/machinery/door/airlock)) // only airlocks have arePowerSystemsOn()
return

if(SEND_SIGNAL(parent, COMSIG_TWOHANDED_WIELDED_TRY_WIELD_INTERACT) && airlock.arePowerSystemsOn())
to_chat(user, "<span class='warning'>You need to be wielding [parent] to do that!</span>")
return TRUE

if(!airlock.density)
return TRUE

// open unpowered
if(can_force_open_while_unpowered && !airlock.arePowerSystemsOn())
INVOKE_ASYNC(src, PROC_REF(open_unpowered_door), airlock)
return TRUE

// open powered
if(can_force_open_while_powered)
INVOKE_ASYNC(src, PROC_REF(open_powered_airlock), airlock, user)
return TRUE

/// open airlock with delay
/datum/component/forces_doors_open/proc/open_powered_airlock(obj/machinery/door/airlock/airlock, mob/user)
if(!no_sound)
playsound(parent, open_sound, 100, 1)

if(do_after_once(user, time_to_open, target = airlock, attempt_cancel_message = "You decide to stop prying [airlock] with [parent]."))
if(airlock.open(TRUE))
return // successfully opened

// opening failed
if(airlock.density)
to_chat(user, "<span class='warning'>Despite your attempts, [airlock] refuses to open.</span>")

/// open door without checks
/datum/component/forces_doors_open/proc/open_unpowered_door(obj/machinery/door/door)
door.open(TRUE)

/// subtype for mantis blades
/datum/component/forces_doors_open/mantis/on_interact(datum/source, mob/user, atom/target)
if(check_intent(user))
return

if(try_to_open_firedoor(target))
return ITEM_INTERACT_COMPLETE

var/obj/item/melee/mantis_blade/secondblade = user.get_inactive_hand()
if(!istype(secondblade, /obj/item/melee/mantis_blade))
to_chat(user, "<span class='warning'>You need a second [parent] to pry open doors!</span>")
return ITEM_INTERACT_COMPLETE

if(try_to_force_open_airlock(user, target))
return ITEM_INTERACT_COMPLETE
Loading
Loading