diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 3667dca5804..f8193e8d4c1 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -22,6 +22,9 @@ if(S.prevents_buckled_mobs_attacking()) return + if(SEND_SIGNAL(A, COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY, src) & COMPONENT_CANCEL_ATTACK_CHAIN) + return + A.attack_hand(src) /atom/proc/attack_hand(mob/user as mob) diff --git a/code/datums/components/sticky.dm b/code/datums/components/sticky.dm new file mode 100644 index 00000000000..dcb05ab2a22 --- /dev/null +++ b/code/datums/components/sticky.dm @@ -0,0 +1,118 @@ +// kinda like duct tape but not shit (just kidding, its shit but in a different way) +/datum/component/sticky + /// The atom we are stickied to + var/atom/attached_to + /// Our priority overlay put on top of attached_to + var/icon/overlay + /// Do we drop on attached_to's destroy? If not, we qdel + var/drop_on_attached_destroy = FALSE + +/datum/component/sticky/Initialize(_drop_on_attached_destroy = FALSE) + if(!isitem(parent)) + stack_trace("/datum/component/sticky's parent is not an item, its [parent.type]") + return COMPONENT_INCOMPATIBLE + + drop_on_attached_destroy = _drop_on_attached_destroy + RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(stick_to_it)) + +/datum/component/sticky/proc/stick_to_it(obj/item/I, atom/target, mob/user, params) + SIGNAL_HANDLER + if(!in_range(I, target)) + return + if(isstorage(target)) + var/obj/item/storage/S = target + if(S.can_be_inserted(parent)) + return + if(target.GetComponent(/datum/component/sticky)) + return + if(!user.canUnEquip(I)) + return + + INVOKE_ASYNC(user, TYPE_PROC_REF(/mob, unEquip), I) + + var/list/click_params = params2list(params) + //Center the icon where the user clicked. + if(!click_params || !click_params["icon-x"] || !click_params["icon-y"]) + return + + attached_to = target + move_to_the_thing(parent) + if(user) + to_chat(user, "You attach [parent] to [attached_to].") + + overlay = icon(I.icon, I.icon_state) + //Clamp it so that the icon never moves more than 16 pixels in either direction + overlay.Shift(EAST, clamp(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)) + overlay.Shift(NORTH, clamp(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)) + + attached_to.add_overlay(overlay, priority = TRUE) + I.invisibility = INVISIBILITY_ABSTRACT + + RegisterSignal(attached_to, COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY, PROC_REF(pick_up)) + RegisterSignal(attached_to, COMSIG_PARENT_EXAMINE, PROC_REF(add_sticky_text)) + RegisterSignal(attached_to, COMSIG_PARENT_QDELETING, PROC_REF(on_attached_destroy)) + if(ismovable(attached_to)) + RegisterSignal(attached_to, COMSIG_MOVABLE_MOVED, PROC_REF(on_move)) + START_PROCESSING(SSobj, src) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/datum/component/sticky/proc/pick_up(atom/A, mob/living/carbon/human/user) + SIGNAL_HANDLER + if(!attached_to) + return + if(user.a_intent != INTENT_GRAB) + return + if(user.get_active_hand()) + return + attached_to.cut_overlay(overlay, priority = TRUE) + + var/obj/item/I = parent + I.pixel_x = initial(I.pixel_x) + I.pixel_y = initial(I.pixel_y) + move_to_the_thing(parent) + INVOKE_ASYNC(user, TYPE_PROC_REF(/mob, put_in_hands), I) + if(user) + to_chat(user, "You take [parent] off of [attached_to].") + + + I.invisibility = initial(I.invisibility) + UnregisterSignal(attached_to, list(COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY, COMSIG_PARENT_EXAMINE)) + STOP_PROCESSING(SSobj, src) + attached_to = null + return COMPONENT_CANCEL_ATTACK_CHAIN + +/datum/component/sticky/proc/add_sticky_text(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + if(!in_range(user, attached_to)) + return + examine_list += "There is [parent] attached to [source], grab [attached_to.p_them()] to remove it." + +/datum/component/sticky/proc/on_move(datum/source, oldloc, move_dir) + SIGNAL_HANDLER + if(!attached_to) + stack_trace("/datum/component/sticky was called on_move, but without an attached atom") + return + move_to_the_thing(parent) + +/datum/component/sticky/process() // because sometimes the item can move inside something, like a crate + if(!attached_to) + return PROCESS_KILL + move_to_the_thing(parent) + +/datum/component/sticky/proc/on_attached_destroy(datum/source) + SIGNAL_HANDLER + if(!drop_on_attached_destroy) + qdel(parent) + return + + var/turf/T = get_turf(source) + if(!T) + T = get_turf(parent) + move_to_the_thing(parent, T) + +/datum/component/sticky/proc/move_to_the_thing(obj/item/I, turf/target) + if(!istype(I)) + return // only items should be able to have the sticky component + if(!target) + target = get_turf(attached_to) + INVOKE_ASYNC(I, TYPE_PROC_REF(/atom/movable, forceMove), target) diff --git a/code/datums/uplink_items/uplink_general.dm b/code/datums/uplink_items/uplink_general.dm index b1dd0135e29..625531234a7 100644 --- a/code/datums/uplink_items/uplink_general.dm +++ b/code/datums/uplink_items/uplink_general.dm @@ -464,9 +464,9 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/stealthy_tools/camera_bug name = "Camera Bug" - desc = "Enables you to view all cameras on the network to track a target." + desc = "Enables you to view all cameras on the network to track a target. Also has 5 sticky hidden cameras, allowing you remote view of any object you can stick a camera on." reference = "CB" - item = /obj/item/camera_bug + item = /obj/item/storage/box/syndie_kit/camera_bug cost = 1 surplus = 90 diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 7fffc5358c5..141144dc750 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -406,6 +406,7 @@ return TRUE /obj/machinery/camera/portable //Cameras which are placed inside of things, such as helmets. + start_active = TRUE // theres no real way to reactivate these, so never break them when they init var/turf/prev_turf /obj/machinery/camera/portable/Initialize(mapload) diff --git a/code/game/objects/items/devices/camera_bug.dm b/code/game/objects/items/devices/camera_bug.dm index 88bfa0ed9bf..389e3da2694 100644 --- a/code/game/objects/items/devices/camera_bug.dm +++ b/code/game/objects/items/devices/camera_bug.dm @@ -3,14 +3,15 @@ name = "camera bug" desc = "For illicit snooping through the camera network." icon = 'icons/obj/device.dmi' - icon_state = "camera_bug" - w_class = WEIGHT_CLASS_TINY - item_state = "camera_bug" + icon_state = "camera_bug" + w_class = WEIGHT_CLASS_TINY + item_state = "camera_bug" throw_speed = 4 throw_range = 20 origin_tech = "syndicate=1;engineering=3" /// Integrated camera console to serve UI data var/obj/machinery/computer/security/camera_bug/integrated_console + var/connections = 0 /obj/machinery/computer/security/camera_bug name = "invasive camera utility" @@ -22,7 +23,7 @@ . = ..() integrated_console = new(src) integrated_console.parent = src - integrated_console.network = list("SS13") + integrated_console.network = list("SS13", "camera_bug[UID()]") /obj/item/camera_bug/Destroy() QDEL_NULL(integrated_console) @@ -43,3 +44,56 @@ . = ..() integrated_console.network = list("ERT") +/obj/item/wall_bug + name = "\improper small camera" + desc = "A camera with a sticky backside." + icon = 'icons/obj/device.dmi' + icon_state = "wall_bug" + w_class = WEIGHT_CLASS_TINY + var/obj/machinery/camera/portable/camera + var/index = "REPORT THIS TO CODERS" + +/obj/item/wall_bug/Initialize(mapload, obj/item/camera_bug/the_bug) + . = ..() + link_to_camera(the_bug) + AddComponent(/datum/component/sticky) + +/obj/item/wall_bug/Destroy() + QDEL_NULL(camera) + . = ..() + +/obj/item/wall_bug/examine(mob/user) + . = ..() + if(in_range(user, src)) + . += "It has a small label on it reading \"[index]\"." + +/obj/item/wall_bug/proc/link_to_camera(obj/item/camera_bug/camera_bug) + if(!istype(camera_bug)) + return + if(camera) // we can't link twice + return + camera_bug.connections++ + index = camera_bug.connections + + camera = new /obj/machinery/camera/portable(src) + camera.network = list("camera_bug[camera_bug.UID()]") + camera.c_tag = "Hidden Camera [index]" + +/obj/item/paper/camera_bug + name = "Camera Bug Guide" + icon_state = "paper" + info = {"Instructions on your new invasive camera utility
+
+ This camera bug can access all default cameras on the station, along with the hidden cameras provided in this kit.
+
+ The cameras in this kit have a sticky backside, allowing you to attach them to literally anything, even people.
+
+ You may remove the cameras from said objects by grabbing them with an empty hand.
+
+ You can view these hidden cameras by looking up "Hidden Camera" on your camera bug.
+
+ Only the camera bug provided in this kit can see these hidden cameras.
+
+ Other Camera bugs cannot see your hidden cameras.
+
+ There is no other way to get these hidden cameras, so make sure to not lose them!
"} diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm index 59ae3a2fa75..9af05a5019e 100644 --- a/code/game/objects/items/weapons/dice.dm +++ b/code/game/objects/items/weapons/dice.dm @@ -252,7 +252,7 @@ /obj/item/storage/toolbox/syndicate, /obj/item/storage/backpack/clown/syndie, /obj/item/storage/backpack/satchel_flat, - /obj/item/camera_bug, + /obj/item/storage/box/syndie_kit/camera_bug, /obj/item/storage/belt/military/traitor, /obj/item/clothing/glasses/chameleon/thermal, /obj/item/borg/upgrade/modkit/indoors, diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm index af25037ff74..00d249bfd12 100644 --- a/code/game/objects/items/weapons/storage/uplink_kits.dm +++ b/code/game/objects/items/weapons/storage/uplink_kits.dm @@ -374,3 +374,12 @@ To apply, hold the injector a short distance away from the outer thigh before ap new /obj/item/gun/projectile/automatic/pistol(src) new /obj/item/ammo_box/magazine/m10mm(src) new /obj/item/ammo_box/magazine/m10mm(src) + +/obj/item/storage/box/syndie_kit/camera_bug + name = "\improper Camera Bug kit" + +/obj/item/storage/box/syndie_kit/camera_bug/populate_contents() + var/camera = new /obj/item/camera_bug(src) + new /obj/item/paper/camera_bug(src) + for(var/i in 1 to 5) + new /obj/item/wall_bug(src, camera) diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 212df4631b6..abf40126598 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/paradise.dme b/paradise.dme index 1af32ce2f5c..5d4bcf5629d 100644 --- a/paradise.dme +++ b/paradise.dme @@ -379,6 +379,7 @@ #include "code\datums\components\spooky.dm" #include "code\datums\components\squeak.dm" #include "code\datums\components\squish.dm" +#include "code\datums\components\sticky.dm" #include "code\datums\components\surgery_initiator.dm" #include "code\datums\components\swarming.dm" #include "code\datums\discord\discord_manager.dm"