diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 39c3aafe5c..85f324c387 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -83,9 +83,8 @@ /obj/machinery/camera/emp_act(severity) if(!isEmpProof() && prob(100/severity)) - if(!affected_by_emp_until || (world.time < affected_by_emp_until)) + 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() diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm new file mode 100644 index 0000000000..69905f0cb8 --- /dev/null +++ b/code/game/objects/items/devices/laserpointer.dm @@ -0,0 +1,219 @@ +/obj/item/device/laser_pointer + name = "laser pointer" + desc = "Don't shine it in your eyes!" + icon = 'icons/obj/device.dmi' + icon_state = "pointer" + item_state = "pen" + var/pointer_icon_state + slot_flags = SLOT_BELT + matter = list("glass" = 500,"metal" = 500) + w_class = 2 //Increased to 2, because diodes are w_class 2. Conservation of matter. + origin_tech = list(TECH_MAGNET = 2, TECH_COMBAT = 1) + var/turf/pointer_loc + var/energy = 8 + var/max_energy = 8 + var/effectchance = 20 + var/cooldown = 10 + var/last_used_time = 0 + var/recharging = 0 + var/recharge_locked = 0 + var/obj/item/weapon/stock_parts/micro_laser/diode //used for upgrading! + + +/obj/item/device/laser_pointer/red + pointer_icon_state = "red_laser" +/obj/item/device/laser_pointer/green + pointer_icon_state = "green_laser" +/obj/item/device/laser_pointer/blue + pointer_icon_state = "blue_laser" +/obj/item/device/laser_pointer/purple + pointer_icon_state = "purple_laser" + +/obj/item/device/laser_pointer/New() + ..() + diode = new(src) + if(!pointer_icon_state) + pointer_icon_state = pick("red_laser","green_laser","blue_laser","purple_laser") + +/obj/item/device/laser_pointer/upgraded/New() + ..() + diode = new /obj/item/weapon/stock_parts/micro_laser/ultra + + + +/obj/item/device/laser_pointer/attack(mob/living/M, mob/user) + laser_act(M, user) + +/obj/item/device/laser_pointer/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/weapon/stock_parts/micro_laser)) + if(!diode) + user.drop_item() + W.loc = src + diode = W + to_chat(user, "You install a [diode.name] in [src].") + else + to_chat(user, "[src] already has a diode.") + + else if(istype(W, /obj/item/weapon/screwdriver)) + if(diode) + to_chat(user, "You remove the [diode.name] from the [src].") + diode.loc = get_turf(src.loc) + diode = null + return + ..() + return + +/obj/item/device/laser_pointer/afterattack(var/atom/target, var/mob/living/user, flag, params) + if(flag) //we're placing the object on a table or in backpack + return + laser_act(target, user) + +/obj/item/device/laser_pointer/proc/laser_act(var/atom/target, var/mob/living/user) + if(!(user in (viewers(world.view,target)))) + return + if(!(world.time - last_used_time >= cooldown)) + return + if (!diode) + to_chat(user, "You point [src] at [target], but nothing happens!") + return + if (!user.IsAdvancedToolUser()) + to_chat(user, "You don't have the dexterity to do this!") + return + + add_fingerprint(user) + + //nothing happens if the battery is drained + if(recharge_locked) + to_chat(user, "You point [src] at [target], but it's still charging.") + return + + var/outmsg + var/turf/targloc = get_turf(target) + + //human/alien mobs + if(iscarbon(target)) + if(user.zone_sel.selecting == "eyes") + var/mob/living/carbon/C = target + + //20% chance to actually hit the eyes + + if(prob(effectchance * diode.rating)) + add_attack_logs(user,C,"Tried blinding using [src]") + + //eye target check, will return -1 to 2 + var/eye_prot = C.eyecheck() + if(C.blinded) + eye_prot = 4 + var/severity = (rand(0, 1) + diode.rating - eye_prot) + var/mob/living/carbon/human/H = C + var/obj/item/organ/internal/eyes/E = H.internal_organs_by_name[O_EYES] + if(!E) + outmsg = "You shine [src] at [C], but they don't seem to have eyes." + return + + outmsg = "You shine [src] into [C]'s eyes." + switch(severity) + if(0) + //rank 1 diode with basic eye protection (like sunglasses), or rank 2 with industrial protection (like welding goggles) + to_chat(C, "A small, bright dot appears in your vision.") + if(1) + //rank 1 with no protection, rank 2 with basic protection, or rank 3 with industrial protection + to_chat(C, "Something bright flashes in the corner of your vision.") + if(2) + //rank 1 or 2 with no protection, rank 2 or 3 with basic protection, or rank 3 with industrial protection + //alternatively, rank 1 with minor vulnerability (like night vision goggles) + flick("flash", C.flash_eyes()) + to_chat(C, "A bright light shines across your eyes!") + if(3) + //rank 1 with minor vulnerability, rank 2 or 3 with no protection, or rank 3 with basic protection + if(prob(3 * diode.rating)) + C.Weaken(1) + flick("flash", C.flash_eyes()) + E.damage += 1 + to_chat(C, "A bright light briefly blinds you!") + if(4) + //rank 3 with no protection, or rank 2 with minor vulnerability + if(prob(5 * diode.rating)) + C.Weaken(1) + flick("e_flash", C.flash_eyes()) + E.damage += 2 + to_chat(C, "A blinding light burns your eyes!") + else + outmsg = "You shine the [src] at [C], but miss their eyes." + + //robots and AI + else if(issilicon(target)) + var/mob/living/silicon/S = target + //20% chance to actually hit the sensors + if(prob(effectchance * diode.rating)) + flick("flash", S.flash_eyes(affect_silicon = TRUE)) + if (prob(3 * diode.rating)) + S.Weaken(1) + to_chat(S, "Your sensors were blinded by a laser!") + outmsg = "You blind [S] by shining [src] at their sensors." + add_attack_logs(user,S,"Tried disabling using [src]") + else + outmsg = "You shine the [src] at [S], but miss their sensors." + + //cameras + else if(istype(target, /obj/machinery/camera)) + var/obj/machinery/camera/C = target + if(prob(effectchance * diode.rating)) + C.emp_act(4 - diode.rating) + outmsg = "You shine the [src] into the lens of [C]." + add_attack_logs(user,C.name,"Tried disabling using [src]") + else + outmsg = "You missed the lens of [C] with [src]." + + //cats! + for(var/mob/living/simple_animal/cat/C in viewers(1,targloc)) + if (!(C.stat || C.buckled)) + if(prob(50) && !(C.client)) + C.visible_message("[C] pounces on the light!", "You pounce on the light!") + step_towards(C, targloc) + C.lay_down() + spawn(10) + C.lay_down() + else + C.set_dir(get_dir(C,targloc)) + C.visible_message("[C] watches the light.", "Your attention is drawn to the mysterious glowing dot.") + + + //laser pointer image + icon_state = "pointer_[pointer_icon_state]" + var/list/showto = list() + for(var/mob/M in viewers(world.view,targloc)) + if(M.client) + showto.Add(M.client) + var/image/I = image('icons/obj/projectiles.dmi',targloc,pointer_icon_state,cooldown) + I.plane = PLANE_LIGHTING_ABOVE + I.pixel_x = target.pixel_x + rand(-5,5) + I.pixel_y = target.pixel_y + rand(-5,5) + + if(outmsg) + user.visible_message("[user] points [src] at [target].", outmsg) + else + user.visible_message("[user] points [src] at [target].", "You point [src] at [target].") + + last_used_time = world.time + energy -= 1 + if(energy <= max_energy) + if(!recharging) + recharging = 1 + processing_objects.Add(src) + if(energy <= 0) + to_chat(user, "You've overused the battery of [src], now it needs time to recharge!") + recharge_locked = 1 + + flick_overlay(I, showto, cooldown) + spawn(cooldown) + icon_state = "pointer" + +/obj/item/device/laser_pointer/process() + if(prob(20 - recharge_locked*5)) + energy += 1 + if(energy >= max_energy) + energy = max_energy + recharging = 0 + recharge_locked = 0 + ..() \ No newline at end of file diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm index 5f747a9a86..3da9a7226c 100644 --- a/code/modules/client/preference_setup/loadout/loadout_utility.dm +++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm @@ -79,6 +79,11 @@ path =/obj/item/weapon/storage/secure/briefcase cost = 2 +/datum/gear/utility/laserpointer + display_name = "laser pointer" + path =/obj/item/device/laser_pointer + cost = 2 + /datum/gear/utility/flashlight display_name = "flashlight" path = /obj/item/device/flashlight @@ -145,4 +150,4 @@ /datum/gear/utility/umbrella/New() ..() - gear_tweaks = list(gear_tweak_free_color_choice) \ No newline at end of file + gear_tweaks = list(gear_tweak_free_color_choice) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 3fb0c6e65e..aff4b81e1f 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -266,6 +266,10 @@ /mob/living/carbon/proc/eyecheck() return 0 +/mob/living/carbon/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) + if(eyecheck() < intensity || override_blindness_check) + return ..() + // ++++ROCKDTBEN++++ MOB PROCS -- Ask me before touching. // Stop! ... Hammertime! ~Carn diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index f83be22d62..57dc59f218 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -670,6 +670,12 @@ I.additional_flash_effects(number) return number +/mob/living/carbon/human/flash_eyes(var/intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) + if(internal_organs_by_name[O_EYES]) // Eyes are fucked, not a 'weak point'. + var/obj/item/organ/internal/eyes/I = internal_organs_by_name[O_EYES] + I.additional_flash_effects(intensity) + return ..() + #define add_clothing_protection(A) \ var/obj/item/clothing/C = A; \ flash_protection += C.flash_protection; \ diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 33db48993d..4e0e0daf2b 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -866,6 +866,15 @@ default behaviour is: to_chat(src, "You are now [resting ? "resting" : "getting up"]") update_canmove() +//called when the mob receives a bright flash +/mob/living/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash) + if(override_blindness_check || !(disabilities & BLIND)) + overlay_fullscreen("flash", type) + spawn(25) + if(src) + clear_fullscreen("flash", 25) + return 1 + /mob/living/proc/cannot_use_vents() if(mob_size > MOB_SMALL) return "You can't fit into that vent." diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index 8ba90c6401..1484cff07f 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -751,6 +751,15 @@ other types of metals and chemistry for reagents). build_path = /obj/item/device/lightreplacer sort_string = "VAAAH" +datum/design/item/laserpointer + name = "laser pointer" + desc = "Don't shine it in your eyes!" + id = "laser_pointer" + req_tech = list(TECH_MAGNET = 3) + materials = list(DEFAULT_WALL_MATERIAL = 100, "glass" = 50) + build_path = /obj/item/device/laser_pointer + sort_string = "VAAAI" + /datum/design/item/paicard name = "'pAI', personal artificial intelligence device" id = "paicard" diff --git a/html/changelogs/prismaticgynoid-laserpointers.yml b/html/changelogs/prismaticgynoid-laserpointers.yml new file mode 100644 index 0000000000..8552709c41 --- /dev/null +++ b/html/changelogs/prismaticgynoid-laserpointers.yml @@ -0,0 +1,4 @@ +author: PrismaticGynoid +delete-after: True +changes: + - rscadd: "Added laser pointers. Available in your loadout, and printed and upgraded by R&D." diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi index 90cc743bcf..7716fd3032 100644 Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index e0e3305d44..cb78fa2263 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 35d09318ee..a0240b53af 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/polaris.dme b/polaris.dme index 47766cdfce..ac467739b1 100644 --- a/polaris.dme +++ b/polaris.dme @@ -856,6 +856,7 @@ #include "code\game\objects\items\devices\geiger.dm" #include "code\game\objects\items\devices\gps.dm" #include "code\game\objects\items\devices\hacktool.dm" +#include "code\game\objects\items\devices\laserpointer.dm" #include "code\game\objects\items\devices\lightreplacer.dm" #include "code\game\objects\items\devices\locker_painter.dm" #include "code\game\objects\items\devices\megaphone.dm"