Files
Bubberstation/code/game/machinery/camera/camera.dm
larentoun 692540a7b9 Singularity_pull() standartize (#87304)
## About The Pull Request
Previous attempt - https://github.com/tgstation/tgstation/pull/87227

`/atom/proc/singularity_pull(obj/singularity/singularity, current_size)`
has first arg typed, but other procs were just referencing it as a
un-typed variable.

Since args are not standartized AND
`atom/proc/singularity_pull(obj/singularity/singularity, current_size)`
is out-dated, since it can be called by things that has
`/datum/component/singularity` - not just by
`obj/singularity/singularity` - This PR just adds args to every
`proc/singularity_pull()` as follows:
`proc/singularity_pull(atom/singularity, current_size)`

## Why It's Good For The Game
Standartization

## Changelog
No changelog needed
2024-10-25 02:08:26 +02:00

447 lines
15 KiB
Plaintext

/**
* Camera assembly frame
* Putting this on a wall will put a deconstructed camera machine on the wall.
*/
/obj/item/wallframe/camera
name = "camera assembly"
desc = "The basic construction for Nanotrasen-Always-Watching-You cameras."
icon = 'icons/obj/machines/camera.dmi'
icon_state = "cameracase"
custom_materials = list(
/datum/material/iron = SMALL_MATERIAL_AMOUNT * 4,
/datum/material/glass = SMALL_MATERIAL_AMOUNT * 2.5,
)
result_path = /obj/machinery/camera/autoname/deconstructed
wall_external = TRUE
/obj/machinery/camera
name = "security camera"
desc = "It's used to monitor rooms."
icon = 'icons/obj/machines/camera.dmi'
icon_state = "camera"
base_icon_state = "camera"
use_power = ACTIVE_POWER_USE
active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.02
layer = WALL_OBJ_LAYER
resistance_flags = FIRE_PROOF
damage_deflection = 12
armor_type = /datum/armor/machinery_camera
max_integrity = 100
integrity_failure = 0.5
///An analyzer in the camera being used for x-ray upgrade.
var/obj/item/analyzer/xray_module
///used to keep from revealing malf AI upgrades for user facing isXRay() checks when they use Upgrade Camera Network ability
///will be false if the camera is upgraded with the proper parts.
var/malf_xray_firmware_active
///so the malf upgrade is restored when the normal upgrade part is removed.
var/malf_xray_firmware_present
///A sheet of plasma stored inside of the camera, giving it EMP protection.
var/obj/item/stack/sheet/mineral/plasma/emp_module
///used to keep from revealing malf AI upgrades for user facing isEmp() checks after they use Upgrade Camera Network ability
///will be false if the camera is upgraded with the proper parts.
var/malf_emp_firmware_active
///so the malf upgrade is restored when the normal upgrade part is removed.
var/malf_emp_firmware_present
///The current state of the camera's construction, all mapped in ones start off already built.
var/camera_construction_state = CAMERA_STATE_FINISHED
///Bitflag of upgrades this camera has: (CAMERA_UPGRADE_XRAY | CAMERA_UPGRADE_EMP_PROOF | CAMERA_UPGRADE_MOTION)
var/camera_upgrade_bitflags = NONE
///List of all networks that can see this camera through the security console.
var/list/network = list(CAMERANET_NETWORK_SS13)
///The tag the camera has, which is essentially its name to security camera consoles.
var/c_tag = null
///Boolean on whether the camera is activated, so can be seen on camera consoles or will just be static.
var/camera_enabled = TRUE
///Boolean for special cameras to bypass the random chance of being broken on roundstart.
var/start_active = FALSE
///The area this camera is built in, which we will add/remove ourselves to the list of cameras in that area from.
var/area/myarea = null
///The max range (and default range) the camera can see.
var/view_range = 7
///The short range the camera can see, if tampered with to be short-sighted.
var/short_range = 2
///Boolean on whether the camera's alarm is triggered.
var/alarm_on = FALSE
///How many times this camera has been EMP'ed consecutively, will reset back to 0 when fixed.
var/emped
///Boolean on whether the AI can even turn on this camera's light- borg caneras dont have one, for example.
var/internal_light = TRUE
///Number of AIs watching this camera with lights on, used for icons.
var/in_use_lights = 0
///Represents a signal source of camera alarms about movement or camera tampering
var/datum/alarm_handler/alarm_manager
///Proximity monitor associated with this atom, for motion sensitive cameras.
var/datum/proximity_monitor/proximity_monitor
/// A copy of the last paper object that was shown to this camera.
var/obj/item/paper/last_shown_paper
var/list/datum/weakref/localMotionTargets = list()
var/detectTime = 0
var/area/station/ai_monitored/area_motion = null
var/alarm_delay = 30 // Don't forget, there's another 3 seconds in queueAlarm()
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/autoname, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/autoname/motion, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/emp_proof, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/motion, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0)
/datum/armor/machinery_camera
melee = 50
bullet = 20
laser = 20
energy = 20
fire = 90
acid = 50
/obj/machinery/camera/Initialize(mapload, ndir, building)
. = ..()
if(building)
setDir(ndir)
for(var/network_name in network)
network -= network_name
network += LOWER_TEXT(network_name)
GLOB.cameranet.cameras += src
myarea = get_room_area()
if(camera_enabled)
GLOB.cameranet.addCamera(src)
LAZYADD(myarea.cameras, src)
#ifdef MAP_TEST
update_appearance()
#else
if(mapload && !start_active && is_station_level(z) && prob(3))
toggle_cam()
else //this is handled by toggle_camera, so no need to update it twice.
update_appearance()
#endif
alarm_manager = new(src)
find_and_hang_on_wall(directional = TRUE, \
custom_drop_callback = CALLBACK(src, PROC_REF(deconstruct), FALSE))
/obj/machinery/camera/Destroy(force)
if(can_use())
toggle_cam(null, 0) //kick anyone viewing out and remove from the camera chunks
GLOB.cameranet.removeCamera(src)
GLOB.cameranet.cameras -= src
cancelCameraAlarm()
if(isarea(myarea))
LAZYREMOVE(myarea.cameras, src)
QDEL_NULL(alarm_manager)
QDEL_NULL(last_shown_paper)
QDEL_NULL(xray_module)
QDEL_NULL(emp_module)
QDEL_NULL(proximity_monitor)
return ..()
/obj/machinery/camera/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
for(var/i in network)
network -= i
network += "[port.shuttle_id]_[i]"
/obj/machinery/camera/Exited(atom/movable/gone, direction)
. = ..()
if(gone == xray_module)
xray_module = null
update_appearance()
if(malf_xray_firmware_present)
malf_xray_firmware_active = malf_xray_firmware_present //re-enable firmware based upgrades after the part is removed.
removeXRay(malf_xray_firmware_present) //make sure we don't remove MALF upgrades.
else if(gone == emp_module)
emp_module = null
if(malf_emp_firmware_present)
malf_emp_firmware_active = malf_emp_firmware_present //re-enable firmware based upgrades after the part is removed.
removeEmpProof(malf_emp_firmware_present) //make sure we don't remove MALF upgrades
else if(gone == proximity_monitor)
emp_module = null
removeMotion()
/obj/machinery/camera/proc/create_prox_monitor()
if(!proximity_monitor)
proximity_monitor = new(src, 1)
RegisterSignal(proximity_monitor, COMSIG_QDELETING, PROC_REF(proximity_deleted))
/obj/machinery/camera/proc/proximity_deleted()
SIGNAL_HANDLER
proximity_monitor = null
/obj/machinery/camera/proc/set_area_motion(area/A)
area_motion = A
create_prox_monitor()
/obj/machinery/camera/examine(mob/user)
. = ..()
if(isEmpProof(TRUE)) //don't reveal it's upgraded if was done via MALF AI Upgrade Camera Network ability
. += span_info("It has electromagnetic interference shielding installed.")
else
. += span_info("It can be shielded against electromagnetic interference with some <b>plasma</b>.")
if(isXRay(TRUE)) //don't reveal it's upgraded if was done via MALF AI Upgrade Camera Network ability
. += span_info("It has an X-ray photodiode installed.")
else
. += span_info("It can be upgraded with an X-ray photodiode with an <b>analyzer</b>.")
if(isMotion())
. += span_info("It has a proximity sensor installed.")
else
. += span_info("It can be upgraded with a <b>proximity sensor</b>.")
if(!camera_enabled)
. += span_info("It's currently deactivated.")
if(!panel_open && powered())
. += span_notice("You'll need to open its maintenance panel with a <b>screwdriver</b> to turn it back on.")
if(panel_open)
. += span_info("Its maintenance panel is currently open.")
if(!camera_enabled && powered())
. += span_info("It can reactivated with <b>wirecutters</b>.")
/obj/machinery/camera/emp_act(severity, reset_time = 90 SECONDS)
. = ..()
if(!camera_enabled)
return
if(. & EMP_PROTECT_SELF)
return
if(!prob(150 / severity))
return
network = list()
GLOB.cameranet.removeCamera(src)
set_machine_stat(machine_stat | EMPED)
set_light(0)
emped++ //Increase the number of consecutive EMP's
update_appearance()
addtimer(CALLBACK(src, PROC_REF(post_emp_reset), emped, network), reset_time)
for(var/mob/M as anything in GLOB.player_list)
if (M.client?.eye == src)
M.reset_perspective(null)
to_chat(M, span_warning("The screen bursts into static!"))
/obj/machinery/camera/on_saboteur(datum/source, disrupt_duration)
. = ..()
//lasts twice as much so we don't have to constantly shoot cameras just to be S T E A L T H Y
emp_act(EMP_LIGHT, reset_time = disrupt_duration * 2)
return TRUE
/obj/machinery/camera/proc/post_emp_reset(thisemp, previous_network)
if(QDELETED(src))
return
triggerCameraAlarm() //camera alarm triggers even if multiple EMPs are in effect.
if(emped != thisemp) //Only fix it if the camera hasn't been EMP'd again
return
network = previous_network
set_machine_stat(machine_stat & ~EMPED)
update_appearance()
if(can_use())
GLOB.cameranet.addCamera(src)
emped = 0 //Resets the consecutive EMP count
addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 10 SECONDS)
/obj/machinery/camera/attack_ai(mob/living/silicon/ai/user)
if (!istype(user))
return
if (!can_use())
return
user.switchCamera(src)
/obj/machinery/camera/proc/setViewRange(num = 7)
src.view_range = num
GLOB.cameranet.updateVisibility(src, 0)
/obj/machinery/camera/proc/shock(mob/living/user)
if(!istype(user))
return
user.electrocute_act(10, src)
/obj/machinery/camera/singularity_pull(atom/singularity, current_size)
if (camera_enabled && current_size >= STAGE_FIVE) // If the singulo is strong enough to pull anchored objects and the camera is still active, turn off the camera as it gets ripped off the wall.
toggle_cam(null, 0)
return ..()
///Drops a specific upgrade and nulls it where necessary.
/obj/machinery/camera/proc/drop_upgrade(obj/item/upgrade_dropped)
upgrade_dropped.forceMove(drop_location())
if(upgrade_dropped == xray_module)
xray_module = null
if(malf_xray_firmware_present)
malf_xray_firmware_active = malf_xray_firmware_present //re-enable firmware based upgrades after the part is removed.
update_appearance()
else if(upgrade_dropped == emp_module)
emp_module = null
if(malf_emp_firmware_present)
malf_emp_firmware_active = malf_emp_firmware_present //re-enable firmware based upgrades after the part is removed.
else if(upgrade_dropped == proximity_monitor)
proximity_monitor = null
/obj/machinery/camera/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
if(machine_stat & BROKEN)
return damage_amount
. = ..()
/obj/machinery/camera/atom_break(damage_flag)
if(!camera_enabled)
return
. = ..()
if(.)
triggerCameraAlarm()
toggle_cam(null, 0)
/obj/machinery/camera/on_deconstruction(disassembled)
if(!disassembled)
if(camera_construction_state >= CAMERA_STATE_WIRED)
new /obj/item/stack/cable_coil(drop_location(), 2)
new /obj/item/stack/sheet/iron(loc)
return
var/obj/item/wallframe/camera/dropped_cam = new(drop_location())
dropped_cam.update_integrity(dropped_cam.max_integrity * 0.5)
if(camera_construction_state >= CAMERA_STATE_WIRED)
new /obj/item/stack/cable_coil(drop_location(), 2)
if(xray_module)
drop_upgrade(xray_module)
if(emp_module)
drop_upgrade(emp_module)
if(proximity_monitor)
drop_upgrade(proximity_monitor)
/obj/machinery/camera/update_icon_state() //TO-DO: Make panel open states, xray camera, and indicator lights overlays instead.
var/xray_module
if(isXRay(TRUE))
xray_module = "xray"
if(!camera_enabled)
icon_state = "[xray_module][base_icon_state]_off"
return ..()
if(machine_stat & EMPED)
icon_state = "[xray_module][base_icon_state]_emp"
return ..()
icon_state = "[xray_module][base_icon_state][in_use_lights ? "_in_use" : ""]"
return ..()
/obj/machinery/camera/proc/toggle_cam(mob/user, displaymessage = TRUE)
camera_enabled = !camera_enabled
if(can_use())
GLOB.cameranet.addCamera(src)
if (isturf(loc))
myarea = get_area(src)
LAZYADD(myarea.cameras, src)
else
myarea = null
else
set_light(0)
GLOB.cameranet.removeCamera(src)
if (isarea(myarea))
LAZYREMOVE(myarea.cameras, src)
// We are not guarenteed that the camera will be on a turf. account for that
var/turf/our_turf = get_turf(src)
GLOB.cameranet.updateChunk(our_turf.x, our_turf.y, our_turf.z)
var/change_msg = "deactivates"
if(camera_enabled)
change_msg = "reactivates"
triggerCameraAlarm()
if(!QDELETED(src)) //We'll be doing it anyway in destroy
addtimer(CALLBACK(src, PROC_REF(cancelCameraAlarm)), 10 SECONDS)
if(displaymessage)
if(user)
visible_message(span_danger("[user] [change_msg] [src]!"))
add_hiddenprint(user)
else
visible_message(span_danger("\The [src] [change_msg]!"))
playsound(src, 'sound/items/tools/wirecutter.ogg', 100, TRUE)
update_appearance() //update Initialize() if you remove this.
// now disconnect anyone using the camera
//Apparently, this will disconnect anyone even if the camera was re-activated.
//I guess that doesn't matter since they can't use it anyway?
for(var/mob/O as anything in GLOB.player_list)
if (O.client?.eye == src)
O.reset_perspective(null)
to_chat(O, span_warning("The screen bursts into static!"))
/obj/machinery/camera/proc/triggerCameraAlarm()
alarm_on = TRUE
alarm_manager.send_alarm(ALARM_CAMERA, src, src)
/obj/machinery/camera/proc/cancelCameraAlarm()
alarm_on = FALSE
alarm_manager.clear_alarm(ALARM_CAMERA)
/obj/machinery/camera/proc/can_use()
if(!camera_enabled)
return FALSE
if(machine_stat & EMPED)
return FALSE
return TRUE
/obj/machinery/camera/proc/can_see()
var/list/see = null
var/turf/pos = get_turf(src)
var/turf/directly_above = GET_TURF_ABOVE(pos)
var/check_lower = pos != get_lowest_turf(pos)
var/check_higher = directly_above && istransparentturf(directly_above) && (pos != get_highest_turf(pos))
if(isXRay())
see = range(view_range, pos)
else
see = get_hear(view_range, pos)
if(check_lower || check_higher)
// Haha datum var access KILL ME
for(var/turf/seen in see)
if(check_lower)
var/turf/visible = seen
while(visible && istransparentturf(visible))
var/turf/below = GET_TURF_BELOW(visible)
for(var/turf/adjacent in range(1, below))
see += adjacent
see += adjacent.contents
visible = below
if(check_higher)
var/turf/above = GET_TURF_ABOVE(seen)
while(above && istransparentturf(above))
for(var/turf/adjacent in range(1, above))
see += adjacent
see += adjacent.contents
above = GET_TURF_ABOVE(above)
return see
/obj/machinery/camera/proc/Togglelight(on=0)
for(var/mob/living/silicon/ai/A in GLOB.ai_list)
for(var/obj/machinery/camera/cam in A.lit_cameras)
if(cam == src)
return
if(on)
set_light(AI_CAMERA_LUMINOSITY)
else
set_light(0)
/obj/machinery/camera/get_remote_view_fullscreens(mob/user)
if(view_range == short_range) //unfocused
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 2)
/obj/machinery/camera/update_remote_sight(mob/living/user)
user.set_invis_see(SEE_INVISIBLE_LIVING) //can't see ghosts through cameras
if(isXRay())
user.add_sight(SEE_TURFS|SEE_MOBS|SEE_OBJS)
else
user.clear_sight(SEE_TURFS|SEE_MOBS|SEE_OBJS)
return TRUE