diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm
index 2f875cef364b..d3e3356d9308 100644
--- a/code/modules/projectiles/guns/smartgun.dm
+++ b/code/modules/projectiles/guns/smartgun.dm
@@ -101,6 +101,10 @@
var/recycletime = 120
var/cover_open = FALSE
+ var/lock_range = 2
+ var/aim_assist = FALSE
+ var/image/autoshot_image
+
/obj/item/weapon/gun/smartgun/Initialize(mapload, ...)
ammo_primary_def = GLOB.ammo_list[ammo_primary_def] //Gun initialize calls replace_ammo() so we need to set these first.
ammo_secondary_def = GLOB.ammo_list[ammo_secondary_def]
@@ -112,6 +116,11 @@
battery = new /obj/item/smartgun_battery(src)
muzzle_flash = "muzzle_flash_blue"
muzzle_flash_color = COLOR_MUZZLE_BLUE
+ autoshot_image = image('icons/effects/effects.dmi', null, "lock")
+ autoshot_image.layer = ABOVE_XENO_LAYER
+ autoshot_image.plane = GAME_PLANE
+ autoshot_image.appearance_flags = RESET_COLOR|RESET_ALPHA|RESET_TRANSFORM|KEEP_APART
+ autoshot_image.alpha = 190
. = ..()
if(has_cover)
desc += SPAN_INFO("\nAlt-click it to open the feed cover and allow for reloading.")
@@ -294,6 +303,29 @@
else
button.icon_state = "template"
+/datum/action/item_action/smartgun/toggle_aim_assist/New(Target, obj/item/holder)
+ . = ..()
+ name = "Toggle Aim Assist"
+
+ action_icon_state = "autofire"
+ button.name = name
+ button.overlays.Cut()
+ button.overlays += image('icons/mob/hud/actions.dmi', button, action_icon_state)
+
+/datum/action/item_action/smartgun/toggle_aim_assist/action_activate()
+ . = ..()
+ var/obj/item/weapon/gun/smartgun/smortgun = holder_item
+ smortgun.toggle_aim_assist(usr)
+
+/datum/action/item_action/smartgun/toggle_aim_assist/proc/update_icon()
+ if(!holder_item)
+ return
+ var/obj/item/weapon/gun/smartgun/smortgun = holder_item
+ if(smortgun.aim_assist)
+ button.icon_state = "template_on"
+ else
+ button.icon_state = "template"
+
/datum/action/item_action/smartgun/toggle_accuracy_improvement/New(Target, obj/item/holder)
. = ..()
name = "Toggle Accuracy Improvement"
@@ -471,6 +503,9 @@
set_gun_config_values()
/obj/item/weapon/gun/smartgun/Fire(atom/target, mob/living/user, params, reflex = 0, dual_wield)
+ if(aim_assist && !auto_fire)
+ target = get_assist_target(user, target)
+
if(!requires_battery)
return ..()
@@ -534,19 +569,54 @@
TAF.update_icon()
auto_fire()
+/obj/item/weapon/gun/smartgun/proc/toggle_aim_assist(mob/user, silent)
+ if(!silent)
+ to_chat(user, "[icon2html(src, user)] You [aim_assist ? "disable" : "enable"] \the [src]'s aim assist.")
+ balloon_alert(user, "aim assist [aim_assist? "disabled" : "enabled"]")
+ playsound(loc,'sound/machines/click.ogg', 25, 1)
+
+ aim_assist = !aim_assist
+
+ if(aim_assist)
+ enable_auto_aim(user)
+ else
+ disable_auto_aim(user)
+
+/obj/item/weapon/gun/smartgun/proc/enable_auto_aim(mob/user)
+ drain += 50
+ START_PROCESSING(SSobj, src)
+ var/datum/action/item_action/smartgun/toggle_aim_assist/aim_assist_action = locate(/datum/action/item_action/smartgun/toggle_aim_assist) in actions
+ aim_assist_action.update_icon()
+ recalculate_attachment_bonuses()
+
+/obj/item/weapon/gun/smartgun/proc/disable_auto_aim(mob/user)
+ drain -= 50
+ var/datum/action/item_action/smartgun/toggle_aim_assist/aim_assist_action = locate(/datum/action/item_action/smartgun/toggle_aim_assist) in actions
+ aim_assist_action.update_icon()
+ recalculate_attachment_bonuses()
+
+/obj/item/weapon/gun/smartgun/proc/reset_autoshot_image()
+ autoshot_image.loc = null
+ autoshot_image.pixel_x = 0
+ autoshot_image.pixel_y = 0
+
+/obj/item/weapon/gun/smartgun/proc/set_autoshot_image(mob/living/target)
+ autoshot_image.loc = target
+ autoshot_image.pixel_x = -target.pixel_x // -16 is counted by -(-16)
+ autoshot_image.pixel_y = -target.pixel_y
+
/obj/item/weapon/gun/smartgun/proc/auto_fire()
if(auto_fire)
drain += 150
- if(!motion_detector)
- START_PROCESSING(SSobj, src)
- if(!auto_fire)
+ START_PROCESSING(SSobj, src)
+ else
drain -= 150
- if(!motion_detector)
- STOP_PROCESSING(SSobj, src)
/obj/item/weapon/gun/smartgun/process()
- if(!auto_fire && !motion_detector)
+ if(!auto_fire && !motion_detector && !aim_assist)
STOP_PROCESSING(SSobj, src)
+ if(aim_assist && last_fired + 1 SECONDS <= world.time)
+ reset_autoshot_image()
if(auto_fire)
auto_prefire()
if(motion_detector)
@@ -572,6 +642,56 @@
TAF.update_icon()
auto_fire()
+/obj/item/weapon/gun/smartgun/proc/get_assist_target(mob/living/user, target)
+ if(!aim_assist)
+ return target
+
+ var/dist_unconscious = 9999
+ var/dist_conscious = 9999
+
+ var/mob/living/unconscious_target = null
+ var/mob/living/conscious_target = null
+ for(var/mob/living/targetted_mob in range(lock_range, target) & oviewers(user.get_maximum_view_range(), user))
+ if(targetted_mob.invisibility)
+ continue
+ if(HAS_TRAIT(targetted_mob, TRAIT_ABILITY_BURROWED))
+ continue
+ if(targetted_mob.is_ventcrawling)
+ continue
+ if(targetted_mob.stat == DEAD)
+ continue // No dead or non living.
+
+ if(iff_enabled && targetted_mob.get_target_lock(user.faction_group))
+ continue
+
+ var/dist = get_dist_sqrd(user, targetted_mob)
+
+ if(targetted_mob.stat == UNCONSCIOUS && dist_unconscious > dist)
+ dist_unconscious = dist
+ unconscious_target = targetted_mob
+ else if(dist_conscious > dist)
+ dist_conscious = dist
+ conscious_target = targetted_mob
+
+ if(conscious_target)
+ set_autoshot_image(conscious_target)
+ . = conscious_target
+ else if(unconscious_target)
+ set_autoshot_image(unconscious_target)
+ . = unconscious_target
+ else
+ . = target
+ reset_autoshot_image()
+
+/obj/item/weapon/gun/smartgun/wield(mob/living/user)
+ . = ..()
+ user.client.images |= autoshot_image
+
+/obj/item/weapon/gun/smartgun/unwield(mob/user)
+ . = ..()
+ user.client?.images -= autoshot_image
+ reset_autoshot_image()
+
/obj/item/weapon/gun/smartgun/proc/get_target(mob/living/user)
var/list/conscious_targets = list()
var/list/unconscious_targets = list()
@@ -674,12 +794,9 @@
/obj/item/weapon/gun/smartgun/proc/motion_detector()
if(motion_detector)
drain += 15
- if(!auto_fire)
- START_PROCESSING(SSobj, src)
- if(!motion_detector)
+ START_PROCESSING(SSobj, src)
+ else
drain -= 15
- if(!auto_fire)
- STOP_PROCESSING(SSobj, src)
//CO SMARTGUN
/obj/item/weapon/gun/smartgun/co
@@ -810,9 +927,19 @@
flags_gun_features = GUN_WY_RESTRICTED|GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY
drum_cover_overlay = FALSE
has_cover = FALSE
+ actions_types = list(
+ /datum/action/item_action/smartgun/toggle_accuracy_improvement,
+ /datum/action/item_action/smartgun/toggle_ammo_type,
+ /datum/action/item_action/smartgun/toggle_aim_assist,
+ /datum/action/item_action/smartgun/toggle_frontline_mode,
+ /datum/action/item_action/smartgun/toggle_lethal_mode,
+ /datum/action/item_action/smartgun/toggle_motion_detector,
+ /datum/action/item_action/smartgun/toggle_recoil_compensation,
+ )
/obj/item/weapon/gun/smartgun/l56a2/Initialize(mapload, ...)
. = ..()
+ toggle_aim_assist(null, TRUE)
MD.iff_signal = FACTION_PMC
/obj/item/weapon/gun/smartgun/l56a2/elite
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 1bafa0f662bd..5da80718f590 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ