/obj/structure/machinery/camera name = "security camera" desc = "It's used to monitor compartments." icon = 'icons/obj/monitors.dmi' icon_state = "camera" use_power = POWER_USE_ACTIVE idle_power_usage = 5 active_power_usage = 10 layer = CAMERA_LAYER obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED maxhealth = OBJECT_HEALTH_EXTREMELY_LOW armor = list( MELEE = ARMOR_MELEE_SMALL, BULLET = ARMOR_BALLISTIC_MINOR, LASER = ARMOR_LASER_MINOR ) var/list/network = list(NETWORK_STATION) var/c_tag = null var/c_tag_order = 999 var/status = 1 anchored = 1.0 var/invuln = null var/bugged = 0 var/obj/item/camera_assembly/assembly = null var/toughness = 5 //sorta fragile // WIRES /// Wires datum var/datum/wires/camera/wires = null //OTHER var/view_range = 7 var/short_range = 2 var/light_disabled = 0 var/alarm_on = 0 var/busy = 0 var/on_open_network = 0 var/affected_by_emp_until = 0 /obj/structure/machinery/camera/Initialize() wires = new(src) assembly = new(src) assembly.state = 4 SSmachinery.all_cameras += src // Use this to look for cameras that have the same c_tag. if(!isnull(src.c_tag)) for(var/obj/structure/machinery/camera/C in GLOB.cameranet.cameras) var/list/tempnetwork = C.network&src.network if(C != src && C.c_tag == src.c_tag && tempnetwork.len) #if !defined(UNIT_TEST) log_mapping_error("The camera [src.c_tag] at [src.x]-[src.y]-[src.z] conflicts with the c_tag of the camera in [C.x]-[C.y]-[C.z]!") #else SSunit_tests_config.UT.fail("The camera [src.c_tag] at [src.x]-[src.y]-[src.z] conflicts with the c_tag of the camera in [C.x]-[C.y]-[C.z]!") #endif if(!src.network || src.network.len < 1) if(loc) log_mapping_error("[src.name] in [get_area(src)] (x:[src.x] y:[src.y] z:[src.z] has errored. [src.network?"Empty network list":"Null network list"]") else log_mapping_error("[src.name] in [get_area(src)]has errored. [src.network?"Empty network list":"Null network list"]") ASSERT(src.network) ASSERT(src.network.len > 0) set_pixel_offsets() var/list/open_networks = difflist(network, GLOB.restricted_camera_networks) on_open_network = open_networks.len if(on_open_network) GLOB.cameranet.add_source(src) return ..() /obj/structure/machinery/camera/Destroy() SSmachinery.all_cameras -= src deactivate(null, 0) //kick anyone viewing out if(assembly) QDEL_NULL(assembly) cancelCameraAlarm(force = TRUE) cancelAlarm() for(var/mob/target in motionTargets.Copy()) lostTarget(target) if(area_motion && area_motion.motioncamera == src) area_motion.motioncamera = null area_motion = null QDEL_NULL(wires) GLOB.cameranet.cameras -= src if(on_open_network) GLOB.cameranet.remove_source(src) . = ..() /obj/structure/machinery/camera/set_pixel_offsets() pixel_x = dir & (NORTH|SOUTH) ? 0 : (dir == EAST ? -13 : 13) pixel_y = dir & (NORTH|SOUTH) ? (dir == NORTH ? -3 : DEFAULT_WALL_OFFSET) : 0 /obj/structure/machinery/camera/process() if((stat & EMPED) && world.time >= affected_by_emp_until) stat &= ~EMPED cancelCameraAlarm() update_icon() update_coverage() return internal_process() /obj/structure/machinery/camera/proc/internal_process() // motion camera event loop if (stat & (EMPED|NOPOWER)) return if(!isMotion()) . = PROCESS_KILL return if (detectTime > 0) var/elapsed = world.time - detectTime if (elapsed > alarm_delay) triggerAlarm() else if (detectTime == -1) for (var/mob/target in motionTargets) if (target.stat == 2 || QDELING(target)) lostTarget(target) // If not detecting with motion camera... if (!area_motion) // See if the camera is still in range if(!in_range(src, target)) // If they aren't in range, lose the target. lostTarget(target) /obj/structure/machinery/camera/emp_act(severity) . = ..() if(!isEmpProof() && prob(100/severity)) if(!affected_by_emp_until || (world.time < affected_by_emp_until)) affected_by_emp_until = max(affected_by_emp_until, world.time + (90 SECONDS / severity)) else stat |= EMPED set_light(0) triggerCameraAlarm() kick_viewers() update_icon() update_coverage() /obj/structure/machinery/camera/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit) . = ..() if(. != BULLET_ACT_HIT) return . add_damage(hitting_projectile.get_structure_damage(), hitting_projectile.damage_flags(), hitting_projectile.damage_type, hitting_projectile.armor_penetration, hitting_projectile) /obj/structure/machinery/camera/ex_act(severity) if(src.invuln) return //camera dies if an explosion touches it! if(severity <= 2 || prob(50)) destroy() ..() //and give it the regular chance of being deleted outright /obj/structure/machinery/camera/hitby(atom/movable/hitting_atom, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) ..() if (istype(hitting_atom, /obj)) var/obj/O = hitting_atom if (O.throwforce >= src.toughness) visible_message(SPAN_WARNING("[src] was hit by [O].")) add_damage(O.throwforce, O.damage_flags(), O.damtype, O.armor_penetration, O) /obj/structure/machinery/camera/proc/setViewRange(var/num = 7) src.view_range = num GLOB.cameranet.update_visibility(src, 0) /obj/structure/machinery/camera/attack_hand(mob/living/carbon/human/user as mob) if(!istype(user)) return if(user.species.can_shred(user)) user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) set_status(0) user.do_attack_animation(src) visible_message(SPAN_WARNING("\The [user] slashes at [src]!")) playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) add_hiddenprint(user) destroy() /obj/structure/machinery/camera/attackby(obj/item/attacking_item, mob/user) update_coverage() // DECONSTRUCTION if(attacking_item.tool_behaviour == TOOL_SCREWDRIVER) //to_chat(user, SPAN_NOTICE("You start to [panel_open ? "close" : "open"] the camera's panel.")) //if(toggle_panel(user)) // No delay because no one likes screwdrivers trying to be hip and have a duration cooldown panel_open = !panel_open user.visible_message(SPAN_WARNING("[user] screws the camera's panel [panel_open ? "open" : "closed"]!"), SPAN_NOTICE("You screw the camera's panel [panel_open ? "open" : "closed"].")) attacking_item.play_tool_sound(get_turf(src), 50) return TRUE else if((attacking_item.tool_behaviour == TOOL_WIRECUTTER || attacking_item.tool_behaviour == TOOL_MULTITOOL) && panel_open) interact(user) return TRUE else if(attacking_item.tool_behaviour == TOOL_WELDER && (wires.CanDeconstruct() || (stat & BROKEN))) if(weld(attacking_item, user)) if(assembly) assembly.forceMove(src.loc) assembly.anchored = 1 assembly.camera_name = c_tag assembly.camera_network = english_list(network, "Station", ",", ",") assembly.update_icon() assembly.dir = src.dir if(stat & BROKEN) assembly.state = 2 to_chat(user, SPAN_NOTICE("You repaired \the [src] frame.")) else assembly.state = 1 to_chat(user, SPAN_NOTICE("You cut \the [src] free from the wall.")) new /obj/item/stack/cable_coil(loc, 2) assembly = null //so qdel doesn't eat it. qdel(src) return TRUE // OTHER else if (can_use() && (istype(attacking_item, /obj/item/paper)) && isliving(user)) var/info = null var/mob/living/U = user var/obj/item/paper/X = null var/itemname = "" if(istype(attacking_item, /obj/item/paper)) X = attacking_item itemname = X.name info = X.info to_chat(U, "You hold \a [itemname] up to the camera ...") for(var/mob/living/silicon/ai/O in GLOB.living_mob_list) var/entry = O.addCameraRecord(itemname,info) if(!O.client) continue if(U.name == "Unknown") to_chat(O, "[U] holds \a [itemname] up to one of your cameras ...view message") else to_chat(O, "[U] holds \a [itemname] up to one of your cameras ...view message") for(var/mob/O in GLOB.player_list) if (istype(O.machine, /obj/structure/machinery/computer/security)) var/obj/structure/machinery/computer/security/S = O.machine if (S.current_camera == src) to_chat(O, "[U] holds \a [itemname] up to one of the cameras ...") O << browse("