Player-craftable Trapdoors (#68920)

Makes trapdoors player-craftable.
Player-crafted trapdoors have a tiny outline as well as being visible on examine. (Mapped in trapdoors have conspicuous = FALSE by default)
Trapdoors can be made by using a trapdoor kit (crafted via player crafting menu) on openspace.
Trapdoor electronics / assembly can be made via autolathe or engineering lathe.
A preloaded trapdoor remote (optional) can be made by crafting the electronics with a compact remote (from science lathe / circuit lab) and some cable coil.
Also allows unlinking trapdoors via a multitool, decreased trapdoor link range, and made some changes to trapdoor code.

Added change: Trapdoors now don't break with just a crowbar
Why It's Good For The Game

Trapdoors currently can only be added in by mappers and this would allow for a lot of interesting contraptions, while having player-crafted trapdoors be detectable provides some counterplay
Picture

trapdoorlookdemo
Changelog

cl
add: You can now make trapdoors. Craft a trapdoor kit and use it on an openspace tile to make one, then link and activate it with some trapdoor electronics (printable at an autolathe or the engineering lathe) and optionally a trapdoor remote (crafted in personal crafting menu).
qol: You can now unlink trapdoors by using a multitool on them.
balance: Trapdoors now won't break if you just crowbar them. You need to block them from closing, such as with a lattice, cover it up with a wall, or fully destroy the floor tile its on to get rid of them.
/cl
This commit is contained in:
RandomGamer123
2022-08-14 12:48:55 +12:00
committed by GitHub
parent f545330500
commit f7e80ff35b
7 changed files with 137 additions and 10 deletions
@@ -759,6 +759,29 @@
time = 20 SECONDS
category = CAT_MISC
/datum/crafting_recipe/trapdoor_kit
name = "Trapdoor Construction Kit"
result = /obj/item/trapdoor_kit
reqs = list(/obj/item/stack/sheet/iron = 4,
/obj/item/stack/rods = 4,
/obj/item/stack/cable_coil = 10,
/obj/item/stock_parts/manipulator = 2,
/obj/item/assembly/signaler = 1)
tool_behaviors = list(TOOL_WELDER, TOOL_SCREWDRIVER)
time = 10 SECONDS
category = CAT_MISC
/datum/crafting_recipe/trapdoor_remote
name = "Trapdoor Remote"
result = /obj/item/trapdoor_remote/preloaded // since its useless without its assembly just require an assembly to craft it
reqs = list(
/obj/item/compact_remote = 1,
/obj/item/stack/cable_coil = 5,
/obj/item/assembly/trapdoor = 1)
tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
time = 5 SECONDS
category = CAT_MISC
/datum/crafting_recipe/mousetrap
name = "Mouse Trap"
result = /obj/item/assembly/mousetrap
+101 -9
View File
@@ -2,7 +2,7 @@
///makes this file more legible
#define IS_OPEN(parent) isgroundlessturf(parent)
///distance a trapdoor will accept a link request.
#define TRAPDOOR_LINKING_SEARCH_RANGE 7
#define TRAPDOOR_LINKING_SEARCH_RANGE 4
/**
* ## trapdoor component!
@@ -15,12 +15,21 @@
var/obj/item/assembly/trapdoor/assembly
///path of the turf this should change into when the assembly is pulsed. needed for openspace trapdoors knowing what to turn back into
var/trapdoor_turf_path
/// is this trapdoor "conspicuous" (ie. it gets examine text and overlay added)
var/conspicuous
/// overlay that makes trapdoors more obvious
var/static/trapdoor_overlay
/datum/component/trapdoor/Initialize(starts_open, trapdoor_turf_path, assembly)
/datum/component/trapdoor/Initialize(starts_open, trapdoor_turf_path, assembly, conspicuous = TRUE)
if(!isopenturf(parent))
return COMPONENT_INCOMPATIBLE
src.conspicuous = conspicuous
src.assembly = assembly
if(!trapdoor_overlay)
trapdoor_overlay = mutable_appearance('icons/turf/overlays.dmi', "border_black", ABOVE_NORMAL_TURF_LAYER)
if(IS_OPEN(parent))
openspace_trapdoor_setup(trapdoor_turf_path, assembly)
else
@@ -38,14 +47,19 @@
src.trapdoor_turf_path = parent.type
if(assembly && assembly.stored_decals.len)
reapply_all_decals()
if(conspicuous)
var/turf/parent_turf = parent
parent_turf.add_overlay(trapdoor_overlay)
/datum/component/trapdoor/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_TURF_CHANGE, .proc/turf_changed_pre)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
if(!src.assembly)
RegisterSignal(SSdcs, COMSIG_GLOB_TRAPDOOR_LINK, .proc/on_link_requested)
else
RegisterSignal(assembly, COMSIG_ASSEMBLY_PULSED, .proc/toggle_trapdoor)
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), .proc/try_unlink)
/datum/component/trapdoor/UnregisterFromParent()
. = ..()
@@ -53,6 +67,33 @@
if(assembly)
UnregisterSignal(assembly, COMSIG_ASSEMBLY_PULSED)
UnregisterSignal(parent, COMSIG_TURF_CHANGE)
UnregisterSignal(parent, COMSIG_PARENT_EXAMINE)
UnregisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL))
/datum/component/trapdoor/proc/try_unlink(turf/source, mob/user, obj/item/tool)
SIGNAL_HANDLER
if(!assembly)
return
if(IS_OPEN(parent))
source.balloon_alert(user, "can't unlink trapdoor when its open")
return
source.balloon_alert(user, "unlinking trapdoor")
INVOKE_ASYNC(src, .proc/async_try_unlink, source, user, tool)
return
/datum/component/trapdoor/proc/async_try_unlink(turf/source, mob/user, obj/item/tool)
if(!do_after(user, 5 SECONDS, target=source))
return
if(IS_OPEN(parent))
source.balloon_alert(user, "can't unlink trapdoor when its open")
return
assembly.linked = FALSE
assembly.stored_decals = list()
UnregisterSignal(assembly, COMSIG_ASSEMBLY_PULSED)
UnregisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL))
RegisterSignal(SSdcs, COMSIG_GLOB_TRAPDOOR_LINK, .proc/on_link_requested)
assembly = null
source.balloon_alert(user, "trapdoor unlinked")
/datum/component/trapdoor/proc/decal_detached(datum/source, description, cleanable, directional, pic)
SIGNAL_HANDLER
@@ -76,13 +117,14 @@
///called by linking remotes to tie an assembly to the trapdoor
/datum/component/trapdoor/proc/on_link_requested(datum/source, obj/item/assembly/trapdoor/assembly)
SIGNAL_HANDLER
if(get_dist(parent, assembly) > TRAPDOOR_LINKING_SEARCH_RANGE)
if(get_dist(parent, assembly) > TRAPDOOR_LINKING_SEARCH_RANGE || assembly.linked)
return
. = LINKED_UP
src.assembly = assembly
assembly.linked = TRUE
UnregisterSignal(SSdcs, COMSIG_GLOB_TRAPDOOR_LINK)
RegisterSignal(assembly, COMSIG_ASSEMBLY_PULSED, .proc/toggle_trapdoor)
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), .proc/try_unlink)
///signal called by our assembly being pulsed
/datum/component/trapdoor/proc/toggle_trapdoor(datum/source)
@@ -96,14 +138,18 @@
/datum/component/trapdoor/proc/turf_changed_pre(datum/source, path, new_baseturfs, flags, post_change_callbacks)
SIGNAL_HANDLER
var/turf/open/dying_trapdoor = parent
if((!IS_OPEN(dying_trapdoor) && !IS_OPEN(path)) || path == /turf/open/floor/plating) //not a process of the trapdoor, so this trapdoor has been destroyed
if((flags & CHANGETURF_TRAPDOOR_INDUCED) == 0) //not a process of the trapdoor
if(!IS_OPEN(parent) && !ispath(path, /turf/closed) && !ispath(path, /turf/open/openspace)) // allow people to place tiles on plating / change tiles without breaking the trapdoor
post_change_callbacks += CALLBACK(src, /datum/component/trapdoor.proc/carry_over_trapdoor, path, conspicuous, assembly)
return
// otherwise, break trapdoor
dying_trapdoor.visible_message(span_warning("The trapdoor mechanism in [dying_trapdoor] is broken!"))
if(assembly)
assembly.linked = FALSE
assembly.stored_decals.Cut()
assembly = null
return
post_change_callbacks += CALLBACK(assembly, /obj/item/assembly/trapdoor.proc/carry_over_trapdoor, trapdoor_turf_path)
post_change_callbacks += CALLBACK(src, /datum/component/trapdoor.proc/carry_over_trapdoor, trapdoor_turf_path, conspicuous, assembly)
/**
* ## carry_over_trapdoor
@@ -111,8 +157,18 @@
* applies the trapdoor to the new turf (created by the last trapdoor)
* apparently callbacks with arguments on invoke and the callback itself have the callback args go first. interesting!
*/
/obj/item/assembly/trapdoor/proc/carry_over_trapdoor(trapdoor_turf_path, turf/new_turf)
new_turf.AddComponent(/datum/component/trapdoor, FALSE, trapdoor_turf_path, src)
/datum/component/trapdoor/proc/carry_over_trapdoor(trapdoor_turf_path, conspicuous, assembly, turf/new_turf)
new_turf.AddComponent(/datum/component/trapdoor, FALSE, trapdoor_turf_path, assembly, conspicuous)
/**
* ## on_examine
*
* examine message for conspicuous trapdoors that makes it obvious
*/
/datum/component/trapdoor/proc/on_examine(datum/source, mob/user, list/examine_text)
SIGNAL_HANDLER
if(conspicuous)
examine_text += "There seems to be a tiny gap around this tile with some wires that you might be able to pulse with a <b>multitool</b>."
/**
* ## try_opening
@@ -127,7 +183,7 @@
RegisterSignal(parent, COMSIG_TURF_DECAL_DETACHED, .proc/decal_detached)
playsound(trapdoor_turf, 'sound/machines/trapdoor/trapdoor_open.ogg', 50)
trapdoor_turf.visible_message(span_warning("[trapdoor_turf] swings open!"))
trapdoor_turf.ChangeTurf(/turf/open/openspace, flags = CHANGETURF_INHERIT_AIR)
trapdoor_turf.ChangeTurf(/turf/open/openspace, flags = CHANGETURF_INHERIT_AIR | CHANGETURF_TRAPDOOR_INDUCED)
/**
* ## try_closing
@@ -143,7 +199,7 @@
return
playsound(trapdoor_turf, 'sound/machines/trapdoor/trapdoor_shut.ogg', 50)
trapdoor_turf.visible_message(span_warning("The trapdoor mechanism in [trapdoor_turf] swings shut!"))
trapdoor_turf.ChangeTurf(trapdoor_turf_path, flags = CHANGETURF_INHERIT_AIR)
trapdoor_turf.ChangeTurf(trapdoor_turf_path, flags = CHANGETURF_INHERIT_AIR | CHANGETURF_TRAPDOOR_INDUCED)
#undef IS_OPEN
@@ -280,3 +336,39 @@
/obj/item/trapdoor_remote/preloaded/Initialize(mapload)
. = ..()
internals = new(src)
/// trapdoor parts kit, allows trapdoors to be made by players
/obj/item/trapdoor_kit
name = "trapdoor parts kit"
desc = "A kit containing all the parts needed to build a trapdoor. Can only be used on open space."
icon = 'icons/obj/improvised.dmi'
icon_state = "kitsuitcase"
var/in_use = FALSE
/obj/item/trapdoor_kit/Initialize(mapload)
. = ..()
AddElement(/datum/element/openspace_item_click_handler)
/obj/item/trapdoor_kit/handle_openspace_click(turf/target, mob/user, proximity_flag, click_parameters)
afterattack(target, user, proximity_flag, click_parameters)
/obj/item/trapdoor_kit/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(!proximity_flag)
return
var/turf/target_turf = get_turf(target)
if(!isopenspaceturf(target_turf))
return
in_use = TRUE
balloon_alert(user, "constructing trapdoor")
if(!do_after(user, 5 SECONDS, target = target))
in_use = FALSE
return
in_use = FALSE
if(!isopenspaceturf(target_turf)) // second check to make sure nothing changed during constructions
return
var/turf/new_turf = target_turf.PlaceOnTop(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
new_turf.AddComponent(/datum/component/trapdoor, starts_open = FALSE, conspicuous = TRUE)
balloon_alert(user, "trapdoor constructed")
qdel(src)
return