diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm
index 49ef7a72855..0397b5bcdde 100644
--- a/code/__DEFINES/admin.dm
+++ b/code/__DEFINES/admin.dm
@@ -43,4 +43,21 @@
#define R_MAXPERMISSION 32768 //This holds the maximum value for a permission. It is used in iteration, so keep it updated.
-#define R_HOST 65535
\ No newline at end of file
+#define R_HOST 65535
+
+#define ADMIN_QUE(user) "(?)"
+#define ADMIN_FLW(user) "(FLW)"
+#define ADMIN_PP(user) "(PP)"
+#define ADMIN_VV(atom) "(VV)"
+#define ADMIN_SM(user) "(SM)"
+#define ADMIN_TP(user) "(TP)"
+#define ADMIN_BSA(user) "(BSA)"
+#define ADMIN_CENTCOM_REPLY(user) "(RPLY)"
+#define ADMIN_SYNDICATE_REPLY(user) "(RPLY)"
+#define ADMIN_SC(user) "(SC)"
+#define ADMIN_LOOKUP(user) "[key_name_admin(user)][ADMIN_QUE(user)]"
+#define ADMIN_LOOKUPFLW(user) "[key_name_admin(user)][ADMIN_QUE(user)] [ADMIN_FLW(user)]"
+#define ADMIN_FULLMONTY(user) "[key_name_admin(user)] [ADMIN_QUE(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_FLW(user)] [ADMIN_TP(user)]"
+#define ADMIN_JMP(src) "(JMP)"
+#define COORD(src) "[src ? "([src.x],[src.y],[src.z])" : "nonexistent location"]"
+#define ADMIN_COORDJMP(src) "[src ? "[COORD(src)] [ADMIN_JMP(src)]" : "nonexistent location"]"
\ No newline at end of file
diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm
index 94668321c60..3b370f8a945 100644
--- a/code/__HELPERS/matrices.dm
+++ b/code/__HELPERS/matrices.dm
@@ -24,3 +24,39 @@
animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above
//3 billion% intentional
+
+//Dumps the matrix data in format a-f
+/matrix/proc/tolist()
+ . = list()
+ . += a
+ . += b
+ . += c
+ . += d
+ . += e
+ . += f
+
+//Dumps the matrix data in a matrix-grid format
+/*
+ a d 0
+ b e 0
+ c f 1
+*/
+/matrix/proc/togrid()
+ . = list()
+ . += a
+ . += d
+ . += 0
+ . += b
+ . += e
+ . += 0
+ . += c
+ . += f
+ . += 1
+
+//The X pixel offset of this matrix
+/matrix/proc/get_x_shift()
+ . = c
+
+//The Y pixel offset of this matrix
+/matrix/proc/get_y_shift()
+ . = f
\ No newline at end of file
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index de091cb8584..e0d25da3ffd 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1009,6 +1009,50 @@ proc/get_mob_with_client_list()
else if(zone == "l_foot") return "left foot"
else if(zone == "r_foot") return "right foot"
else return zone
+
+/*
+
+ Gets the turf this atom's *ICON* appears to inhabit
+ It takes into account:
+ * Pixel_x/y
+ * Matrix x/y
+
+ NOTE: if your atom has non-standard bounds then this proc
+ will handle it, but:
+ * if the bounds are even, then there are an even amount of "middle" turfs, the one to the EAST, NORTH, or BOTH is picked
+ (this may seem bad, but you're atleast as close to the center of the atom as possible, better than byond's default loc being all the way off)
+ * if the bounds are odd, the true middle turf of the atom is returned
+
+*/
+
+/proc/get_turf_pixel(atom/movable/AM)
+ if(!istype(AM))
+ return
+
+ //Find AM's matrix so we can use it's X/Y pixel shifts
+ var/matrix/M = matrix(AM.transform)
+
+ var/pixel_x_offset = AM.pixel_x + M.get_x_shift()
+ var/pixel_y_offset = AM.pixel_y + M.get_y_shift()
+
+ //Irregular objects
+ if(AM.bound_height != world.icon_size || AM.bound_width != world.icon_size)
+ var/icon/AMicon = icon(AM.icon, AM.icon_state)
+ pixel_x_offset += ((AMicon.Width()/world.icon_size)-1)*(world.icon_size*0.5)
+ pixel_y_offset += ((AMicon.Height()/world.icon_size)-1)*(world.icon_size*0.5)
+ qdel(AMicon)
+
+ //DY and DX
+ var/rough_x = round(round(pixel_x_offset,world.icon_size)/world.icon_size)
+ var/rough_y = round(round(pixel_y_offset,world.icon_size)/world.icon_size)
+
+ //Find coordinates
+ var/turf/T = get_turf(AM) //use AM's turfs, as it's coords are the same as AM's AND AM's coords are lost if it is inside another atom
+ var/final_x = T.x + rough_x
+ var/final_y = T.y + rough_y
+
+ if(final_x || final_y)
+ return locate(final_x, final_y, T.z)
//Finds the distance between two atoms, in pixels
//centered = 0 counts from turf edge to edge
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index cdce17f6277..f3ae2fdea48 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -31,9 +31,15 @@
return
next_click = world.time + 1
-
if(control_disabled || stat)
return
+
+ var/turf/pixel_turf = get_turf_pixel(A)
+ if(pixel_turf && !cameranet.checkTurfVis(pixel_turf))
+ log_admin("[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(A)])")
+ message_admins("[key_name_admin(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([ADMIN_COORDJMP(A)]))")
+ send2irc_adminless_only("NOCHEAT", "[key_name(src)] might be running a modified client! (failed checkTurfVis on AI click of [A]([COORD(A)]))")
+ return
var/list/modifiers = params2list(params)
if(modifiers["shift"] && modifiers["ctrl"])