diff --git a/code/datums/elements/can_barricade.dm b/code/datums/elements/can_barricade.dm new file mode 100644 index 00000000000..039e715dc33 --- /dev/null +++ b/code/datums/elements/can_barricade.dm @@ -0,0 +1,64 @@ +#define PLANK_BARRICADE_AMOUNT 2 + +/datum/element/can_barricade + element_flags = ELEMENT_BESPOKE + id_arg_index = 2 + +/datum/element/can_barricade/Attach(atom/target) + . = ..() + + if(!isatom(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_PARENT_ATTACKBY, .proc/on_start_barricade) + RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/on_examine) + + target.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1 + RegisterSignal(target, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, .proc/on_requesting_context_from_item) + +/datum/element/can_barricade/Detach(atom/target) + UnregisterSignal(target, list(COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM)) + // We don't remove HAS_CONTEXTUAL_SCREENTIPS_1, since there could be other stuff still hooked to it, + // and being set without signals is not dangerous, just less performant. + // A lot of things don't do this, perhaps make a proc that checks if any signals are still set, and if not, + // remove the flag. + return ..() + +/datum/element/can_barricade/proc/on_examine(atom/source, mob/user, list/examine_texts) + SIGNAL_HANDLER + examine_texts += span_notice("This looks like it can be barricaded with planks of wood.") + +/datum/element/can_barricade/proc/on_start_barricade(atom/source, obj/item/stack/sheet/mineral/wood/plank, mob/living/user, params) + SIGNAL_HANDLER + + if(user.combat_mode || !istype(plank) || !istype(user)) + return + + if(plank.get_amount() < PLANK_BARRICADE_AMOUNT) + source.balloon_alert(user, "need [PLANK_BARRICADE_AMOUNT] [plank] sheets!") + return COMPONENT_CANCEL_ATTACK_CHAIN + + source.balloon_alert(user, "constructing barricade...") + playsound(source, 'sound/items/hammering_wood.ogg', 50, vary = TRUE) + INVOKE_ASYNC(src, .proc/barricade, source, plank, user, params) //signal handlers can't have do_afters inside of them + return COMPONENT_CANCEL_ATTACK_CHAIN + +/// when our element gets attacked by wooden planks it creates a barricade +/datum/element/can_barricade/proc/barricade(atom/source, obj/item/stack/sheet/mineral/wood/plank, mob/living/user, params) + if(!do_after(user, 5 SECONDS, target = source) || !plank.use(2) || (locate(/obj/structure/barricade/wooden/crude) in source.loc)) + return + + source.balloon_alert(user, "barricade constructed") + var/obj/structure/barricade/wooden/crude/barricade = new (source.loc) + barricade.add_fingerprint(user) + +/datum/element/can_barricade/proc/on_requesting_context_from_item(atom/source, list/context, obj/item/held_item, mob/user) + SIGNAL_HANDLER + + if(istype(held_item, /obj/item/stack/sheet/mineral/wood) && source.Adjacent(user)) + context[SCREENTIP_CONTEXT_LMB] = "Construct barricade" + return CONTEXTUAL_SCREENTIP_SET + + return NONE + +#undef PLANK_BARRICADE_AMOUNT diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 67f1abf7ee6..b5e833eb45a 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -51,10 +51,7 @@ return TRUE return FALSE - - /////BARRICADE TYPES/////// - /obj/structure/barricade/wooden name = "wooden barricade" desc = "This space is blocked off by a wooden barricade." @@ -63,6 +60,13 @@ bar_material = WOOD var/drop_amount = 3 +/obj/structure/barricade/wooden/Initialize(mapload) + . = ..() + + var/static/list/tool_behaviors = list(TOOL_CROWBAR = list(SCREENTIP_CONTEXT_LMB = "Deconstruct")) + AddElement(/datum/element/contextual_screentip_tools, tool_behaviors) + register_context() + /obj/structure/barricade/wooden/attackby(obj/item/I, mob/user) if(istype(I,/obj/item/stack/sheet/mineral/wood)) var/obj/item/stack/sheet/mineral/wood/W = I @@ -71,6 +75,7 @@ return else to_chat(user, span_notice("You start adding [I] to [src]...")) + playsound(src, 'sound/items/hammering_wood.ogg', 50, vary = TRUE) if(do_after(user, 50, target=src)) W.use(5) var/turf/T = get_turf(src) @@ -79,6 +84,15 @@ return return ..() +/obj/structure/barricade/wooden/crowbar_act(mob/living/user, obj/item/tool) + balloon_alert(user, "deconstructing barricade...") + if(!tool.use_tool(src, user, 2 SECONDS, volume=50)) + return + balloon_alert(user, "barricade deconstructed") + tool.play_tool_sound(src) + new /obj/item/stack/sheet/mineral/wood(get_turf(src), drop_amount) + qdel(src) + return TOOL_ACT_TOOLTYPE_SUCCESS /obj/structure/barricade/wooden/crude name = "crude plank barricade" @@ -87,6 +101,7 @@ drop_amount = 1 max_integrity = 50 proj_pass_rate = 65 + layer = SIGN_LAYER /obj/structure/barricade/wooden/crude/snow desc = "This space is blocked off by a crude assortment of planks. It seems to be covered in a layer of snow." diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 94d34c907e3..56fffcc63ed 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -68,6 +68,7 @@ COMSIG_ATOM_MAGICALLY_UNLOCKED = .proc/on_magic_unlock, ) AddElement(/datum/element/connect_loc, loc_connections) + AddElement(/datum/element/can_barricade) /obj/machinery/door/examine(mob/user) . = ..() @@ -87,7 +88,7 @@ if(isaicamera(user) || issilicon(user)) return . - if (isnull(held_item) && Adjacent(user)) + if(isnull(held_item) && Adjacent(user)) context[SCREENTIP_CONTEXT_LMB] = "Open" return CONTEXTUAL_SCREENTIP_SET @@ -274,6 +275,8 @@ return TRUE else if(I.item_flags & NOBLUDGEON || user.combat_mode) return ..() + else if(!user.combat_mode && istype(I, /obj/item/stack/sheet/mineral/wood)) + return ..() // we need this so our can_barricade element can be called using COMSIG_PARENT_ATTACKBY else if(try_to_activate_door(user)) return TRUE return ..() diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index d9000afa596..01de086464e 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -34,19 +34,6 @@ /// If some inconsiderate jerk has had their blood spilled on this window, thus making it cleanable var/bloodied = FALSE -/obj/structure/window/examine(mob/user) - . = ..() - switch(state) - if(WINDOW_SCREWED_TO_FRAME) - . += span_notice("The window is screwed to the frame.") - if(WINDOW_IN_FRAME) - . += span_notice("The window is unscrewed but pried into the frame.") - if(WINDOW_OUT_OF_FRAME) - if (anchored) - . += span_notice("The window is screwed to the floor.") - else - . += span_notice("The window is unscrewed from the floor, and could be deconstructed by wrenching.") - /obj/structure/window/Initialize(mapload, direct) . = ..() if(direct) @@ -61,6 +48,7 @@ if(fulltile) setDir() + AddElement(/datum/element/can_barricade) //windows only block while reinforced and fulltile, so we'll use the proc real_explosion_block = explosion_block @@ -78,6 +66,19 @@ if (flags_1 & ON_BORDER_1) AddElement(/datum/element/connect_loc, loc_connections) +/obj/structure/window/examine(mob/user) + . = ..() + switch(state) + if(WINDOW_SCREWED_TO_FRAME) + . += span_notice("The window is screwed to the frame.") + if(WINDOW_IN_FRAME) + . += span_notice("The window is unscrewed but pried into the frame.") + if(WINDOW_OUT_OF_FRAME) + if (anchored) + . += span_notice("The window is screwed to the floor.") + else + . += span_notice("The window is unscrewed from the floor, and could be deconstructed by wrenching.") + /obj/structure/window/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) switch(the_rcd.mode) if(RCD_DECONSTRUCT) diff --git a/sound/items/hammering_wood.ogg b/sound/items/hammering_wood.ogg new file mode 100644 index 00000000000..37ecf90ec44 Binary files /dev/null and b/sound/items/hammering_wood.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 57ffbcabee3..1936d0d360a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -987,6 +987,7 @@ #include "code\datums\elements\bed_tucking.dm" #include "code\datums\elements\bsa_blocker.dm" #include "code\datums\elements\bump_click.dm" +#include "code\datums\elements\can_barricade.dm" #include "code\datums\elements\chemical_transfer.dm" #include "code\datums\elements\chewable.dm" #include "code\datums\elements\cleaning.dm"