Files
Batrachophreno 8111a8489b Restore many missing inhand sprites for items, add/port others (#21831)
Many, many, many items have inhand sprites in their .dmis but for
whatever reasons do not display them in-game. This PR:

1. Updates many item definitions to point to their already-existing
inhands correctly. This consists largely of held tools, but also gas
tanks and jetpacks mounted in the suit storage slot.

2. Adds a few codersprites made by me for objects with either missing
inhands or poorly matching mishands (IE, the tape recorder, which has a
black case, reused the white inhand sprites of the health analyzer). The
new sprites are modified or recolored variations of other inhand sprites
from our repo, except for circuitboards which are new.
<img width="444" height="400" alt="image"
src="https://github.com/user-attachments/assets/7f107b9a-fe24-4e31-8f16-4d34768ee117"
/>


3. Adds inhand sprites for Inflatables and Inflatable Boxes made by
Tomixcomics.
<img width="424" height="101" alt="image"
src="https://github.com/user-attachments/assets/434107c4-8577-49a2-a58e-d6b014c03933"
/>

4. Ports inhand sprites for the Hydraulic Rescue Tool from tg's Jaws of
Life.
<img width="224" height="94" alt="Screenshot 2026-02-07 172931"
src="https://github.com/user-attachments/assets/070c7956-f6a8-4fb5-870f-10c64afcc8b3"
/>

5. Some additional cleanup while in the area. The 'analyzer' has been
renamed the 'gas analyzer' to be consistent with the other analyzer
objects, standardized icon_state naming conventions where I saw
oddballs, updated code docs to use DMDocs when in the area, etc.

### Asset Licenses
The following assets that **have not** been created by myself are
included in this PR:

| Path | Original Author | License |
| --- | --- | --- |
| icons/obj/item/hydraulic_rescue_tool.dmi | [SomeAngryMiner (bee
station)](https://github.com/BeeStation/BeeStation-Hornet/pull/2487),
[maxymax
(/tg/station)](https://github.com/tgstation/tgstation/pull/58616) |
CC-BY-SA |
| icons/obj/item/inflatables.dmi |
[Tomixcomics](https://github.com/tomixcomics) | CC-BY-SA |
2026-02-17 17:51:22 +00:00

185 lines
5.3 KiB
Plaintext

/obj/item/spy_bug
name = "bug"
desc = "" // Nothing to see here
icon = 'icons/obj/weapons.dmi'
icon_state = "eshield0"
item_state = "nothing"
layer = BELOW_TABLE_LAYER
obj_flags = OBJ_FLAG_CONDUCTABLE
force = 11
w_class = WEIGHT_CLASS_TINY
slot_flags = SLOT_EARS
throwforce = 5.0
throw_range = 15
throw_speed = 3
origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1, TECH_ILLEGAL = 3)
var/obj/item/radio/spy/radio
var/obj/machinery/camera/spy/camera
/obj/item/spy_bug/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
if(distance <= 0)
. += "Needs to be both configured and brought in contact with monitor device to be fully functional."
. += "A pen can be used to label the device on a given network."
/obj/item/spy_bug/feedback_hints(mob/user, distance, is_adjacent)
. += ..()
if(distance <= 0)
. += "It's a tiny camera, microphone, and transmission device in a happy union."
/obj/item/spy_bug/New()
..()
radio = new(src)
camera = new(src)
become_hearing_sensitive(ROUNDSTART_TRAIT)
/obj/item/spy_bug/attack_self(mob/user)
radio.set_broadcasting(!radio.get_broadcasting())
to_chat(user, "\The [src]'s radio is [radio.get_broadcasting() ? "broadcasting" : "not broadcasting"] now. The current frequency is [radio.get_frequency()].")
radio.attack_self(user)
/obj/item/spy_bug/attackby(obj/item/attacking_item, mob/user)
if(!istype(user))
return
if(istype(attacking_item, /obj/item/spy_monitor))
var/obj/item/spy_monitor/SM = attacking_item
SM.pair(src, user)
return TRUE
if(attacking_item.tool_behaviour == TOOL_PEN)
var/n_tag = sanitizeSafe( tgui_input_text(user, "What would you like to label the camera?", "Bug Labelling", default = camera.c_tag, max_length = MAX_NAME_LEN), MAX_NAME_LEN )
if(Adjacent(user) && user.stat == CONSCIOUS && n_tag)
camera.c_tag = n_tag
camera.name = "[camera.initial_name] - [n_tag]"
return TRUE
else
return ..()
/obj/item/spy_bug/hear_talk(mob/M, var/msg, verb, datum/language/speaking)
radio.hear_talk(M, msg, verb, speaking)
/obj/item/spy_monitor
name = "\improper PDA"
desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge."
icon = 'icons/obj/modular_computers/pda.dmi'
icon_state = "pda"
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1, TECH_ILLEGAL = 3)
var/operating = 0
var/obj/item/radio/spy/radio
var/obj/machinery/camera/spy/selected_camera
var/list/obj/machinery/camera/spy/cameras = new()
/obj/item/spy_monitor/feedback_hints(mob/user, distance, is_adjacent)
. += ..()
if(distance <= 1)
. += "The time '12:00' is blinking in the corner of the screen and \the [src] looks very cheaply made."
/obj/item/spy_monitor/New()
radio = new(src)
become_hearing_sensitive(ROUNDSTART_TRAIT)
/obj/item/spy_monitor/attack_self(mob/user)
if(operating)
return
radio.attack_self(user)
view_cameras(user)
/obj/item/spy_monitor/attackby(obj/item/attacking_item, mob/user)
if(!istype(user))
return
if(istype(attacking_item, /obj/item/spy_bug))
pair(attacking_item, user)
return TRUE
else
return ..()
/obj/item/spy_monitor/proc/pair(var/obj/item/spy_bug/SB, var/mob/living/user)
if(SB.camera in cameras)
to_chat(user, SPAN_NOTICE("\The [SB] has been unpaired from \the [src]."))
cameras -= SB.camera
else
to_chat(user, SPAN_NOTICE("\The [SB] has been paired with \the [src]."))
cameras += SB.camera
/obj/item/spy_monitor/proc/view_cameras(mob/user)
if(!can_use_cam(user))
return
selected_camera = cameras[1]
view_camera(user)
operating = TRUE
while(selected_camera && Adjacent(user))
selected_camera = tgui_input_list(user, "Select camera bug to view.", "Spy Monitor", cameras)
selected_camera = null
operating = FALSE
/obj/item/spy_monitor/proc/view_camera(mob/user)
spawn(0)
while(selected_camera && Adjacent(user))
var/turf/T = get_turf(selected_camera)
if(!T || !(T.z in GetConnectedZlevels(user.z)) || !selected_camera.can_use())
user.unset_machine()
user.reset_view(null)
to_chat(user, SPAN_NOTICE("[selected_camera] unavailable."))
sleep(90)
else
user.set_machine(selected_camera)
user.reset_view(selected_camera)
sleep(10)
user.unset_machine()
user.reset_view(null)
/obj/item/spy_monitor/proc/can_use_cam(mob/user)
if(operating)
return
if(!cameras.len)
to_chat(user, SPAN_WARNING("No paired cameras detected!"))
to_chat(user, SPAN_WARNING("Bring a bug in contact with this device to pair the camera."))
return
return 1
/obj/item/spy_monitor/hear_talk(mob/M, var/msg, verb, datum/language/speaking)
return radio.hear_talk(M, msg, speaking)
/obj/machinery/camera/spy
// These cheap toys are accessible from the mercenary camera console as well
network = list(NETWORK_MERCENARY)
active_power_usage = 0
/// Set on Initialize(), simulates initial() but for the name variable so we can restore it when needed
var/initial_name
/obj/machinery/camera/spy/Initialize()
. = ..()
name = "DV-136ZB #[rand(1000,9999)]"
initial_name = name
c_tag = name
/obj/machinery/camera/spy/check_eye(var/mob/user as mob)
return FALSE
/obj/item/radio/spy
canhear_range = 7
name = "spy device"
icon_state = "syn_cypherkey"
/obj/item/radio/spy/Initialize()
. = ..()
set_broadcasting(FALSE)
set_listening(FALSE)
set_frequency(1473)