mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-16 01:19:13 +01:00
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 |
331 lines
11 KiB
Plaintext
331 lines
11 KiB
Plaintext
/* Teleportation devices.
|
|
* Contains:
|
|
* * Locator
|
|
* * Hand-tele
|
|
* * Closet Teleporter
|
|
* * Inhibitor handling proc for above
|
|
*/
|
|
|
|
/*
|
|
* Special inhibitor handling. Different from the one used by teleport datums.
|
|
*/
|
|
/proc/check_inhibitors(var/turf/T)
|
|
for(var/found_inhibitor in GLOB.bluespace_inhibitors)
|
|
var/obj/machinery/anti_bluespace/AB = found_inhibitor
|
|
if(T.z != AB.z || get_dist(T, AB) > 8 || (AB.stat & (NOPOWER | BROKEN)))
|
|
continue
|
|
else
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/*
|
|
* Locator
|
|
*/
|
|
|
|
|
|
/obj/item/locator
|
|
name = "locator"
|
|
desc = "A device that can be used to track those with locator implants."
|
|
icon = 'icons/obj/item/pinpointer.dmi'
|
|
icon_state = "pinoff"
|
|
var/temp = null
|
|
var/frequency = 1451
|
|
var/broadcasting = null
|
|
var/listening = TRUE
|
|
obj_flags = OBJ_FLAG_CONDUCTABLE
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
item_state = "electronic"
|
|
throw_speed = 4
|
|
throw_range = 20
|
|
origin_tech = list(TECH_MAGNET = 1)
|
|
matter = list(DEFAULT_WALL_MATERIAL = 400)
|
|
|
|
/obj/item/locator/attack_self(mob/user as mob)
|
|
user.set_machine(src)
|
|
var/dat
|
|
if (src.temp)
|
|
dat = "[src.temp]<BR><BR><A href='byond://?src=[REF(src)];temp=1'>Clear</A>"
|
|
else
|
|
dat = {"
|
|
<B>Persistent Signal Locator</B><HR>
|
|
Frequency:
|
|
<A href='byond://?src=[REF(src)];freq=-10'>-</A>
|
|
<A href='byond://?src=[REF(src)];freq=-2'>-</A> [format_frequency(src.frequency)]
|
|
<A href='byond://?src=[REF(src)];freq=2'>+</A>
|
|
<A href='byond://?src=[REF(src)];freq=10'>+</A><BR>
|
|
|
|
<A href='byond://?src=[REF(src)];refresh=1'>Refresh</A>"}
|
|
user << browse(HTML_SKELETON(dat), "window=radio")
|
|
onclose(user, "radio")
|
|
return
|
|
|
|
/obj/item/locator/Topic(href, href_list)
|
|
..()
|
|
if (usr.stat || usr.restrained())
|
|
return
|
|
var/turf/current_location = get_turf(usr)//What turf is the user on?
|
|
if(!current_location||current_location.z==1)//If turf was not found or they're on z level 1.
|
|
to_chat(usr, "The [src] is malfunctioning.")
|
|
return
|
|
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))))
|
|
usr.set_machine(src)
|
|
if (href_list["refresh"])
|
|
src.temp = "<B>Persistent Signal Locator</B><HR>"
|
|
var/turf/sr = get_turf(src)
|
|
|
|
if (sr)
|
|
src.temp += "<B>Located Beacons:</B><BR>"
|
|
|
|
for(var/obj/item/radio/beacon/W in GLOB.teleportbeacons)
|
|
if (W.get_frequency() == src.frequency)
|
|
var/turf/tr = get_turf(W)
|
|
if (tr.z == sr.z && tr)
|
|
var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
|
|
if (direct < 5)
|
|
direct = "very strong"
|
|
else
|
|
if (direct < 10)
|
|
direct = "strong"
|
|
else
|
|
if (direct < 20)
|
|
direct = "weak"
|
|
else
|
|
direct = "very weak"
|
|
src.temp += "[W.code]-[dir2text(get_dir(sr, tr))]-[direct]<BR>"
|
|
|
|
src.temp += "<B>Extraneous Signals:</B><BR>"
|
|
for (var/obj/item/implant/tracking/W in GLOB.implants)
|
|
if (!W.implanted || !(istype(W.loc,/obj/item/organ/external) || ismob(W.loc)))
|
|
continue
|
|
else
|
|
var/mob/M = W.loc
|
|
if (M.stat == DEAD)
|
|
if (M.timeofdeath + W.lifespan_postmortem < world.time)
|
|
continue
|
|
|
|
var/turf/tr = get_turf(W)
|
|
if (tr.z == sr.z && tr)
|
|
var/direct = max(abs(tr.x - sr.x), abs(tr.y - sr.y))
|
|
if (direct < 20)
|
|
if (direct < 5)
|
|
direct = "very strong"
|
|
else
|
|
if (direct < 10)
|
|
direct = "strong"
|
|
else
|
|
direct = "weak"
|
|
src.temp += "[W.id]-[dir2text(get_dir(sr, tr))]-[direct]<BR>"
|
|
|
|
src.temp += "<B>You are at \[[sr.x],[sr.y],[sr.z]\]</B> in orbital coordinates.<BR><BR><A href='byond://?src=[REF(src)];refresh=1'>Refresh</A><BR>"
|
|
else
|
|
src.temp += "<B><span class='warning'>Processing Error:</span></B> Unable to locate orbital position.<BR>"
|
|
else
|
|
if (href_list["freq"])
|
|
src.frequency += text2num(href_list["freq"])
|
|
src.frequency = sanitize_frequency(src.frequency)
|
|
else
|
|
if (href_list["temp"])
|
|
src.temp = null
|
|
if (istype(src.loc, /mob))
|
|
attack_self(src.loc)
|
|
else
|
|
for(var/mob/M in viewers(1, src))
|
|
if (M.client)
|
|
src.attack_self(M)
|
|
return
|
|
|
|
|
|
/*
|
|
* Hand-tele
|
|
*/
|
|
/obj/item/hand_tele
|
|
name = "hand tele"
|
|
desc = "A hand-held bluespace teleporter that can rip open portals to a random nearby location, or lock onto a teleporter with a selected teleportation beacon."
|
|
icon = 'icons/obj/item/hand_tele.dmi'
|
|
icon_state = "hand_tele"
|
|
item_state = "electronic"
|
|
throwforce = 5
|
|
item_flags = ITEM_FLAG_HELD_MAP_TEXT
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
throw_speed = 3
|
|
throw_range = 5
|
|
origin_tech = list(TECH_MAGNET = 1, TECH_BLUESPACE = 3)
|
|
matter = list(DEFAULT_WALL_MATERIAL = 10000)
|
|
|
|
var/obj/machinery/teleport/pad/linked_pad
|
|
var/list/active_teleporters
|
|
|
|
var/max_portals = 2
|
|
|
|
/obj/item/hand_tele/mechanics_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
. += "Ctrl-click to choose which teleportation pad to link to."
|
|
. += "Use in-hand or alt-click to deploy a portal. "
|
|
. += "When not linked to a pad, or the pad isn't pointing at a beacon, it will choose a completely random teleportation destination."
|
|
|
|
/obj/item/hand_tele/feedback_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
if(linked_pad)
|
|
var/area/A = get_area(linked_pad)
|
|
var/display_name = get_area_display_name(A)
|
|
. += SPAN_NOTICE("\The [src] is linked to a teleportation pad in [display_name]")
|
|
else
|
|
. += SPAN_WARNING("\The [src] isn't linked to any teleportation pads!")
|
|
|
|
/obj/item/hand_tele/set_initial_maptext()
|
|
held_maptext = SMALL_FONTS(7, "Ready")
|
|
|
|
/obj/item/hand_tele/attack_self(mob/user)
|
|
var/turf/current_location = get_turf(user)//What turf is the user on?
|
|
if(!current_location || isAdminLevel(current_location.z))
|
|
to_chat(user, SPAN_WARNING("\The [src] can't get a bearing on anything right now."))
|
|
return
|
|
|
|
//Cannot make one if too close to an inhibitor
|
|
if(!check_inhibitors(current_location))
|
|
to_chat(user, SPAN_DANGER("\The [src] can't seem to find a lock. Something in the area must be preventing the portal from opening..."))
|
|
return
|
|
|
|
if(LAZYLEN(active_teleporters) >= max_portals)
|
|
user.show_message(SPAN_WARNING("\The [src] is recharging!"))
|
|
return
|
|
|
|
var/turf/teleport_turf
|
|
if(linked_pad)
|
|
if(linked_pad.stat & (NOPOWER|BROKEN))
|
|
to_chat(user, SPAN_WARNING("The pad \the [src] is connected doesn't seem to be responding!"))
|
|
return
|
|
if(!AreConnectedZLevels(current_location.z, linked_pad.z))
|
|
to_chat(user, SPAN_WARNING("The pad \the [src] is connected to isn't close enough to lock onto now!"))
|
|
return
|
|
if(linked_pad.locked_obj)
|
|
teleport_turf = get_turf(linked_pad.locked_obj.resolve())
|
|
else
|
|
var/list/potential_turfs = list()
|
|
for(var/turf/T in orange(10))
|
|
if(T.x > world.maxx-8 || T.x < 8)
|
|
continue //putting them at the edge is dumb
|
|
if(T.y > world.maxy-8 || T.y < 8)
|
|
continue
|
|
if(T.density || turf_contains_dense_objects(T))
|
|
continue
|
|
if(!check_inhibitors(T))
|
|
continue
|
|
potential_turfs += T
|
|
teleport_turf = pick(potential_turfs)
|
|
|
|
if(!teleport_turf)
|
|
to_chat(user, SPAN_WARNING("\The [src] was unable to get a lock onto anything!"))
|
|
return
|
|
if(isAdminLevel(teleport_turf.z))
|
|
to_chat(user, SPAN_WARNING("The signal to the beacon seems to be scrambled!"))
|
|
return
|
|
|
|
var/obj/effect/portal/P = new /obj/effect/portal(get_turf(src), teleport_turf, src)
|
|
LAZYADD(active_teleporters, P)
|
|
if(LAZYLEN(active_teleporters) >= max_portals)
|
|
check_maptext(SMALL_FONTS(6, "Charge"))
|
|
add_fingerprint(user)
|
|
|
|
/obj/item/hand_tele/AltClick(mob/user)
|
|
if(user == loc)
|
|
attack_self(user)
|
|
return
|
|
return ..()
|
|
|
|
/obj/item/hand_tele/CtrlClick(mob/user)
|
|
if(user == loc)
|
|
var/turf/current_location = get_turf(src)
|
|
var/list/teleport_options = list()
|
|
for(var/obj/machinery/teleport/pad/P in SSmachinery.machinery)
|
|
if(AreConnectedZLevels(current_location.z, P.z))
|
|
var/area/A = get_area(P)
|
|
var/display_name = get_area_display_name(A)
|
|
if(P.engaged)
|
|
teleport_options["[display_name] (Active)"] = P
|
|
else
|
|
teleport_options["[display_name] (Inactive)"] = P
|
|
teleport_options["None (Dangerous)"] = null
|
|
var/teleport_choice = tgui_input_list(user, "Please select a teleporter to lock in on.", "Hand Teleporter", teleport_options)
|
|
if(!teleport_choice)
|
|
return
|
|
var/old_pad = linked_pad
|
|
linked_pad = teleport_options[teleport_choice]
|
|
if(linked_pad)
|
|
RegisterSignal(linked_pad, COMSIG_QDELETING, PROC_REF(pad_destroyed))
|
|
if(old_pad && linked_pad != old_pad)
|
|
UnregisterSignal(old_pad, COMSIG_QDELETING)
|
|
return
|
|
return ..()
|
|
|
|
/obj/item/hand_tele/proc/pad_destroyed()
|
|
linked_pad = null
|
|
audible_message("\The [src] beeps, \"Connected pad destroyed, resetting to no-pad.\"", null, 3)
|
|
|
|
/obj/item/hand_tele/proc/remove_portal(var/obj/effect/portal/P)
|
|
LAZYREMOVE(active_teleporters, P)
|
|
if(LAZYLEN(active_teleporters) < max_portals)
|
|
check_maptext(SMALL_FONTS(7, "Ready"))
|
|
icon_state = "hand_tele"
|
|
else
|
|
icon_state = "hand_tele_recharging"
|
|
|
|
/obj/item/closet_teleporter
|
|
name = "closet teleporter"
|
|
desc = "A device that allows a user to connect two closets into a bluespace network."
|
|
icon = 'icons/obj/modular_computers/modular_components.dmi'
|
|
icon_state = "cpu_normal_photonic"
|
|
obj_flags = OBJ_FLAG_CONDUCTABLE
|
|
w_class = WEIGHT_CLASS_SMALL
|
|
origin_tech = list(TECH_MAGNET = 2, TECH_BLUESPACE = 3)
|
|
matter = list(DEFAULT_WALL_MATERIAL = 400)
|
|
var/obj/structure/closet/attached_closet
|
|
var/obj/item/closet_teleporter/linked_teleporter
|
|
var/last_use = 0
|
|
|
|
/obj/item/closet_teleporter/antagonist_hints(mob/user, distance, is_adjacent)
|
|
. += ..()
|
|
. += "Left-click a closet with this to install."
|
|
. += "Once two closets have been 'upgraded', step into one closet and close the door to teleport to the linked closet."
|
|
. += "It has a one minute cooldown after a batch teleport."
|
|
|
|
/obj/item/closet_teleporter/proc/do_teleport(var/mob/user)
|
|
if(!attached_closet)
|
|
to_chat(user, SPAN_WARNING("\The [src] doesn't have an attached closet!"))
|
|
return FALSE
|
|
if(!linked_teleporter)
|
|
to_chat(user, SPAN_WARNING("\The [src] doesn't have a linked teleporter!"))
|
|
return FALSE
|
|
if(!linked_teleporter.attached_closet)
|
|
to_chat(user, SPAN_WARNING("The linked teleporter doesn't have an attached closet!"))
|
|
return FALSE
|
|
if(last_use + 600 > world.time)
|
|
return FALSE
|
|
if(!check_inhibitors(get_turf(attached_closet)) || !check_inhibitors(get_turf(linked_teleporter.attached_closet)))
|
|
to_chat(user, SPAN_WARNING("Something near you or your destination is destabilizing the bluespace network between the closets. \The [src] can't get a clear link to the other side!"))
|
|
return FALSE
|
|
|
|
var/obj/structure/closet/target_closet = linked_teleporter.attached_closet
|
|
user.forceMove(target_closet.opened ? get_turf(target_closet) : target_closet)
|
|
if(target_closet.opened)
|
|
if(user.client)
|
|
user.client.eye = user.client.mob
|
|
user.client.perspective = MOB_PERSPECTIVE
|
|
user.visible_message(SPAN_NOTICE("\The [user] steps out of the back of \the [target_closet]."), SPAN_NOTICE("You teleport into the linked closet, stepping out of it."))
|
|
user.set_fullscreen(FALSE, "closet_impaired", /atom/movable/screen/fullscreen/closet_impaired)
|
|
else
|
|
if(user.client)
|
|
user.client.eye = target_closet
|
|
target_closet.visible_message(SPAN_WARNING("\The [target_closet] rattles."))
|
|
to_chat(user, SPAN_NOTICE("You teleport into the target closet, bumping into the closed door."))
|
|
target_closet.shake_animation()
|
|
playsound(get_turf(src), 'sound/effects/grillehit.ogg', 100, TRUE)
|
|
return TRUE
|
|
|
|
/obj/item/closet_teleporter/Destroy()
|
|
attached_closet = null
|
|
if(linked_teleporter?.linked_teleporter == src)
|
|
linked_teleporter.linked_teleporter = null
|
|
linked_teleporter = null
|
|
return ..()
|