From fad55066836631767e23dbdb26e0fa1be38ed5d3 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Tue, 2 Dec 2014 17:19:46 -0500 Subject: [PATCH] Cameras can be broken by weapons/projectiles, fixes Fixes being able to show papers to AIs through deactivated cameras. Fixes being able to break doors with TOX, OXY, and CLONE damage. Fixes camera alarms persisting after the camera is deleted. Fixes #7021. Some camera cleanup. --- code/datums/wires/robot.dm | 4 +- code/game/machinery/camera/camera.dm | 136 +++++++++++++----- code/game/machinery/camera/camera_assembly.dm | 4 +- code/game/machinery/doors/door.dm | 6 +- 4 files changed, 107 insertions(+), 43 deletions(-) diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm index 13e53164320..f65ee6be508 100644 --- a/code/datums/wires/robot.dm +++ b/code/datums/wires/robot.dm @@ -40,7 +40,7 @@ var/const/BORG_WIRE_CAMERA = 16 if (BORG_WIRE_CAMERA) if(!isnull(R.camera) && !R.scrambledcodes) R.camera.status = mended - R.camera.deactivate(usr, 0) // Will kick anyone who is watching the Cyborg's camera. + R.camera.kick_viewers() // Will kick anyone who is watching the Cyborg's camera. if(BORG_WIRE_LAWCHECK) //Forces a law update if the borg is set to receive them. Since an update would happen when the borg checks its laws anyway, not much use, but eh if (R.lawupdate) @@ -83,7 +83,7 @@ var/const/BORG_WIRE_CAMERA = 16 if (BORG_WIRE_CAMERA) if(!isnull(R.camera) && R.camera.can_use() && !R.scrambledcodes) - R.camera.deactivate(usr, 0) // Kick anyone watching the Cyborg's camera, doesn't display you disconnecting the camera. + R.camera.kick_viewers() // Kick anyone watching the Cyborg's camera R.visible_message("[R]'s camera lense focuses loudly.") R << "Your camera lense focuses loudly." diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 140659a0e51..96f87e89c1d 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -11,13 +11,15 @@ var/list/network = list("SS13") var/c_tag = null var/c_tag_order = 999 - var/status = 1.0 + var/status = 1 anchored = 1.0 var/panel_open = 0 // 0 = Closed / 1 = Open var/invuln = null var/bugged = 0 var/obj/item/weapon/camera_assembly/assembly = null + var/toughness = 5 //sorta fragile + // WIRES var/datum/wires/camera/wires = null // Wires datum @@ -49,37 +51,57 @@ ASSERT(src.network.len > 0) ..() +/obj/machinery/camera/Del() + if(!alarm_on) + triggerCameraAlarm() + + spawn(50) + src = null + cancelCameraAlarm() //so camera alarms don't just go on forever + ..() + /obj/machinery/camera/emp_act(severity) if(!isEmpProof()) if(prob(100/severity)) - icon_state = "[initial(icon_state)]emp" - var/list/previous_network = network - network = list() - cameranet.removeCamera(src) stat |= EMPED SetLuminosity(0) + kick_viewers() triggerCameraAlarm() + update_icon() + spawn(900) - network = previous_network - icon_state = initial(icon_state) stat &= ~EMPED cancelCameraAlarm() - if(can_use()) - cameranet.addCamera(src) - kick_viewers() + update_icon() + ..() +/obj/machinery/camera/bullet_act(var/obj/item/projectile/P) + if(P.damage_type == BRUTE || P.damage_type == BURN) + take_damage(P.damage) /obj/machinery/camera/ex_act(severity) if(src.invuln) return - else - ..(severity) - 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/machinery/camera/blob_act() return +/obj/machinery/camera/hitby(AM as mob|obj) + ..() + if (istype(AM, /obj)) + var/obj/O = AM + if (O.throwforce >= src.toughness) + visible_message("[src] was hit by [O].") + take_damage(O.throwforce) + /obj/machinery/camera/proc/setViewRange(var/num = 7) src.view_range = num cameranet.updateVisibility(src, 0) @@ -90,14 +112,14 @@ return if(user.species.can_shred(user)) - status = 0 + set_status(0) visible_message("\The [user] slashes at [src]!") playsound(src.loc, 'sound/weapons/slash.ogg', 100, 1) icon_state = "[initial(icon_state)]1" add_hiddenprint(user) - deactivate(user,0) + destroy() -/obj/machinery/camera/attackby(W as obj, mob/living/user as mob) +/obj/machinery/camera/attackby(obj/W as obj, mob/living/user as mob) // DECONSTRUCTION if(isscrewdriver(W)) @@ -111,16 +133,19 @@ else if((iswirecutter(W) || ismultitool(W)) && panel_open) interact(user) - else if(iswelder(W) && wires.CanDeconstruct()) + else if(iswelder(W) && (wires.CanDeconstruct() || (stat & BROKEN))) if(weld(W, user)) - if(assembly) + if (stat & BROKEN) + new /obj/item/broken_device(src.loc) //TODO make a broken electronics item instead of reusing cyborg stuff + new /obj/item/stack/cable_coil(src.loc, length=2) + else if(assembly) assembly.loc = src.loc assembly.state = 1 + new /obj/item/stack/cable_coil(src.loc, length=2) del(src) - // OTHER - else if ((istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user)) + else if (can_use() && (istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/device/pda)) && isliving(user)) var/mob/living/U = user var/obj/item/weapon/paper/X = null var/obj/item/device/pda/P = null @@ -147,6 +172,7 @@ if (S.current == src) O << "[U] holds \a [itemname] up to one of the cameras ..." O << browse(text("[][]", itemname, info), text("window=[]", itemname)) + else if (istype(W, /obj/item/weapon/camera_bug)) if (!src.can_use()) user << "\blue Camera non-functional" @@ -157,22 +183,25 @@ else user << "\blue Camera bugged." src.bugged = 1 - else if(istype(W, /obj/item/weapon/melee/energy/blade))//Putting it here last since it's a special case. I wonder if there is a better way to do these than type casting. - deactivate(user,2)//Here so that you can disconnect anyone viewing the camera, regardless if it's on or off. - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, loc) - spark_system.start() - playsound(loc, 'sound/weapons/blade1.ogg', 50, 1) - playsound(loc, "sparks", 50, 1) - visible_message("\blue The camera has been sliced apart by [] with an energy blade!") - del(src) + + else if(W.damtype == BRUTE || W.damtype == BURN) //bashing cameras + if (W.force >= src.toughness) + visible_message("[src] has been [pick(W.attack_verb)] with [W] by [user]!") + if (istype(W, /obj/item)) //is it even possible to get into attackby() with non-items? + var/obj/item/I = W + if (I.hitsound) + playsound(loc, I.hitsound, 50, 1, -1) + take_damage(W.force) + else ..() - return /obj/machinery/camera/proc/deactivate(user as mob, var/choice = 1) - if(choice==1) - status = !( src.status ) + if(choice != 1) + //legacy support, if choice is != 1 then just kick viewers without changing status + kick_viewers() + else + set_status( !src.status ) if (!(src.status)) visible_message("\red [user] has deactivated [src]!") playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) @@ -183,10 +212,32 @@ playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) icon_state = initial(icon_state) add_hiddenprint(user) - // 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? + +/obj/machinery/camera/proc/take_damage(var/force, var/message) + //prob(25) gives an average of 3-4 hits + if (force >= toughness && (force > toughness*4 || prob(25))) + destroy() + +//Used when someone breaks a camera +/obj/machinery/camera/proc/destroy() + stat |= BROKEN kick_viewers() + triggerCameraAlarm() + update_icon() + + //sparks + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, loc) + spark_system.start() + playsound(loc, "sparks", 50, 1) + +/obj/machinery/camera/proc/set_status(var/newstatus) + if (status != newstatus) + status = newstatus + // 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 couldn't use it anyway? + kick_viewers() //This might be redundant, because of check_eye() /obj/machinery/camera/proc/kick_viewers() @@ -198,6 +249,14 @@ O.reset_view(null) O << "The screen bursts into static." +/obj/machinery/camera/update_icon() + if (!status || (stat & BROKEN)) + icon_state = "[initial(icon_state)]1" + else if (stat & EMPED) + icon_state = "[initial(icon_state)]emp" + else + icon_state = initial(icon_state) + /obj/machinery/camera/proc/triggerCameraAlarm() alarm_on = 1 for(var/mob/living/silicon/S in mob_list) @@ -209,10 +268,11 @@ for(var/mob/living/silicon/S in mob_list) S.cancelAlarm("Camera", get_area(src), src) +//if false, then the camera is listed as DEACTIVATED and cannot be used /obj/machinery/camera/proc/can_use() if(!status) return 0 - if(stat & EMPED) + if(stat & (EMPED|BROKEN)) return 0 return 1 @@ -284,6 +344,10 @@ /obj/machinery/camera/interact(mob/living/user as mob) if(!panel_open || istype(user, /mob/living/silicon/ai)) return + + if(stat & BROKEN) + user << "\The [src] is broken." + return user.set_machine(src) wires.Interact(user) diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index 0017b260c29..48f0a94faf2 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -1,6 +1,6 @@ /obj/item/weapon/camera_assembly name = "camera assembly" - desc = "The basic construction for Nanotrasen-Always-Watching-You cameras." + desc = "A pre-fabricated security camera kit, ready to be assembled and mounted to a surface." icon = 'icons/obj/monitors.dmi' icon_state = "cameracase" w_class = 2 @@ -171,4 +171,4 @@ return 0 return 1 busy = 0 - return 0 \ No newline at end of file + return 0 diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 37966deea69..bc8719060f4 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -129,8 +129,8 @@ /obj/machinery/door/bullet_act(var/obj/item/projectile/Proj) ..() - //Tasers and the like should not damage doors. - if(Proj.damage_type == HALLOSS) + //Tasers and the like should not damage doors. Nor should TOX, OXY, CLONE, etc damage types + if(!(Proj.damage_type == BRUTE || Proj.damage_type == BURN)) return if(Proj.damage) @@ -139,7 +139,7 @@ /obj/machinery/door/hitby(AM as mob|obj) ..() - visible_message("\red [src.name] was hit by [AM].", 1) + visible_message("\red [src.name] was hit by [AM].") var/tforce = 0 if(ismob(AM)) tforce = 15