Files
Alexis 21b4095dfd [MDB IGNORE] [IDB IGNORE] Upstream Sync - 04/17/2026 (#5453)
Upstream 04/17/2026

fixes https://github.com/Bubberstation/Bubberstation/issues/5549

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>
Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com>
Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com>
Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com>
Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com>
Co-authored-by: loganuk <fakeemail123@aol.com>
Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com>
Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com>
Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com>
Co-authored-by: Lucy <lucy@absolucy.moe>
Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com>
Co-authored-by: Isratosh <Isratosh@hotmail.com>
Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com>
Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com>
Co-authored-by: Alexander V. <volas@ya.ru>
Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com>
Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Tim <timothymtorres@gmail.com>
Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com>
Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com>
Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com>
Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com>
Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com>
Co-authored-by: Josh <josh.adam.powell@gmail.com>
Co-authored-by: Josh Powell <josh.powell@softwire.com>
Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com>
Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com>
Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com>
Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
2026-05-16 00:56:00 +02:00

165 lines
5.2 KiB
Plaintext

/**
* A camera controlled by a machine-operating user, like advanced cameras.
* Handles assigning/unassigning it's users, as well as applying sight effects.
*/
/mob/eye/camera/remote
/// Weakref to the current user of this eye. Must be a [living mob][/mob/living].
var/datum/weakref/user_ref
/// Weakref to the creator of this eye. Must be a [machine][/obj/machinery].
var/datum/weakref/origin_ref
/// TRUE if this camera should show itself to the user.
var/visible_to_user = FALSE
/// If visible_to_user is TRUE, it will show this in the center of the screen.
VAR_PROTECTED/image/user_image
/* The below code could be shared by AI eyes... */
/// If TRUE, the eye will have acceleration when moving.
var/acceleration = TRUE
/// Used internally for calculating wait time. (world.timeofday + wait_time)
VAR_FINAL/last_moved = 0
/// The amount of time that must pass before var/sprint is reset.
VAR_PROTECTED/wait_time = 5 DECISECONDS
/// The speed of the camera. Scales from initial(sprint) to var/max_sprint
VAR_PROTECTED/sprint = 10
/// Amount of speed that is added to var/sprint.
VAR_PROTECTED/momentum = 0.5
/// The maximum sprint that this eye can reach.
VAR_PROTECTED/max_sprint = 50
/mob/eye/camera/remote/Initialize(mapload, obj/machinery/creator)
if(!creator)
return INITIALIZE_HINT_QDEL
. = ..()
origin_ref = WEAKREF(creator)
if(visible_to_user)
set_user_icon(icon, icon_state)
/mob/eye/camera/remote/Destroy()
var/mob/living/user = user_ref?.resolve()
var/obj/machinery/origin = origin_ref?.resolve()
if(origin && user)
origin.remove_eye_control(user,src)
assign_user(null)
origin_ref = null
return ..()
/mob/eye/camera/remote/proc/assign_user(mob/living/new_user)
var/mob/living/old_user = user_ref?.resolve()
SEND_SIGNAL(src, COMSIG_REMOTE_CAMERA_ASSIGN_USER, new_user, old_user)
if(old_user)
old_user.remote_control = null
old_user.reset_perspective(null)
name = initial(src.name)
var/client/old_user_client = GetViewerClient()
if(user_image && old_user_client)
old_user_client.images -= user_image
clear_camera_chunks()
user_ref = WEAKREF(new_user) //The user_ref can still be null!
if(new_user)
new_user.remote_control = src
new_user.reset_perspective(src)
name = "Camera Eye ([new_user.name])"
var/client/new_user_client = GetViewerClient()
if(user_image && new_user_client)
new_user_client.images += user_image
if(use_visibility)
update_visibility()
/**
* Sets the camera's user image to this icon and state.
* If chosen_icon is null, the user image will be removed.
*/
/mob/eye/camera/remote/proc/set_user_icon(icon/chosen_icon, icon_state)
SHOULD_CALL_PARENT(TRUE)
var/client/user_client = GetViewerClient()
if(!isnull(chosen_icon))
set_user_icon(null) //remove whatever the last icon was
if(!isicon(chosen_icon) || !(!isnull(icon_state) && istext(icon_state)))
CRASH("Tried to set [src]'s user_image with bad parameters")
user_image = image(chosen_icon, src, icon_state, FLY_LAYER)
if(user_client)
user_client.images += user_image
else
if(user_client)
user_client.images -= user_image
QDEL_NULL(user_image)
/mob/eye/camera/remote/update_remote_sight(mob/living/user)
user.set_invis_see(SEE_INVISIBLE_LIVING) //can't see ghosts through cameras
user.set_sight(SEE_TURFS)
return TRUE
/mob/eye/camera/remote/GetViewerClient()
var/mob/living/user = user_ref?.resolve()
if(user)
return user.client
return null
/mob/eye/camera/remote/setLoc(turf/destination, force_update = FALSE)
. = ..()
var/client/user_client = GetViewerClient()
if(user_image && user_client)
SET_PLANE(user_image, ABOVE_GAME_PLANE, destination) //incase we move a z-level
/mob/eye/camera/remote/relaymove(mob/living/user, direction)
var/initial = initial(src.sprint)
if(last_moved < world.timeofday) // It's been too long since we last moved, reset sprint
sprint = initial
for(var/i = 0; i < max(sprint, initial); i += 20)
var/turf/step = get_turf(get_step_multiz(src, direction))
if(step)
if(!(ISINRANGE_EX(step.x, TRANSITIONEDGE, world.maxx - TRANSITIONEDGE) && ISINRANGE_EX(step.y, TRANSITIONEDGE, world.maxy - TRANSITIONEDGE)))
transition_step(step, direction)
else
setLoc(step)
last_moved = world.timeofday + wait_time
if(acceleration)
sprint = min(sprint + momentum, max_sprint)
else
sprint = initial
/mob/eye/camera/remote/proc/transition_step(turf/destination, direction)
var/datum/space_level/from = SSmapping.get_level(destination.z)
var/datum/space_level/into = from.neigbours["[direction]"]
if(into && allow_z_transition(from, into))
var/dest_x = destination.x
var/dest_y = destination.y
switch(direction)
if(NORTH)
dest_y = 1+TRANSITIONEDGE
if(SOUTH)
dest_y = world.maxy-TRANSITIONEDGE
if(EAST)
dest_x = 1+TRANSITIONEDGE
if(WEST)
dest_x = world.maxx-TRANSITIONEDGE
var/turf/new_destination = locate(dest_x, dest_y, into.z_value)
setLoc(new_destination || destination)
else
setLoc(destination)
/mob/eye/camera/remote/proc/allow_z_transition(datum/space_level/from, datum/space_level/into)
return from == into
/mob/eye/camera/remote/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents)
. = ..()
astype(user_ref?.resolve(), /mob/living)?.on_looking_z_level_change(old_turf, new_turf)