diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index 3b31e34b2f4..87b9094b47e 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -158,6 +158,8 @@
// /obj signals
#define COMSIG_OBJ_DECONSTRUCT "obj_deconstruct" //from base of obj/deconstruct(): (disassembled)
#define COMSIG_OBJ_SETANCHORED "obj_setanchored" //called in /obj/structure/setAnchored(): (value)
+#define COMSIG_OBJ_UPDATE_ICON "obj_update_icon" //called in /obj/update_icon()
+
// /obj/item signals
#define COMSIG_ITEM_ATTACK "item_attack" //from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
diff --git a/code/datums/action.dm b/code/datums/action.dm
index a9c895f3482..dcdc4d1a9ba 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -313,6 +313,9 @@
/datum/action/item_action/toggle_helmet
name = "Toggle Helmet"
+/datum/action/item_action/remove_tape
+ name = "Remove Duct Tape"
+
/datum/action/item_action/toggle_jetpack
name = "Toggle Jetpack"
diff --git a/code/datums/components/ducttape.dm b/code/datums/components/ducttape.dm
new file mode 100644
index 00000000000..c69e90efaf7
--- /dev/null
+++ b/code/datums/components/ducttape.dm
@@ -0,0 +1,55 @@
+/datum/component/ducttape
+ var/x_offset = 0
+ var/y_offset = 0
+ var/icon/tape_overlay = null
+
+/datum/component/ducttape/Initialize(obj/item/I, mob/user, x, y)
+ if(!istype(I)) //Something went wrong
+ return
+ x_offset = x
+ y_offset = y
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/add_tape_text)
+ RegisterSignal(parent, COMSIG_OBJ_UPDATE_ICON, .proc/add_tape_overlay)
+ RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, .proc/afterattack)
+ I.update_icon() //Do this first so the action button preoperly shows the icon
+ var/datum/action/item_action/remove_tape/RT = new(I)
+ if(I.loc == user)
+ RT.Grant(user)
+
+/datum/component/proc/add_tape_text(datum/source, mob/user)
+ to_chat(user, "There's some sticky tape attached to [source].")
+
+/datum/component/ducttape/proc/add_tape_overlay(obj/item/O)
+ tape_overlay = new('icons/obj/bureaucracy.dmi', "tape")
+ tape_overlay.Shift(EAST, x_offset - 2)
+ tape_overlay.Shift(NORTH, y_offset - 2)
+ O.overlays += tape_overlay
+
+/datum/component/ducttape/proc/remove_tape(obj/item/I, mob/user)
+ to_chat(user, "You tear the tape off [I]!")
+ playsound(I, 'sound/items/poster_ripped.ogg', 50, 1)
+ new /obj/item/trash/tapetrash(user.loc)
+ I.update_icon()
+ I.anchored = initial(I.anchored)
+ for(var/datum/action/item_action/remove_tape/RT in I.actions)
+ RT.Remove(user)
+ RT.Destroy()
+ I.overlays.Cut(tape_overlay)
+ user.transfer_fingerprints_to(I)
+ Destroy()
+
+/datum/component/ducttape/proc/afterattack(datum/source, atom/target, mob/user, proximity, params)
+ if(!proximity)
+ return
+ if(!isturf(target))
+ return
+ var/list/clickparams = params2list(params)
+ var/x_offset = text2num(clickparams["icon-x"]) - 16
+ var/y_offset = text2num(clickparams["icon-y"]) - 16
+ var/turf/T = target
+ var/obj/item/I = source
+ to_chat(user, "You stick [I] to [T].")
+ user.unEquip(I)
+ I.forceMove(T)
+ I.pixel_x = x_offset
+ I.pixel_y = y_offset
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index f8798d77c5d..40b3ff692be 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -206,6 +206,9 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
msg += "*--------*"
to_chat(user, msg)
+/obj/item/afterattack(atom/target, mob/user, proximity, params)
+ SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK, target, user, proximity, params)
+ ..()
/obj/item/attack_hand(mob/user as mob, pickupfireoverride = FALSE)
if(!user) return 0
@@ -415,6 +418,12 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
//The default action is attack_self().
//Checks before we get to here are: mob is alive, mob is not restrained, paralyzed, asleep, resting, laying, item is on the mob.
/obj/item/proc/ui_action_click(mob/user, actiontype)
+ if(actiontype == /datum/action/item_action/remove_tape)
+ GET_COMPONENT(DT, /datum/component/ducttape)
+ if(!DT)
+ return
+ DT.remove_tape(src, user)
+ return
attack_self(user)
/obj/item/proc/IsReflect(var/def_zone) //This proc determines if and at what% an object will reflect energy projectiles if it's in l_hand,r_hand or wear_suit
diff --git a/code/game/objects/items/weapons/tape.dm b/code/game/objects/items/weapons/tape.dm
index b8437f3b7ed..a19b2cecd22 100644
--- a/code/game/objects/items/weapons/tape.dm
+++ b/code/game/objects/items/weapons/tape.dm
@@ -13,7 +13,9 @@
update_icon()
-/obj/item/stack/tape_roll/attack(mob/living/carbon/human/M as mob, mob/living/user as mob)
+/obj/item/stack/tape_roll/attack(mob/living/carbon/human/M, mob/living/user)
+ if(!istype(M)) //What good is a duct tape mask if you are unable to speak?
+ return
if(M.wear_mask)
to_chat(user, "Remove [M.p_their()] mask first!")
else if(amount < 2)
@@ -40,25 +42,6 @@
user.unEquip(src, 1)
qdel(src)
-
-
-/* -- Disabled for now until it has a use --
-/obj/item/stack/tape_roll/attack_self(mob/user as mob)
- to_chat(user, "You remove a length of tape from [src].")
-
- var/obj/item/ducttape/tape = new()
- user.put_in_hands(tape)
-*/
-
-/obj/item/stack/tape_roll/proc/stick(var/obj/item/W, mob/user)
- if(!istype(W, /obj/item/paper))
- return
-
- user.unEquip(W)
- var/obj/item/ducttape/tape = new(get_turf(src))
- tape.attach(W)
- user.put_in_hands(tape)
-
/obj/item/stack/tape_roll/update_icon()
var/amount = get_amount()
if((amount <= 2) && (amount > 0))
@@ -72,72 +55,20 @@
else
icon_state = "taperoll-4"
-/obj/item/ducttape
- name = "tape"
- desc = "A piece of sticky tape."
- icon = 'icons/obj/bureaucracy.dmi'
- icon_state = "tape"
- w_class = WEIGHT_CLASS_TINY
- layer = 4
- anchored = 1 //it's sticky, no you cant move it
-
- var/obj/item/stuck = null
-
-/obj/item/ducttape/New()
+/obj/item/stack/tape_roll/afterattack(obj/item/I, mob/user, proximity, params)
..()
- flags |= NOBLUDGEON
-
-/obj/item/ducttape/examine(mob/user)
- return stuck.examine(user)
-
-/obj/item/ducttape/proc/attach(var/obj/item/W)
- stuck = W
- W.forceMove(src)
- icon_state = W.icon_state + "_taped"
- name = W.name + " (taped)"
- overlays = W.overlays
-
-/obj/item/ducttape/attack_self(mob/user)
- if(!stuck)
+ if(!proximity || !istype(I))
return
-
- to_chat(user, "You remove \the [initial(name)] from [stuck].")
-
- user.unEquip(src)
- stuck.forceMove(get_turf(src))
- user.put_in_hands(stuck)
- stuck = null
- overlays = null
- qdel(src)
-
-/obj/item/ducttape/afterattack(var/A, mob/user, flag, params)
- if(!in_range(user, A) || istype(A, /obj/machinery/door) || !stuck)
+ var/list/clickparams = params2list(params)
+ var/x_offset = text2num(clickparams["icon-x"])
+ var/y_offset = text2num(clickparams["icon-y"])
+ if(I.GetComponent(/datum/component/ducttape))
+ to_chat(user, "[I] already has some tape attached!")
return
-
- var/turf/target_turf = get_turf(A)
- var/turf/source_turf = get_turf(user)
-
- var/dir_offset = 0
- if(target_turf != source_turf)
- dir_offset = get_dir(source_turf, target_turf)
- if(!(dir_offset in cardinal))
- to_chat(user, "You cannot reach that from here.")// can only place stuck papers in cardinal directions, to
- return // reduce papers around corners issue.
-
- user.unEquip(src)
- forceMove(source_turf)
-
- if(params)
- var/list/mouse_control = params2list(params)
- if(mouse_control["icon-x"])
- pixel_x = text2num(mouse_control["icon-x"]) - 16
- if(dir_offset & EAST)
- pixel_x += 32
- else if(dir_offset & WEST)
- pixel_x -= 32
- if(mouse_control["icon-y"])
- pixel_y = text2num(mouse_control["icon-y"]) - 16
- if(dir_offset & NORTH)
- pixel_y += 32
- else if(dir_offset & SOUTH)
- pixel_y -= 32
+ if(use(1))
+ to_chat(user, "You apply some tape to [I].")
+ I.AddComponent(/datum/component/ducttape, I, user, x_offset, y_offset)
+ I.anchored = TRUE
+ user.transfer_fingerprints_to(src)
+ else
+ to_chat(user, "You don't have enough tape to do that!")
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index cc2fa8d1d69..c8791a7b269 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -146,7 +146,7 @@
return
/obj/proc/update_icon()
- return
+ SEND_SIGNAL(src, COMSIG_OBJ_UPDATE_ICON)
/mob/proc/unset_machine()
if(machine)
diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm
index 177379deb78..dc0b818fe92 100644
--- a/code/modules/paperwork/clipboard.dm
+++ b/code/modules/paperwork/clipboard.dm
@@ -83,7 +83,7 @@ obj/item/clipboard/proc/penPlacement(mob/user, obj/item/pen/P, placing)
if(containedpen)
overlays += "clipboard_pen"
overlays += "clipboard_over"
- return
+ ..()
/obj/item/clipboard/attackby(obj/item/W, mob/user)
if(isPaperwork(W)) //If it's a photo, paper bundle, or piece of paper, place it on the clipboard.
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 40cc2bcc534..aa639e78f3f 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -53,6 +53,7 @@
updateinfolinks()
/obj/item/paper/update_icon()
+ ..()
if(icon_state == "paper_talisman")
return
if(info)
@@ -303,12 +304,6 @@
if(user.mind && (user.mind.assigned_role == "Clown"))
clown = 1
- if(istype(P, /obj/item/stack/tape_roll))
- var/obj/item/stack/tape_roll/tape = P
- tape.stick(src, user)
- tape.use(1)
- return
-
if(istype(P, /obj/item/paper) || istype(P, /obj/item/photo))
if(istype(P, /obj/item/paper/carbon))
var/obj/item/paper/carbon/C = P
diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm
index 900d3d4bdb8..a2cae0d32bb 100644
--- a/code/modules/paperwork/paper_bundle.dm
+++ b/code/modules/paperwork/paper_bundle.dm
@@ -217,6 +217,7 @@
/obj/item/paper_bundle/update_icon()
+ ..()
if(contents.len)
var/obj/item/paper/P = src[1]
icon_state = P.icon_state
diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi
index 5829e3bb7f5..529417a2b6c 100644
Binary files a/icons/obj/bureaucracy.dmi and b/icons/obj/bureaucracy.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 69340ade5c7..9c37a7804cf 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -260,6 +260,7 @@
#include "code\datums\cache\crew.dm"
#include "code\datums\cache\powermonitor.dm"
#include "code\datums\components\_component.dm"
+#include "code\datums\components\ducttape.dm"
#include "code\datums\components\material_container.dm"
#include "code\datums\components\squeak.dm"
#include "code\datums\diseases\_disease.dm"