diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 4c0eeccf1d..de1dfdbf67 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -44,8 +44,8 @@
else if(hitsound)
playsound(loc, hitsound, get_clamped_volume(), 1, -1)
- user.lastattacked = M
- M.lastattacker = user
+ M.lastattacker = user.real_name
+ M.lastattackerckey = user.ckey
user.do_attack_animation(M)
M.attacked_by(src, user)
diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm
index 56238d5b85..fe7cf33070 100644
--- a/code/controllers/subsystem/blackbox.dm
+++ b/code/controllers/subsystem/blackbox.dm
@@ -191,12 +191,8 @@ SUBSYSTEM_DEF(blackbox)
var/sqljob = sanitizeSQL(L.mind.assigned_role)
var/sqlspecial = sanitizeSQL(L.mind.special_role)
var/sqlpod = sanitizeSQL(placeofdeath.name)
- var/laname
- var/lakey
- if(L.lastattacker && ismob(L.lastattacker))
- var/mob/LA = L.lastattacker
- laname = sanitizeSQL(LA.real_name)
- lakey = sanitizeSQL(LA.key)
+ var/laname = sanitizeSQL(L.lastattacker)
+ var/lakey = sanitizeSQL(L.lastattackerckey)
var/sqlbrute = sanitizeSQL(L.getBruteLoss())
var/sqlfire = sanitizeSQL(L.getFireLoss())
var/sqlbrain = sanitizeSQL(L.getBrainLoss())
diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
index e1c2f43c0f..3a7f99bc8a 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm
@@ -417,8 +417,9 @@ Congratulations! You are now trained for invasive xenobiology research!"}
toggle(user)
/obj/item/abductor_baton/proc/StunAttack(mob/living/L,mob/living/user)
- user.lastattacked = L
- L.lastattacker = user
+
+ L.lastattacker = user.real_name
+ L.lastattackerckey = user.ckey
L.Knockdown(140)
L.apply_effect(STUTTER, 7)
diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm
index ef2af5381b..92d00d9e2d 100644
--- a/code/game/objects/items/stunbaton.dm
+++ b/code/game/objects/items/stunbaton.dm
@@ -1,202 +1,202 @@
-/obj/item/melee/baton
- name = "stunbaton"
- desc = "A stun baton for incapacitating people with."
- icon_state = "stunbaton"
- item_state = "baton"
- lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
- slot_flags = SLOT_BELT
- force = 10
- throwforce = 7
- w_class = WEIGHT_CLASS_NORMAL
- origin_tech = "combat=2"
- attack_verb = list("beaten")
- armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 50, bio = 0, rad = 0, fire = 80, acid = 80)
-
- var/stunforce = 140
- var/status = 0
- var/obj/item/stock_parts/cell/high/cell
- var/hitcost = 1000
- var/throw_hit_chance = 35
-
-/obj/item/melee/baton/get_cell()
- return cell
-
-/obj/item/melee/baton/suicide_act(mob/user)
- user.visible_message("[user] is putting the live [name] in [user.p_their()] mouth! It looks like [user.p_theyre()] trying to commit suicide!")
- return (FIRELOSS)
-
-/obj/item/melee/baton/Initialize()
- . = ..()
- update_icon()
-
-/obj/item/melee/baton/throw_impact(atom/hit_atom)
- ..()
- //Only mob/living types have stun handling
- if(status && prob(throw_hit_chance) && iscarbon(hit_atom))
- baton_stun(hit_atom)
-
-/obj/item/melee/baton/loaded/Initialize() //this one starts with a cell pre-installed.
- cell = new(src)
- update_icon()
- . = ..()
-
-/obj/item/melee/baton/proc/deductcharge(chrgdeductamt)
- if(cell)
- //Note this value returned is significant, as it will determine
- //if a stun is applied or not
- . = cell.use(chrgdeductamt)
- if(status && cell.charge < hitcost)
- //we're below minimum, turn off
- status = 0
- update_icon()
- playsound(loc, "sparks", 75, 1, -1)
-
-
-/obj/item/melee/baton/update_icon()
- if(status)
- icon_state = "[initial(name)]_active"
- else if(!cell)
- icon_state = "[initial(name)]_nocell"
- else
- icon_state = "[initial(name)]"
-
-/obj/item/melee/baton/examine(mob/user)
- ..()
- if(cell)
- to_chat(user, "The baton is [round(cell.percent())]% charged.")
- else
- to_chat(user, "The baton does not have a power source installed.")
-
-/obj/item/melee/baton/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/stock_parts/cell))
- var/obj/item/stock_parts/cell/C = W
- if(cell)
- to_chat(user, "[src] already has a cell.")
- else
- if(C.maxcharge < hitcost)
- to_chat(user, "[src] requires a higher capacity cell.")
- return
- if(!user.transferItemToLoc(W, src))
- return
- cell = W
- to_chat(user, "You install a cell in [src].")
- update_icon()
-
- else if(istype(W, /obj/item/screwdriver))
- if(cell)
- cell.update_icon()
- cell.forceMove(get_turf(src))
- cell = null
- to_chat(user, "You remove the cell from [src].")
- status = 0
- update_icon()
- else
- return ..()
-
-/obj/item/melee/baton/attack_self(mob/user)
- if(cell && cell.charge > hitcost)
- status = !status
- to_chat(user, "[src] is now [status ? "on" : "off"].")
- playsound(loc, "sparks", 75, 1, -1)
- else
- status = 0
- if(!cell)
- to_chat(user, "[src] does not have a power source!")
- else
- to_chat(user, "[src] is out of charge.")
- update_icon()
- add_fingerprint(user)
-
-/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user)
- if(status && user.disabilities & CLUMSY && prob(50))
- user.visible_message("[user] accidentally hits themself with [src]!", \
- "You accidentally hit yourself with [src]!")
- user.Knockdown(stunforce*3)
- deductcharge(hitcost)
- return
-
- if(iscyborg(M))
- ..()
- return
-
-
- if(ishuman(M))
- var/mob/living/carbon/human/L = M
- if(check_martial_counter(L, user))
- return
-
- if(user.a_intent != INTENT_HARM)
- if(status)
- if(baton_stun(M, user))
- user.do_attack_animation(M)
- return
- else
- M.visible_message("[user] has prodded [M] with [src]. Luckily it was off.", \
- "[user] has prodded you with [src]. Luckily it was off")
- else
- if(status)
- baton_stun(M, user)
- ..()
-
-
-/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user)
- if(ishuman(L))
- var/mob/living/carbon/human/H = L
- if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that
- playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
- return 0
- if(iscyborg(loc))
- var/mob/living/silicon/robot/R = loc
- if(!R || !R.cell || !R.cell.use(hitcost))
- return 0
- else
- if(!deductcharge(hitcost))
- return 0
-
- L.Knockdown(stunforce)
- L.apply_effect(STUTTER, stunforce)
- if(user)
- user.lastattacked = L
- L.lastattacker = user
- L.visible_message("[user] has stunned [L] with [src]!", \
- "[user] has stunned you with [src]!")
- add_logs(user, L, "stunned")
-
- playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
-
- if(ishuman(L))
- var/mob/living/carbon/human/H = L
- H.forcesay(GLOB.hit_appends)
-
-
- return 1
-
-/obj/item/melee/baton/emp_act(severity)
- deductcharge(1000 / severity)
- ..()
-
-//Makeshift stun baton. Replacement for stun gloves.
-/obj/item/melee/baton/cattleprod
- name = "stunprod"
- desc = "An improvised stun baton."
- icon_state = "stunprod_nocell"
- item_state = "prod"
- lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
- w_class = WEIGHT_CLASS_BULKY
- force = 3
- throwforce = 5
- stunforce = 100
- hitcost = 2000
- throw_hit_chance = 10
- slot_flags = SLOT_BACK
- var/obj/item/device/assembly/igniter/sparkler = 0
-
-/obj/item/melee/baton/cattleprod/Initialize()
- . = ..()
- sparkler = new (src)
-
-/obj/item/melee/baton/cattleprod/baton_stun()
- if(sparkler.activate())
- ..()
+/obj/item/melee/baton
+ name = "stunbaton"
+ desc = "A stun baton for incapacitating people with."
+ icon_state = "stunbaton"
+ item_state = "baton"
+ lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
+ slot_flags = SLOT_BELT
+ force = 10
+ throwforce = 7
+ w_class = WEIGHT_CLASS_NORMAL
+ origin_tech = "combat=2"
+ attack_verb = list("beaten")
+ armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 50, bio = 0, rad = 0, fire = 80, acid = 80)
+
+ var/stunforce = 140
+ var/status = 0
+ var/obj/item/stock_parts/cell/high/cell
+ var/hitcost = 1000
+ var/throw_hit_chance = 35
+
+/obj/item/melee/baton/get_cell()
+ return cell
+
+/obj/item/melee/baton/suicide_act(mob/user)
+ user.visible_message("[user] is putting the live [name] in [user.p_their()] mouth! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (FIRELOSS)
+
+/obj/item/melee/baton/Initialize()
+ . = ..()
+ update_icon()
+
+/obj/item/melee/baton/throw_impact(atom/hit_atom)
+ ..()
+ //Only mob/living types have stun handling
+ if(status && prob(throw_hit_chance) && iscarbon(hit_atom))
+ baton_stun(hit_atom)
+
+/obj/item/melee/baton/loaded/Initialize() //this one starts with a cell pre-installed.
+ cell = new(src)
+ update_icon()
+ . = ..()
+
+/obj/item/melee/baton/proc/deductcharge(chrgdeductamt)
+ if(cell)
+ //Note this value returned is significant, as it will determine
+ //if a stun is applied or not
+ . = cell.use(chrgdeductamt)
+ if(status && cell.charge < hitcost)
+ //we're below minimum, turn off
+ status = 0
+ update_icon()
+ playsound(loc, "sparks", 75, 1, -1)
+
+
+/obj/item/melee/baton/update_icon()
+ if(status)
+ icon_state = "[initial(name)]_active"
+ else if(!cell)
+ icon_state = "[initial(name)]_nocell"
+ else
+ icon_state = "[initial(name)]"
+
+/obj/item/melee/baton/examine(mob/user)
+ ..()
+ if(cell)
+ to_chat(user, "The baton is [round(cell.percent())]% charged.")
+ else
+ to_chat(user, "The baton does not have a power source installed.")
+
+/obj/item/melee/baton/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/stock_parts/cell))
+ var/obj/item/stock_parts/cell/C = W
+ if(cell)
+ to_chat(user, "[src] already has a cell.")
+ else
+ if(C.maxcharge < hitcost)
+ to_chat(user, "[src] requires a higher capacity cell.")
+ return
+ if(!user.transferItemToLoc(W, src))
+ return
+ cell = W
+ to_chat(user, "You install a cell in [src].")
+ update_icon()
+
+ else if(istype(W, /obj/item/screwdriver))
+ if(cell)
+ cell.update_icon()
+ cell.forceMove(get_turf(src))
+ cell = null
+ to_chat(user, "You remove the cell from [src].")
+ status = 0
+ update_icon()
+ else
+ return ..()
+
+/obj/item/melee/baton/attack_self(mob/user)
+ if(cell && cell.charge > hitcost)
+ status = !status
+ to_chat(user, "[src] is now [status ? "on" : "off"].")
+ playsound(loc, "sparks", 75, 1, -1)
+ else
+ status = 0
+ if(!cell)
+ to_chat(user, "[src] does not have a power source!")
+ else
+ to_chat(user, "[src] is out of charge.")
+ update_icon()
+ add_fingerprint(user)
+
+/obj/item/melee/baton/attack(mob/M, mob/living/carbon/human/user)
+ if(status && user.disabilities & CLUMSY && prob(50))
+ user.visible_message("[user] accidentally hits themself with [src]!", \
+ "You accidentally hit yourself with [src]!")
+ user.Knockdown(stunforce*3)
+ deductcharge(hitcost)
+ return
+
+ if(iscyborg(M))
+ ..()
+ return
+
+
+ if(ishuman(M))
+ var/mob/living/carbon/human/L = M
+ if(check_martial_counter(L, user))
+ return
+
+ if(user.a_intent != INTENT_HARM)
+ if(status)
+ if(baton_stun(M, user))
+ user.do_attack_animation(M)
+ return
+ else
+ M.visible_message("[user] has prodded [M] with [src]. Luckily it was off.", \
+ "[user] has prodded you with [src]. Luckily it was off")
+ else
+ if(status)
+ baton_stun(M, user)
+ ..()
+
+
+/obj/item/melee/baton/proc/baton_stun(mob/living/L, mob/user)
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ if(H.check_shields(src, 0, "[user]'s [name]", MELEE_ATTACK)) //No message; check_shields() handles that
+ playsound(L, 'sound/weapons/genhit.ogg', 50, 1)
+ return 0
+ if(iscyborg(loc))
+ var/mob/living/silicon/robot/R = loc
+ if(!R || !R.cell || !R.cell.use(hitcost))
+ return 0
+ else
+ if(!deductcharge(hitcost))
+ return 0
+
+ L.Knockdown(stunforce)
+ L.apply_effect(STUTTER, stunforce)
+ if(user)
+ L.lastattacker = user.real_name
+ L.lastattackerckey = user.ckey
+ L.visible_message("[user] has stunned [L] with [src]!", \
+ "[user] has stunned you with [src]!")
+ add_logs(user, L, "stunned")
+
+ playsound(loc, 'sound/weapons/egloves.ogg', 50, 1, -1)
+
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ H.forcesay(GLOB.hit_appends)
+
+
+ return 1
+
+/obj/item/melee/baton/emp_act(severity)
+ deductcharge(1000 / severity)
+ ..()
+
+//Makeshift stun baton. Replacement for stun gloves.
+/obj/item/melee/baton/cattleprod
+ name = "stunprod"
+ desc = "An improvised stun baton."
+ icon_state = "stunprod_nocell"
+ item_state = "prod"
+ lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/melee_righthand.dmi'
+ w_class = WEIGHT_CLASS_BULKY
+ force = 3
+ throwforce = 5
+ stunforce = 100
+ hitcost = 2000
+ throw_hit_chance = 10
+ slot_flags = SLOT_BACK
+ var/obj/item/device/assembly/igniter/sparkler = 0
+
+/obj/item/melee/baton/cattleprod/Initialize()
+ . = ..()
+ sparkler = new (src)
+
+/obj/item/melee/baton/cattleprod/baton_stun()
+ if(sparkler.activate())
+ ..()
diff --git a/code/game/objects/structures/manned_turret.dm b/code/game/objects/structures/manned_turret.dm
index 70176ede53..669abb792a 100644
--- a/code/game/objects/structures/manned_turret.dm
+++ b/code/game/objects/structures/manned_turret.dm
@@ -201,8 +201,8 @@
O.attacked_by(src, user)
/obj/item/gun_control/attack(mob/living/M, mob/living/user)
- user.lastattacked = M
- M.lastattacker = user
+ M.lastattacker = user.real_name
+ M.lastattackerckey = user.ckey
M.attacked_by(src, user)
add_fingerprint(user)
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 6becdb3ddd..6d9630cb56 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -27,8 +27,9 @@
var/damageoverlaytemp = 0
var/computer_id = null
var/lastattacker = null
- var/lastattacked = null
- var/list/logging = list(INDIVIDUAL_ATTACK_LOG, INDIVIDUAL_SAY_LOG, INDIVIDUAL_EMOTE_LOG, INDIVIDUAL_OOC_LOG, INDIVIDUAL_LOOC_LOG)
+ var/lastattackerckey = null
+ var/list/logging = list(INDIVIDUAL_ATTACK_LOG, INDIVIDUAL_SAY_LOG, INDIVIDUAL_EMOTE_LOG, INDIVIDUAL_OOC_LOG)
+
var/obj/machinery/machine = null
var/other_mobs = null
var/disabilities = 0 //Carbon