From fbf5fa078674ec960905c8fc294c82e91bf2dea6 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 15:53:12 -0800 Subject: [PATCH 01/14] the action and the item --- code/game/objects/items/robot/ai_upgrades.dm | 139 ++++++++++++++++++ .../management/ai_controlpanel.dm | 14 +- 2 files changed, 151 insertions(+), 2 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index 26f6b553ce4f..0c87977fd74c 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -45,3 +45,142 @@ log_game("[key_name(user)] has upgraded [key_name(AI)] with a [src].") message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].") qdel(src) + +/obj/item/cameragun_upgrade + name = "camera laser upgrade" + desc = "A software package that will allow an artificial intelligence to briefly increase the amount of light an camera outputs to an outrageous amount to the point it burns skins. Must be installed using an unlocked AI control console." // In short, laser gun! + icon = 'icons/obj/module.dmi' + icon_state = "datadisk3" + +/obj/item/cameragun_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user) + . = ..() + if(!istype(AI)) + return + + var/datum/action/innate/ai/ranged/cameragun/ability = new + ability.Grant(AI) + + to_chat(user, span_notice("You upgrade [AI]. [src] is consumed in the process.")) + log_game("[key_name(user)] has upgraded [key_name(AI)] with a [src].") + message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].") + qdel(src) + +/// An ability that allows the user to shoot a laser beam at a target from the nearest camera. +/datum/action/innate/ai/ranged/cameragun + name = "Camera Laser Gun" + desc = "Shoots a laser from the nearest available camera toward a chosen destination. Accuracy not guaranteed." // Disclaimer is to warn people to treat this like a turret's aiming -- it might be a bit dumb at times. + button_icon = 'icons/obj/guns/energy.dmi' + button_icon_state = "laser" + enable_text = span_notice("You prepare to overcharge a camera. Click a target for a nearby camera to shoot a laser at.") + disable_text = span_notice("You dissipate the overcharged energy.") + click_action = FALSE // Even though that we are an click action, we want to use Activate() and Deactivate(). + COOLDOWN_DECLARE(next_shot) + var/cooldown = 10 SECONDS + +/// Checks if it is possible for an projectile to reach a target in a straight line from a camera. +/datum/action/innate/ai/ranged/cameragun/proc/can_shoot_to(obj/machinery/camera/C, turf/target, atom/A, ensureness = 0) + var/turf/turf_camera = get_turf(C.loc) + var/obj/dummy = new(turf_camera) + switch(ensureness) // How confident do we want to be about the projectile reaching their destination? Lower is more restrictive/confident. + if(0) + dummy.pass_flags |= PASSTABLE // Might hit their attached wall if the camera is on a corner -- should hit otherwise. + if(1) + dummy.pass_flags |= PASSTABLE|PASSGLASS|PASSGRILLE // Same concerns above. + if(2) + dummy.pass_flags |= PASSTABLE|PASSGLASS|PASSGRILLE|PASSMACHINES|PASSCOMPUTER|PASSMOB|PASSSTRUCTURE // May hit a dense object on the way, but intentional. + for(var/turf/turf in getline(turf_camera, target)) + if(turf.density) + qdel(dummy) + return FALSE + for(var/atom/movable/AM in turf) + if(!AM.CanPass(dummy, turf, 1)) + qdel(dummy) + return FALSE + qdel(dummy) + return TRUE + +/datum/action/innate/ai/ranged/cameragun/New() + ..() + START_PROCESSING(SSfastprocess, src) + +/datum/action/innate/ai/ranged/cameragun/Destroy() + STOP_PROCESSING(SSfastprocess, src) + return ..() + +/datum/action/innate/ai/ranged/cameragun/process() + build_all_button_icons() // To update the button to display if active/available. + +/datum/action/innate/ai/ranged/cameragun/Activate(loud = TRUE) + if(!COOLDOWN_FINISHED(src, next_shot)) + to_chat(owner, span_notice("Wait [COOLDOWN_TIMELEFT(src, next_shot)/10] seconds for the next camera overcharge.")) + return + set_ranged_ability(owner, loud ? enable_text : null) + active = TRUE + background_icon_state = "bg_default_on" + build_all_button_icons() + +/datum/action/innate/ai/ranged/cameragun/Deactivate(loud = TRUE) + unset_ranged_ability(owner, loud ? disable_text : null) + active = FALSE + background_icon_state = "bg_default" + build_all_button_icons() + +/datum/action/innate/ai/ranged/cameragun/IsAvailable(feedback = FALSE) + . = ..() + if(!. || !COOLDOWN_FINISHED(src, next_shot)) + return FALSE + +/datum/action/innate/ai/ranged/cameragun/do_ability(mob/living/caller, params, atom/target) + var/turf/loc_target = get_turf(target) + var/obj/machinery/camera/chosen_camera + for(var/obj/machinery/camera/cam in GLOB.cameranet.cameras) + if(!isturf(cam.loc)) + continue + if(cam == target) + continue + if(!cam.status || cam.emped) // Non-functional camera. + continue + var/turf/loc_camera = get_turf(cam) + if(loc_target.z != loc_camera.z) + continue + if(get_dist(cam, target) > 12) + continue + if(get_dist(cam, target) == 0) // Pointblank shot. + chosen_camera = cam + break + if(can_shoot_to(cam, loc_target, null, ensureness = 0)) // Camera with the best accuracy. + chosen_camera = cam + break + if(!can_shoot_to(cam, loc_target, null, ensureness = 2)) // Never had the possibility to hit. + continue + if(!chosen_camera) + chosen_camera = cam + continue + if(get_dist(chosen_camera, target) > get_dist(cam, target)) // Closest camera that can hit. + chosen_camera = cam + continue + if(!chosen_camera) + Deactivate(FALSE) + to_chat(caller, span_notice("Unable to find nearby available cameras for this target.")) + return FALSE + + COOLDOWN_START(src, next_shot, cooldown) + var/turf/loc_chosen = get_turf(chosen_camera) + var/obj/projectile/beam/laser/proj = null + proj = new /obj/projectile/beam/laser(loc_chosen) + proj.preparePixelProjectile(target, loc_chosen) + proj.firer = caller + + // Fire the shot. + var/pointblank = get_dist(chosen_camera, target) == 0 ? TRUE : FALSE // Same tile. + if(pointblank) + chosen_camera.visible_message(span_danger("[chosen_camera] fires a laser point blank at [target]!")) + proj.fire(direct_target = target) + else + chosen_camera.visible_message(span_danger("[chosen_camera] fires a laser!")) + proj.fire() + Deactivate(FALSE) + to_chat(caller, span_danger("Camera overcharged.")) + + chosen_camera.emp_act(EMP_LIGHT) // 90 seconds downtime -- definitely enough time to toolbox this camera (unless it is emp-proof). + return TRUE diff --git a/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm b/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm index eaccf21f5213..f0ac4cb859fa 100644 --- a/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm +++ b/code/modules/mob/living/silicon/ai/decentralized/management/ai_controlpanel.dm @@ -80,7 +80,17 @@ GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6)) return ..() var/obj/item/surveillance_upgrade/upgrade = W upgrade.afterattack(AI, user) - + return FALSE + if(istype(W, /obj/item/cameragun_upgrade)) + if(!authenticated) + to_chat(user, span_warning("You need to be logged in to do this!")) + return ..() + var/mob/living/silicon/ai/AI = input("Select an AI", "Select an AI", null, null) as null|anything in GLOB.ai_list + if(!AI) + return ..() + var/obj/item/cameragun_upgrade/upgrade = W + upgrade.afterattack(AI, user) + return FALSE if(istype(W, /obj/item/malf_upgrade)) if(!authenticated) to_chat(user, span_warning("You need to be logged in to do this!")) @@ -90,7 +100,7 @@ GLOBAL_VAR_INIT(ai_control_code, random_nukecode(6)) return ..() var/obj/item/malf_upgrade/upgrade = W upgrade.afterattack(AI, user) - + return FALSE return ..() /obj/machinery/computer/ai_control_console/emag_act(mob/user, obj/item/card/emag/emag_card) From ab70c85fefc43e33d5f1a0ddfc13107a47915e5f Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 16:09:19 -0800 Subject: [PATCH 02/14] uplink item and cost reason --- code/modules/uplink/uplink_items.dm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 4a0d87837d9d..b9c4661ee47f 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -2680,6 +2680,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) cost = 4 // Not as "destructive" as the emag. In addition, less features than the normal emag. Increase price once more impactful features are added. restricted_roles = list("Clown") +/datum/uplink_item/role_restricted/ai_cameragun + name = "AI Camera Gun Upgrade" + desc = "A disk containing experimental and illegal software that allows an AI to temporarily override the safety features on their cameras, enabling them to shoot a laser beam out of them." + item = /obj/item/cameragun_upgrade + cost = 8 // Considering that you have to: subvert an AI, trust the AI not to be a traitor/unsubverted, accept that every camera is gonna get disabled later, and pay more than an emag for this... 8 is fair. + restricted_roles = list("Roboticist", "Research Director") + // Pointless /datum/uplink_item/badass category = "(Pointless) Badassery" From 71f4574e917da3f4ebb06ad16af86e4e5ee71174 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 16:11:06 -0800 Subject: [PATCH 03/14] no need for msg due to isavailable --- code/game/objects/items/robot/ai_upgrades.dm | 3 --- 1 file changed, 3 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index 0c87977fd74c..96c4b2b5ecd2 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -111,9 +111,6 @@ build_all_button_icons() // To update the button to display if active/available. /datum/action/innate/ai/ranged/cameragun/Activate(loud = TRUE) - if(!COOLDOWN_FINISHED(src, next_shot)) - to_chat(owner, span_notice("Wait [COOLDOWN_TIMELEFT(src, next_shot)/10] seconds for the next camera overcharge.")) - return set_ranged_ability(owner, loud ? enable_text : null) active = TRUE background_icon_state = "bg_default_on" From 7eb1f47022f9f764ea5b734f29e62e66b2959515 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 16:13:58 -0800 Subject: [PATCH 04/14] better var name --- code/game/objects/items/robot/ai_upgrades.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index 96c4b2b5ecd2..693d76c712b4 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -78,10 +78,10 @@ var/cooldown = 10 SECONDS /// Checks if it is possible for an projectile to reach a target in a straight line from a camera. -/datum/action/innate/ai/ranged/cameragun/proc/can_shoot_to(obj/machinery/camera/C, turf/target, atom/A, ensureness = 0) +/datum/action/innate/ai/ranged/cameragun/proc/can_shoot_to(obj/machinery/camera/C, turf/target, atom/A, confidence = 0) var/turf/turf_camera = get_turf(C.loc) var/obj/dummy = new(turf_camera) - switch(ensureness) // How confident do we want to be about the projectile reaching their destination? Lower is more restrictive/confident. + switch(confidence) // How confident do we want to be about the projectile reaching their destination? Lower is more restrictive/confident. if(0) dummy.pass_flags |= PASSTABLE // Might hit their attached wall if the camera is on a corner -- should hit otherwise. if(1) @@ -145,10 +145,10 @@ if(get_dist(cam, target) == 0) // Pointblank shot. chosen_camera = cam break - if(can_shoot_to(cam, loc_target, null, ensureness = 0)) // Camera with the best accuracy. + if(can_shoot_to(cam, loc_target, null, confidence = 0)) // Camera with the best accuracy. chosen_camera = cam break - if(!can_shoot_to(cam, loc_target, null, ensureness = 2)) // Never had the possibility to hit. + if(!can_shoot_to(cam, loc_target, null, confidence = 2)) // Never had the possibility to hit. continue if(!chosen_camera) chosen_camera = cam From a367e13ea0fdefb49a926fe5f8e7a4da84e65977 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 17:43:32 -0800 Subject: [PATCH 05/14] accuracy (almost) guaranteed!!! --- code/game/objects/items/robot/ai_upgrades.dm | 55 ++++++++++---------- code/modules/projectiles/projectile.dm | 6 +-- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index 693d76c712b4..4fa40f3736c0 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -68,7 +68,7 @@ /// An ability that allows the user to shoot a laser beam at a target from the nearest camera. /datum/action/innate/ai/ranged/cameragun name = "Camera Laser Gun" - desc = "Shoots a laser from the nearest available camera toward a chosen destination. Accuracy not guaranteed." // Disclaimer is to warn people to treat this like a turret's aiming -- it might be a bit dumb at times. + desc = "Shoots a laser from the nearest available camera toward a chosen destination. Only fires if the laser will hit target/destination." // This means if you aim at a turf and it doesn't collide, it won't fire. button_icon = 'icons/obj/guns/energy.dmi' button_icon_state = "laser" enable_text = span_notice("You prepare to overcharge a camera. Click a target for a nearby camera to shoot a laser at.") @@ -77,27 +77,31 @@ COOLDOWN_DECLARE(next_shot) var/cooldown = 10 SECONDS + /// Checks if it is possible for an projectile to reach a target in a straight line from a camera. -/datum/action/innate/ai/ranged/cameragun/proc/can_shoot_to(obj/machinery/camera/C, turf/target, atom/A, confidence = 0) - var/turf/turf_camera = get_turf(C.loc) - var/obj/dummy = new(turf_camera) - switch(confidence) // How confident do we want to be about the projectile reaching their destination? Lower is more restrictive/confident. - if(0) - dummy.pass_flags |= PASSTABLE // Might hit their attached wall if the camera is on a corner -- should hit otherwise. - if(1) - dummy.pass_flags |= PASSTABLE|PASSGLASS|PASSGRILLE // Same concerns above. - if(2) - dummy.pass_flags |= PASSTABLE|PASSGLASS|PASSGRILLE|PASSMACHINES|PASSCOMPUTER|PASSMOB|PASSSTRUCTURE // May hit a dense object on the way, but intentional. - for(var/turf/turf in getline(turf_camera, target)) - if(turf.density) - qdel(dummy) - return FALSE - for(var/atom/movable/AM in turf) - if(!AM.CanPass(dummy, turf, 1)) - qdel(dummy) - return FALSE - qdel(dummy) - return TRUE +/datum/action/innate/ai/ranged/cameragun/proc/can_shoot_to(obj/machinery/camera/C, turf/target, confidence = 0) + var/obj/projectile/proj = new /obj/projectile + proj.icon = null + proj.icon_state = null + proj.hitsound = "" + proj.suppressed = TRUE + proj.ricochets_max = 0 + proj.ricochet_chance = 0 + proj.damage = 0 + proj.nodamage = TRUE + proj.log_override = TRUE + proj.hitscan = TRUE + proj.pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE + + var/turf/current_turf = get_turf(C) + proj.preparePixelProjectile(target, current_turf) + proj.fire() + + var/turf/target_turf = get_turf(target) + var/turf/last_turf = proj.hitscan_last + if(last_turf == target_turf) + return TRUE + return FALSE /datum/action/innate/ai/ranged/cameragun/New() ..() @@ -140,15 +144,12 @@ var/turf/loc_camera = get_turf(cam) if(loc_target.z != loc_camera.z) continue - if(get_dist(cam, target) > 12) - continue if(get_dist(cam, target) == 0) // Pointblank shot. chosen_camera = cam break - if(can_shoot_to(cam, loc_target, null, confidence = 0)) // Camera with the best accuracy. - chosen_camera = cam - break - if(!can_shoot_to(cam, loc_target, null, confidence = 2)) // Never had the possibility to hit. + if(get_dist(cam, target) > 12) + continue + if(!can_shoot_to(cam, loc_target)) // Camera can hit this spot. continue if(!chosen_camera) chosen_camera = cam diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index f8c23aa21917..6535c89380a5 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -58,7 +58,8 @@ var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored. var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation. var/datum/point/beam_index - var/turf/hitscan_last //last turf touched during hitscanning. + /// The ending/last touched turf during hitscanning. + var/turf/hitscan_last var/tracer_type var/muzzle_type var/impact_type @@ -584,10 +585,9 @@ pixel_x = trajectory.return_px() pixel_y = trajectory.return_py() forcemoved = TRUE - hitscan_last = loc else if(T != loc) step_towards(src, T) - hitscan_last = loc + hitscan_last = T if(!hitscanning && !forcemoved) pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier * SSprojectiles.global_iterations_per_move pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier * SSprojectiles.global_iterations_per_move From 2d23c9af9021f02d9c7771e2134a6a503570b45d Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 18:13:31 -0800 Subject: [PATCH 06/14] now can target objects (but not specific turfs) --- code/game/objects/items/robot/ai_upgrades.dm | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index 4fa40f3736c0..d03847083815 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -68,7 +68,7 @@ /// An ability that allows the user to shoot a laser beam at a target from the nearest camera. /datum/action/innate/ai/ranged/cameragun name = "Camera Laser Gun" - desc = "Shoots a laser from the nearest available camera toward a chosen destination. Only fires if the laser will hit target/destination." // This means if you aim at a turf and it doesn't collide, it won't fire. + desc = "Shoots a laser from the nearest available camera toward a chosen destination. Only fires if the laser could reach destination." // This means if you aim at a turf and it doesn't collide, it won't fire. Beware of moving targets. button_icon = 'icons/obj/guns/energy.dmi' button_icon_state = "laser" enable_text = span_notice("You prepare to overcharge a camera. Click a target for a nearby camera to shoot a laser at.") @@ -77,9 +77,8 @@ COOLDOWN_DECLARE(next_shot) var/cooldown = 10 SECONDS - /// Checks if it is possible for an projectile to reach a target in a straight line from a camera. -/datum/action/innate/ai/ranged/cameragun/proc/can_shoot_to(obj/machinery/camera/C, turf/target, confidence = 0) +/datum/action/innate/ai/ranged/cameragun/proc/can_shoot_to(obj/machinery/camera/C, atom/target, confidence = 0) var/obj/projectile/proj = new /obj/projectile proj.icon = null proj.icon_state = null @@ -93,8 +92,7 @@ proj.hitscan = TRUE proj.pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE - var/turf/current_turf = get_turf(C) - proj.preparePixelProjectile(target, current_turf) + proj.preparePixelProjectile(target, C) proj.fire() var/turf/target_turf = get_turf(target) @@ -149,7 +147,7 @@ break if(get_dist(cam, target) > 12) continue - if(!can_shoot_to(cam, loc_target)) // Camera can hit this spot. + if(!can_shoot_to(cam, target)) // Camera can hit this spot. continue if(!chosen_camera) chosen_camera = cam @@ -166,7 +164,7 @@ var/turf/loc_chosen = get_turf(chosen_camera) var/obj/projectile/beam/laser/proj = null proj = new /obj/projectile/beam/laser(loc_chosen) - proj.preparePixelProjectile(target, loc_chosen) + proj.preparePixelProjectile(target, chosen_camera) proj.firer = caller // Fire the shot. From 4619e07600e2c1c2d902c53c56552886649fa12e Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 18:14:13 -0800 Subject: [PATCH 07/14] better comment --- code/game/objects/items/robot/ai_upgrades.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index d03847083815..a3cfd96b9fea 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -147,7 +147,7 @@ break if(get_dist(cam, target) > 12) continue - if(!can_shoot_to(cam, target)) // Camera can hit this spot. + if(!can_shoot_to(cam, target)) // Camera cannot hit this target (assuming they are not moving). continue if(!chosen_camera) chosen_camera = cam From 71defba9e71e0c918fa5b6515c2b42a549ad40d3 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 18:29:30 -0800 Subject: [PATCH 08/14] better uplink name --- code/modules/uplink/uplink_items.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index b9c4661ee47f..989fd308dfcf 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -2681,7 +2681,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) restricted_roles = list("Clown") /datum/uplink_item/role_restricted/ai_cameragun - name = "AI Camera Gun Upgrade" + name = "AI Camera Laser Gun Upgrade" desc = "A disk containing experimental and illegal software that allows an AI to temporarily override the safety features on their cameras, enabling them to shoot a laser beam out of them." item = /obj/item/cameragun_upgrade cost = 8 // Considering that you have to: subvert an AI, trust the AI not to be a traitor/unsubverted, accept that every camera is gonna get disabled later, and pay more than an emag for this... 8 is fair. From 69f32c99fe6c9019fc89eeb95a01b11694932468 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 18:30:36 -0800 Subject: [PATCH 09/14] EMP_HEAVY --- code/game/objects/items/robot/ai_upgrades.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index a3cfd96b9fea..e53f9e51541c 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -178,5 +178,5 @@ Deactivate(FALSE) to_chat(caller, span_danger("Camera overcharged.")) - chosen_camera.emp_act(EMP_LIGHT) // 90 seconds downtime -- definitely enough time to toolbox this camera (unless it is emp-proof). + chosen_camera.emp_act(EMP_HEAVY) // 90 seconds downtime -- definitely enough time to toolbox this camera (unless it is emp-proof). return TRUE From 5fb53a55b22a6d1f764e57767104b3a621b11551 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Wed, 22 Nov 2023 18:46:56 -0800 Subject: [PATCH 10/14] proper logging msg --- code/game/objects/items/robot/ai_upgrades.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index e53f9e51541c..ffa9f449aaac 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -61,8 +61,8 @@ ability.Grant(AI) to_chat(user, span_notice("You upgrade [AI]. [src] is consumed in the process.")) - log_game("[key_name(user)] has upgraded [key_name(AI)] with a [src].") - message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].") + log_game("[key_name(user)] has upgraded [key_name(AI)] with [src].") + message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with [src].") qdel(src) /// An ability that allows the user to shoot a laser beam at a target from the nearest camera. From 9faae7fb0e424c99eb413378066c848be6ad05e0 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Fri, 24 Nov 2023 02:39:21 -0800 Subject: [PATCH 11/14] no dupes + fixing other upgrades logging --- code/game/objects/items/robot/ai_upgrades.dm | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index ffa9f449aaac..3ca94ce91a0f 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -8,7 +8,6 @@ icon = 'icons/obj/module.dmi' icon_state = "datadisk3" - /obj/item/malf_upgrade/afterattack(mob/living/silicon/ai/AI, mob/user) . = ..() if(!istype(AI)) @@ -20,12 +19,11 @@ to_chat(AI, span_userdanger("[user] has upgraded you with combat software!")) to_chat(AI, span_userdanger("Your current laws and objectives remain unchanged.")) //this unlocks malf powers, but does not give the license to plasma flood AI.add_malf_picker() - log_game("[key_name(user)] has upgraded [key_name(AI)] with a [src].") - message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].") + log_game("[key_name(user)] has upgraded [key_name(AI)] with \a [src].") + message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with \a [src].") to_chat(user, span_notice("You upgrade [AI]. [src] is consumed in the process.")) qdel(src) - //Lipreading /obj/item/surveillance_upgrade name = "surveillance software upgrade" @@ -42,8 +40,8 @@ to_chat(AI, span_userdanger("[user] has upgraded you with surveillance software!")) to_chat(AI, "Via a combination of hidden microphones and lip reading software, you are able to use your cameras to listen in on conversations.") to_chat(user, span_notice("You upgrade [AI]. [src] is consumed in the process.")) - log_game("[key_name(user)] has upgraded [key_name(AI)] with a [src].") - message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with a [src].") + log_game("[key_name(user)] has upgraded [key_name(AI)] with \a [src].") + message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with \a [src].") qdel(src) /obj/item/cameragun_upgrade @@ -57,12 +55,18 @@ if(!istype(AI)) return + // No giving multiple copies. + for(var/datum/action/action in AI.actions) + if(action.type == /datum/action/innate/ai/ranged/cameragun) + to_chat(user, span_notice("[AI] has already been upgraded with \a [src].")) + return + var/datum/action/innate/ai/ranged/cameragun/ability = new ability.Grant(AI) to_chat(user, span_notice("You upgrade [AI]. [src] is consumed in the process.")) - log_game("[key_name(user)] has upgraded [key_name(AI)] with [src].") - message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with [src].") + log_game("[key_name(user)] has upgraded [key_name(AI)] with \a [src].") + message_admins("[ADMIN_LOOKUPFLW(user)] has upgraded [ADMIN_LOOKUPFLW(AI)] with \a [src].") qdel(src) /// An ability that allows the user to shoot a laser beam at a target from the nearest camera. @@ -73,7 +77,7 @@ button_icon_state = "laser" enable_text = span_notice("You prepare to overcharge a camera. Click a target for a nearby camera to shoot a laser at.") disable_text = span_notice("You dissipate the overcharged energy.") - click_action = FALSE // Even though that we are an click action, we want to use Activate() and Deactivate(). + click_action = FALSE // Even though that we are a click action, we want to use Activate() and Deactivate(). COOLDOWN_DECLARE(next_shot) var/cooldown = 10 SECONDS @@ -87,7 +91,7 @@ proj.ricochets_max = 0 proj.ricochet_chance = 0 proj.damage = 0 - proj.nodamage = TRUE + proj.nodamage = TRUE // Prevents this hitscan test projectile from detonating certain objects (e.g. welding tanks). proj.log_override = TRUE proj.hitscan = TRUE proj.pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE From 3f6dd7f9eaed138c24b475a8321ce37d27045203 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Fri, 24 Nov 2023 03:18:15 -0800 Subject: [PATCH 12/14] dont need to null it i think --- code/game/objects/items/robot/ai_upgrades.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index 3ca94ce91a0f..726b56e419ed 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -166,8 +166,7 @@ COOLDOWN_START(src, next_shot, cooldown) var/turf/loc_chosen = get_turf(chosen_camera) - var/obj/projectile/beam/laser/proj = null - proj = new /obj/projectile/beam/laser(loc_chosen) + var/obj/projectile/beam/laser/proj = new(loc_chosen) proj.preparePixelProjectile(target, chosen_camera) proj.firer = caller From b80db3f1e440719335645f93fd69011559d30fad Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Fri, 24 Nov 2023 03:29:27 -0800 Subject: [PATCH 13/14] increases pointblank from 0tile -> 1tile --- code/game/objects/items/robot/ai_upgrades.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index 726b56e419ed..85d7c9eee791 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -72,7 +72,7 @@ /// An ability that allows the user to shoot a laser beam at a target from the nearest camera. /datum/action/innate/ai/ranged/cameragun name = "Camera Laser Gun" - desc = "Shoots a laser from the nearest available camera toward a chosen destination. Only fires if the laser could reach destination." // This means if you aim at a turf and it doesn't collide, it won't fire. Beware of moving targets. + desc = "Shoots a laser from the nearest available camera toward a chosen destination if it is highly probable to reach said destination." button_icon = 'icons/obj/guns/energy.dmi' button_icon_state = "laser" enable_text = span_notice("You prepare to overcharge a camera. Click a target for a nearby camera to shoot a laser at.") @@ -146,12 +146,12 @@ var/turf/loc_camera = get_turf(cam) if(loc_target.z != loc_camera.z) continue - if(get_dist(cam, target) == 0) // Pointblank shot. + if(get_dist(cam, target) <= 1) // Pointblank shot. chosen_camera = cam break if(get_dist(cam, target) > 12) continue - if(!can_shoot_to(cam, target)) // Camera cannot hit this target (assuming they are not moving). + if(!can_shoot_to(cam, target)) // No chance to hit. continue if(!chosen_camera) chosen_camera = cam @@ -171,7 +171,7 @@ proj.firer = caller // Fire the shot. - var/pointblank = get_dist(chosen_camera, target) == 0 ? TRUE : FALSE // Same tile. + var/pointblank = get_dist(chosen_camera, target) <= 1 ? TRUE : FALSE // Same tile or right next. if(pointblank) chosen_camera.visible_message(span_danger("[chosen_camera] fires a laser point blank at [target]!")) proj.fire(direct_target = target) From 7cad3ca5667a2dbe6793761d1ce26586ff2a0960 Mon Sep 17 00:00:00 2001 From: Rune Knight Date: Fri, 24 Nov 2023 06:02:40 -0800 Subject: [PATCH 14/14] unused parameter --- code/game/objects/items/robot/ai_upgrades.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index 85d7c9eee791..f3b5b032231c 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -81,8 +81,8 @@ COOLDOWN_DECLARE(next_shot) var/cooldown = 10 SECONDS -/// Checks if it is possible for an projectile to reach a target in a straight line from a camera. -/datum/action/innate/ai/ranged/cameragun/proc/can_shoot_to(obj/machinery/camera/C, atom/target, confidence = 0) +/// Checks if it is possible for a (hitscan) projectile to reach a target in a straight line from a camera. +/datum/action/innate/ai/ranged/cameragun/proc/can_shoot_to(obj/machinery/camera/C, atom/target) var/obj/projectile/proj = new /obj/projectile proj.icon = null proj.icon_state = null @@ -91,7 +91,7 @@ proj.ricochets_max = 0 proj.ricochet_chance = 0 proj.damage = 0 - proj.nodamage = TRUE // Prevents this hitscan test projectile from detonating certain objects (e.g. welding tanks). + proj.nodamage = TRUE // Prevents this projectile from detonating certain objects (e.g. welding tanks). proj.log_override = TRUE proj.hitscan = TRUE proj.pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE