diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm
new file mode 100644
index 00000000000..c02737400ba
--- /dev/null
+++ b/code/_onclick/adjacent.dm
@@ -0,0 +1,124 @@
+/*
+ Adjacency proc for determining touch range
+
+ This is mostly to determine if a user can enter a square for the purposes of touching something.
+ Examples include reaching a square diagonally or reaching something on the other side of a glass window.
+
+ This is calculated by looking for border items, or in the case of clicking diagonally from yourself, dense items.
+ This proc will NOT notice if you are trying to attack a window on the other side of a dense object in its turf. There is a window helper for that.
+
+ Note that in all cases the neighbor is handled simply; this is usually the user's mob, in which case it is up to you
+ to check that the mob is not inside of something
+*/
+/atom/proc/Adjacent(var/atom/neighbor) // basic inheritance, unused
+ return 0
+
+// Not a sane use of the function and (for now) indicative of an error elsewhere
+/area/Adjacent(var/atom/neighbor)
+ CRASH("Call to /area/Adjacent(), unimplemented proc")
+
+
+/*
+ Adjacency (to turf):
+ * If you are in the same turf, always true
+ * If you are vertically/horizontally adjacent, ensure there are no border objects
+ * If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square.
+ * Passing through in this case ignores anything with the throwpass flag, such as tables, racks, and morgue trays.
+*/
+/turf/Adjacent(var/atom/neighbor, var/atom/target = null)
+ var/turf/T0 = get_turf(neighbor)
+ if(T0 == src)
+ return 1
+ if(get_dist(src,T0) > 1)
+ return 0
+
+ if(T0.x == x || T0.y == y)
+ // Check for border blockages
+ return T0.ClickCross(get_dir(T0,src), border_only = 1) && src.ClickCross(get_dir(src,T0), border_only = 1, target_atom = target)
+
+ // Not orthagonal
+ var/in_dir = get_dir(neighbor,src) // eg. northwest (1+8)
+ var/d1 = in_dir&(in_dir-1) // eg west (1+8)&(8) = 8
+ var/d2 = in_dir - d1 // eg north (1+8) - 8 = 1
+
+ for(var/d in list(d1,d2))
+ if(!T0.ClickCross(d, border_only = 1))
+ continue // could not leave T0 in that direction
+
+ var/turf/T1 = get_step(T0,d)
+ if(!T1 || T1.density || !T1.ClickCross(get_dir(T1,T0) & get_dir(T1,src), border_only = 0))
+ continue // couldn't enter or couldn't leave T1
+
+ if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target))
+ continue // could not enter src
+
+ return 1 // we don't care about our own density
+ return 0
+
+/*
+ Adjacency (to anything else):
+ * Must be on a turf
+ * In the case of a multiple-tile object, all valid locations are checked for adjacency.
+
+ Note: Multiple-tile objects are created when the bound_width and bound_height are creater than the tile size.
+ This is not used in stock /tg/station currently.
+*/
+/atom/movable/Adjacent(var/atom/neighbor)
+ if(neighbor == loc) return 1
+ if(!isturf(loc)) return 0
+ for(var/turf/T in locs)
+ if(isnull(T)) continue
+ if(T.Adjacent(neighbor,src)) return 1
+ return 0
+
+// This is necessary for storage items not on your person.
+/obj/item/Adjacent(var/atom/neighbor, var/recurse = 1)
+ if(neighbor == loc) return 1
+ if(istype(loc,/obj/item))
+ if(recurse > 0)
+ return loc.Adjacent(neighbor,recurse - 1)
+ return 0
+ return ..()
+/*
+ Special case: This allows you to reach a door when it is visally on top of,
+ but technically behind, a fire door
+
+ You could try to rewrite this to be faster, but I'm not sure anything would be.
+ This can be safely removed if border firedoors are ever moved to be on top of doors
+ so they can be interacted with without opening the door.
+*/
+/obj/machinery/door/Adjacent(var/atom/neighbor)
+ var/obj/machinery/door/firedoor/border_only/BOD = locate() in loc
+ if(BOD)
+ BOD.throwpass = 1 // allow click to pass
+ . = ..()
+ BOD.throwpass = 0
+ return .
+ return ..()
+
+
+/*
+ This checks if you there is uninterrupted airspace between that turf and this one.
+ This is defined as any dense ON_BORDER object, or any dense object without throwpass.
+ The border_only flag allows you to not objects (for source and destination squares)
+*/
+/turf/proc/ClickCross(var/target_dir, var/border_only, var/target_atom = null)
+ for(var/obj/O in src)
+ if( !O.density || O == target_atom || O.throwpass) continue // throwpass is used for anything you can click through
+
+ if( O.flags&ON_BORDER) // windows have throwpass but are on border, check them first
+ if( O.dir & target_dir || O.dir&(O.dir-1) ) // full tile windows are just diagonals mechanically
+ return 0
+
+ else if( !border_only ) // dense, not on border, cannot pass over
+ return 0
+ return 1
+/*
+ Aside: throwpass does not do what I thought it did originally, and is only used for checking whether or not
+ a thrown object should stop after already successfully entering a square. Currently the throw code involved
+ only seems to affect hitting mobs, because the checks performed against objects are already performed when
+ entering or leaving the square. Since throwpass isn't used on mobs, but only on objects, it is effectively
+ useless. Throwpass may later need to be removed and replaced with a passcheck (bitfield on movable atom passflags).
+
+ Since I don't want to complicate the click code rework by messing with unrelated systems it won't be changed here.
+*/
\ No newline at end of file
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
new file mode 100644
index 00000000000..cb840a1d90e
--- /dev/null
+++ b/code/_onclick/ai.dm
@@ -0,0 +1,125 @@
+/*
+ AI ClickOn()
+
+ Note currently ai restrained() returns 0 in all cases,
+ therefore restrained code has been removed
+
+ The AI can double click to move the camera (this was already true but is cleaner),
+ or double click a mob to track them.
+
+ Note that AI have no need for the adjacency proc, and so this proc is a lot cleaner.
+*/
+/mob/living/silicon/ai/DblClickOn(var/atom/A, params)
+ if(client.buildmode) // comes after object.Click to allow buildmode gui objects to be clicked
+ build_click(src, client.buildmode, params, A)
+ return
+
+ if(control_disabled || stat) return
+ next_move = world.time + 9
+
+ if(ismob(A))
+ ai_actual_track(A)
+ else
+ A.move_camera_by_click()
+
+
+/mob/living/silicon/ai/ClickOn(var/atom/A, params)
+ if(world.time <= next_click)
+ return
+ next_click = world.time + 1
+
+ if(client.buildmode) // comes after object.Click to allow buildmode gui objects to be clicked
+ build_click(src, client.buildmode, params, A)
+ return
+
+ var/list/modifiers = params2list(params)
+ if(modifiers["middle"])
+ MiddleClickOn(A)
+ return
+ if(modifiers["shift"])
+ ShiftClickOn(A)
+ return
+ if(modifiers["alt"]) // alt and alt-gr (rightalt)
+ AltClickOn(A)
+ return
+ if(modifiers["ctrl"])
+ CtrlClickOn(A)
+ return
+
+ if(control_disabled || stat || world.time <= next_move) return
+ next_move = world.time + 9
+
+ /*
+ AI restrained() currently does nothing
+ if(restrained())
+ RestrainedClickOn(A)
+ else
+ */
+ A.attack_ai(src)
+
+/*
+ AI has no need for the UnarmedAttack() and RangedAttack() procs,
+ because the AI code is not generic; attack_ai() is used instead.
+ The below is only really for safety, or you can alter the way
+ it functions and re-insert it above.
+*/
+/mob/living/silicon/ai/UnarmedAttack(atom/A)
+ A.attack_ai(src)
+/mob/living/silicon/ai/RangedAttack(atom/A)
+ A.attack_ai(src)
+
+/atom/proc/attack_ai(mob/user as mob)
+ return
+
+/*
+ Since the AI handles shift, ctrl, and alt-click differently
+ than anything else in the game, atoms have separate procs
+ for AI shift, ctrl, and alt clicking.
+*/
+/mob/living/silicon/ai/ShiftClickOn(var/atom/A)
+ A.AIShiftClick(src)
+/mob/living/silicon/ai/CtrlClickOn(var/atom/A)
+ A.AICtrlClick(src)
+/mob/living/silicon/ai/AltClickOn(var/atom/A)
+ A.AIAltClick(src)
+
+/*
+ The following criminally helpful code is just the previous code cleaned up;
+ I have no idea why it was in atoms.dm instead of respective files.
+*/
+
+/atom/proc/AIShiftClick()
+ return
+
+/obj/machinery/door/airlock/AIShiftClick() // Opens and closes doors!
+ if(density)
+ Topic("aiEnable=7", list("aiEnable"="7"), 1) // 1 meaning no window (consistency!)
+ else
+ Topic("aiDisable=7", list("aiDisable"="7"), 1)
+ return
+
+
+/atom/proc/AICtrlClick()
+ return
+
+/obj/machinery/door/airlock/AICtrlClick() // Bolts doors
+ if(locked)
+ Topic("aiEnable=4", list("aiEnable"="4"), 1)// 1 meaning no window (consistency!)
+ else
+ Topic("aiDisable=4", list("aiDisable"="4"), 1)
+
+/obj/machinery/power/apc/AICtrlClick() // turns off APCs.
+ Topic("breaker=1", list("breaker"="1"), 0) // 0 meaning no window (consistency! wait...)
+
+
+/atom/proc/AIAltClick()
+ return
+
+/obj/machinery/door/airlock/AIAltClick() // Eletrifies doors.
+ if(!secondsElectrified)
+ // permenant shock
+ Topic("aiEnable=6", list("aiEnable"="6"), 1) // 1 meaning no window (consistency!)
+ else
+ // disable/6 is not in Topic; disable/5 disables both temporary and permenant shock
+ Topic("aiDisable=5", list("aiDisable"="5"), 1)
+ return
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
new file mode 100644
index 00000000000..5ece365899c
--- /dev/null
+++ b/code/_onclick/click.dm
@@ -0,0 +1,302 @@
+/*
+ Click code cleanup
+ ~Sayu
+*/
+
+// 1 decisecond click delay (above and beyond mob/next_move)
+/mob/var/next_click = 0
+
+/*
+ Before anything else, defer these calls to a per-mobtype handler. This allows us to
+ remove istype() spaghetti code, but requires the addition of other handler procs to simplify it.
+
+ Alternately, you could hardcode every mob's variation in a flat ClickOn() proc; however,
+ that's a lot of code duplication and is hard to maintain.
+
+ Note that this proc can be overridden, and is in the case of screen objects.
+*/
+/atom/Click(location,control,params)
+ usr.ClickOn(src, params)
+/atom/DblClick(location,control,params)
+ usr.DblClickOn(src,params)
+
+/*
+ Standard mob ClickOn()
+ Handles exceptions: Buildmode, middle click, modified clicks, mech actions
+
+ After that, mostly just check your state, check whether you're holding an item,
+ check whether you're adjacent to the target, then pass off the click to whoever
+ is recieving it.
+ The most common are:
+ * mob/UnarmedAttack(atom,adjacent) - used here only when adjacent, with no item in hand; in the case of humans, checks gloves
+ * atom/attackby(item,user) - used only when adjacent
+ * item/afterattack(atom,user,adjacent,params) - used both ranged and adjacent
+ * mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed
+*/
+/mob/proc/ClickOn( var/atom/A, var/params )
+ if(world.time <= next_click)
+ return
+ next_click = world.time + 1
+
+ if(client.buildmode)
+ build_click(src, client.buildmode, params, A)
+ return
+
+ var/list/modifiers = params2list(params)
+ if(modifiers["middle"])
+ MiddleClickOn(A)
+ return
+ if(modifiers["shift"])
+ ShiftClickOn(A)
+ return
+ if(modifiers["alt"]) // alt and alt-gr (rightalt)
+ AltClickOn(A)
+ return
+ if(modifiers["ctrl"])
+ CtrlClickOn(A)
+ return
+
+ if(stat || paralysis || stunned || weakened)
+ return
+
+ face_atom(A) // change direction to face what you clicked on
+
+ if(next_move > world.time) // in the year 2000...
+ return
+
+ if(istype(loc,/obj/mecha))
+ var/obj/mecha/M = loc
+ return M.click_action(A,src)
+
+ if(restrained())
+ RestrainedClickOn(A)
+ return
+
+ if(in_throw_mode)
+ throw_item(A)
+ return
+
+ var/obj/item/W = get_active_hand()
+
+ if(W == A)
+ next_move = world.time + 6
+ if(W.flags&USEDELAY)
+ next_move += 5
+ W.attack_self(src)
+ if(hand)
+ update_inv_l_hand(0)
+ else
+ update_inv_r_hand(0)
+
+ return
+
+ // operate two levels deep here (item in backpack in src; NOT item in box in backpack in src)
+ if(A == loc || (A in loc) || (A in contents) || (A.loc in contents))
+
+ // faster access to objects already on you
+ if(A in contents)
+ next_move = world.time + 6 // on your person
+ else
+ next_move = world.time + 8 // in a box/bag or in your square
+
+ // No adjacency needed
+ if(W)
+ if(W.flags&USEDELAY)
+ next_move += 5
+
+ var/resolved = A.attackby(W,src)
+ if(!resolved && A && W)
+ W.afterattack(A,src,1,params) // 1 indicates adjacency
+ else
+ UnarmedAttack(A)
+ return
+
+ if(!isturf(loc)) // This is going to stop you from telekinesing from inside a closet, but I don't shed many tears for that
+ return
+
+ // Allows you to click on a box's contents, if that box is on the ground, but no deeper than that
+ if(isturf(A) || isturf(A.loc) || (A.loc && isturf(A.loc.loc)))
+ next_move = world.time + 10
+
+ if(A.Adjacent(src)) // see adjacent.dm
+ if(W)
+ if(W.flags&USEDELAY)
+ next_move += 5
+
+ // Return 1 in attackby() to prevent afterattack() effects (when safely moving items for example)
+ var/resolved = A.attackby(W,src)
+ if(!resolved && A && W)
+ W.afterattack(A,src,1,params) // 1: clicking something Adjacent
+ else
+ UnarmedAttack(A, 1)
+ return
+ else // non-adjacent click
+ if(W)
+ W.afterattack(A,src,0,params) // 0: not Adjacent
+ else
+ RangedAttack(A, params)
+
+ return
+
+// Default behavior: ignore double clicks, consider them normal clicks instead
+/mob/proc/DblClickOn(var/atom/A, var/params)
+ ClickOn(A,params)
+
+
+/*
+ Translates into attack_hand, etc.
+
+ Note: proximity_flag here is used to distinguish between normal usage (flag=1),
+ and usage when clicking on things telekinetically (flag=0). This proc will
+ not be called at ranged except with telekinesis.
+
+ proximity_flag is not currently passed to attack_hand, and is instead used
+ in human click code to allow glove touches only at melee range.
+*/
+/mob/proc/UnarmedAttack(var/atom/A, var/proximity_flag)
+ return
+
+/*
+ Ranged unarmed attack:
+
+ This currently is just a default for all mobs, involving
+ laser eyes and telekinesis. You could easily add exceptions
+ for things like ranged glove touches, spitting alien acid/neurotoxin,
+ animals lunging, etc.
+*/
+/mob/proc/RangedAttack(var/atom/A, var/params)
+ if(!mutations.len) return
+ if((LASER in mutations) && a_intent == "harm")
+ LaserEyes(A) // moved into a proc below
+ else if(TK in mutations)
+ switch(get_dist(src,A))
+ if(0)
+ ;
+ if(1 to 5) // not adjacent may mean blocked by window
+ next_move += 2
+ if(5 to 7)
+ next_move += 5
+ if(8 to tk_maxrange)
+ next_move += 10
+ else
+ return
+ A.attack_tk(src)
+/*
+ Restrained ClickOn
+
+ Used when you are handcuffed and click things.
+ Not currently used by anything but could easily be.
+*/
+/mob/proc/RestrainedClickOn(var/atom/A)
+ return
+
+/*
+ Middle click
+ Only used for swapping hands
+*/
+/mob/proc/MiddleClickOn(var/atom/A)
+ return
+/mob/living/carbon/MiddleClickOn(var/atom/A)
+ swap_hand()
+
+// In case of use break glass
+/*
+/atom/proc/MiddleClick(var/mob/M as mob)
+ return
+*/
+
+/*
+ Shift click
+ For most mobs, examine.
+ This is overridden in ai.dm
+*/
+/mob/proc/ShiftClickOn(var/atom/A)
+ A.ShiftClick(src)
+ return
+/atom/proc/ShiftClick(var/mob/user)
+ if(user.client && user.client.eye == user)
+ examine()
+ user.face_atom(src)
+ return
+
+/*
+ Ctrl click
+ For most objects, pull
+*/
+/mob/proc/CtrlClickOn(var/atom/A)
+ A.CtrlClick(src)
+ return
+/atom/proc/CtrlClick(var/mob/user)
+ return
+
+/atom/movable/CtrlClick(var/mob/user)
+ if(Adjacent(user))
+ user.start_pulling(src)
+
+/*
+ Alt click
+ Unused except for AI
+*/
+/mob/proc/AltClickOn(var/atom/A)
+ A.AltClick(src)
+ return
+
+/atom/proc/AltClick(var/mob/user)
+ var/turf/T = get_turf(src)
+ if(T && T.Adjacent(user))
+ if(user.listed_turf == T)
+ user.listed_turf = null
+ else
+ user.listed_turf = T
+ user.client.statpanel = T.name
+ return
+
+/*
+ Misc helpers
+
+ Laser Eyes: as the name implies, handles this since nothing else does currently
+ face_atom: turns the mob towards what you clicked on
+*/
+/mob/proc/LaserEyes(atom/A)
+ return
+
+/mob/living/LaserEyes(atom/A)
+ next_move = world.time + 6
+ var/turf/T = get_turf(src)
+ var/turf/U = get_turf(A)
+
+ var/obj/item/projectile/beam/LE = new /obj/item/projectile/beam( loc )
+ LE.icon = 'icons/effects/genetics.dmi'
+ LE.icon_state = "eyelasers"
+ playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
+
+ LE.firer = src
+ LE.def_zone = get_organ_target()
+ LE.original = A
+ LE.current = T
+ LE.yo = U.y - T.y
+ LE.xo = U.x - T.x
+ spawn( 1 )
+ LE.process()
+
+/mob/living/carbon/human/LaserEyes()
+ if(nutrition>0)
+ ..()
+ nutrition = max(nutrition - rand(1,5),0)
+ handle_regular_hud_updates()
+ else
+ src << "\red You're out of energy! You need food!"
+
+// Simple helper to face what you clicked on, in case it should be needed in more than one place
+/mob/proc/face_atom(var/atom/A)
+ if( buckled || !A || !x || !y || !A.x || !A.y ) return
+ var/dx = A.x - x
+ var/dy = A.y - y
+ if(!dx && !dy) return
+
+ if(abs(dx) < abs(dy))
+ if(dy > 0) usr.dir = NORTH
+ else usr.dir = SOUTH
+ else
+ if(dx > 0) usr.dir = EAST
+ else usr.dir = WEST
\ No newline at end of file
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
new file mode 100644
index 00000000000..640a09d045f
--- /dev/null
+++ b/code/_onclick/cyborg.dm
@@ -0,0 +1,118 @@
+/*
+ Cyborg ClickOn()
+
+ Cyborgs have no range restriction on attack_robot(), because it is basically an AI click.
+ However, they do have a range restriction on item use, so they cannot do without the
+ adjacency code.
+*/
+
+/mob/living/silicon/robot/ClickOn(var/atom/A, var/params)
+ if(world.time <= next_click)
+ return
+ next_click = world.time + 1
+
+ if(client.buildmode) // comes after object.Click to allow buildmode gui objects to be clicked
+ build_click(src, client.buildmode, params, A)
+ return
+
+ var/list/modifiers = params2list(params)
+ if(modifiers["middle"])
+ MiddleClickOn(A)
+ return
+ if(modifiers["shift"])
+ ShiftClickOn(A)
+ return
+ if(modifiers["alt"]) // alt and alt-gr (rightalt)
+ AltClickOn(A)
+ return
+ if(modifiers["ctrl"])
+ CtrlClickOn(A)
+ return
+
+ if(stat || lockcharge || weakened || stunned || paralysis)
+ return
+
+ if(next_move >= world.time)
+ return
+
+ face_atom(A) // change direction to face what you clicked on
+
+ /*
+ cyborg restrained() currently does nothing
+ if(restrained())
+ RestrainedClickOn(A)
+ return
+ */
+
+ var/obj/item/W = get_active_hand()
+
+ // Cyborgs have no range-checking unless there is item use
+ if(!W)
+ A.attack_robot(src)
+ return
+
+ // buckled cannot prevent machine interlinking but stops arm movement
+ if( buckled )
+ return
+
+ if(W == A)
+ next_move = world.time + 8
+ if(W.flags&USEDELAY)
+ next_move += 5
+
+ W.attack_self(src)
+ return
+
+ // cyborgs are prohibited from using storage items so we can I think safely remove (A.loc in contents)
+ if(A == loc || (A in loc) || (A in contents))
+ // No adjacency checks
+ next_move = world.time + 8
+ if(W.flags&USEDELAY)
+ next_move += 5
+
+ var/resolved = A.attackby(W,src)
+ if(!resolved && A && W)
+ W.afterattack(A,src,1,params)
+ return
+
+ if(!isturf(loc))
+ return
+
+ // cyborgs are prohibited from using storage items so we can I think safely remove (A.loc && isturf(A.loc.loc))
+ if(isturf(A) || isturf(A.loc))
+ if(A.Adjacent(src)) // see adjacent.dm
+ next_move = world.time + 10
+ if(W.flags&USEDELAY)
+ next_move += 5
+
+ var/resolved = A.attackby(W, src)
+ if(!resolved && A && W)
+ W.afterattack(A, src, 1, params)
+ return
+ else
+ next_move = world.time + 10
+ W.afterattack(A, src, 0, params)
+ return
+ return
+
+//Middle click cycles through selected modules.
+/mob/living/silicon/robot/MiddleClickOn(var/atom/A)
+ cycle_modules()
+ return
+
+/*
+ As with AI, these are not used in click code,
+ because the code for robots is specific, not generic.
+
+ If you would like to add advanced features to robot
+ clicks, you can do so here, but you will have to
+ change attack_robot() above to the proper function
+*/
+/mob/living/silicon/robot/UnarmedAttack(atom/A)
+ A.attack_robot(src)
+/mob/living/silicon/robot/RangedAttack(atom/A)
+ A.attack_robot(src)
+
+/atom/proc/attack_robot(mob/user as mob)
+ attack_ai(user)
+ return
diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm
new file mode 100644
index 00000000000..42a0574f4d8
--- /dev/null
+++ b/code/_onclick/drag_drop.dm
@@ -0,0 +1,18 @@
+/*
+ MouseDrop:
+
+ Called on the atom you're dragging. In a lot of circumstances we want to use the
+ recieving object instead, so that's the default action. This allows you to drag
+ almost anything into a trash can.
+*/
+/atom/MouseDrop(atom/over)
+ if(!usr || !over) return
+ if(!Adjacent(usr) || !over.Adjacent(usr)) return // should stop you from dragging through windows
+
+ spawn(0)
+ over.MouseDrop_T(src,usr)
+ return
+
+// recieve a mousedrop
+/atom/proc/MouseDrop_T(atom/dropping, mob/user)
+ return
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
new file mode 100644
index 00000000000..fc822a38542
--- /dev/null
+++ b/code/_onclick/hud/_defines.dm
@@ -0,0 +1,119 @@
+/*
+ These defines specificy screen locations. For more information, see the byond documentation on the screen_loc var.
+
+ The short version:
+
+ Everything is encoded as strings because apparently that's how Byond rolls.
+
+ "1,1" is the bottom left square of the user's screen. This aligns perfectly with the turf grid.
+ "1:2,3:4" is the square (1,3) with pixel offsets (+2, +4); slightly right and slightly above the turf grid.
+ Pixel offsets are used so you don't perfectly hide the turf under them, that would be crappy.
+
+ The size of the user's screen is defined by client.view (indirectly by world.view), in our case "15x15".
+ Therefore, the top right corner (except during admin shenanigans) is at "15,15"
+*/
+
+//Upper left action buttons, displayed when you pick up an item that has this enabled.
+#define ui_action_slot1 "1:6,14:26"
+#define ui_action_slot2 "2:8,14:26"
+#define ui_action_slot3 "3:10,14:26"
+#define ui_action_slot4 "4:12,14:26"
+#define ui_action_slot5 "5:14,14:26"
+
+//Lower left, persistant menu
+#define ui_inventory "1:6,1:5"
+
+//Lower center, persistant menu
+#define ui_sstore1 "3:10,1:5"
+#define ui_id "4:12,1:5"
+#define ui_belt "5:14,1:5"
+#define ui_back "6:14,1:5"
+#define ui_rhand "7:16,1:5"
+#define ui_lhand "8:16,1:5"
+#define ui_equip "7:16,2:5"
+#define ui_swaphand1 "7:16,2:5"
+#define ui_swaphand2 "8:16,2:5"
+#define ui_storage1 "9:18,1:5"
+#define ui_storage2 "10:20,1:5"
+
+#define ui_alien_head "4:12,1:5" //aliens
+#define ui_alien_oclothing "5:14,1:5" //aliens
+
+#define ui_inv1 "6:16,1:5" //borgs
+#define ui_inv2 "7:16,1:5" //borgs
+#define ui_inv3 "8:16,1:5" //borgs
+#define ui_borg_store "9:16,1:5" //borgs
+
+#define ui_monkey_mask "5:14,1:5" //monkey
+#define ui_monkey_back "6:14,1:5" //monkey
+
+//Lower right, persistant menu
+#define ui_dropbutton "11:22,1:5"
+#define ui_drop_throw "14:28,2:7"
+#define ui_pull_resist "13:26,2:7"
+#define ui_acti "13:26,1:5"
+#define ui_movi "12:24,1:5"
+#define ui_zonesel "14:28,1:5"
+#define ui_acti_alt "14:28,1:5" //alternative intent switcher for when the interface is hidden (F12)
+
+#define ui_borg_pull "12:24,2:7"
+#define ui_borg_module "13:26,2:7"
+#define ui_borg_panel "14:28,2:7"
+
+//Gun buttons
+#define ui_gun1 "13:26,3:7"
+#define ui_gun2 "14:28, 4:7"
+#define ui_gun3 "13:26,4:7"
+#define ui_gun_select "14:28,3:7"
+
+//Upper-middle right (damage indicators)
+#define ui_toxin "14:28,13:27"
+#define ui_fire "14:28,12:25"
+#define ui_oxygen "14:28,11:23"
+#define ui_pressure "14:28,10:21"
+
+#define ui_alien_toxin "14:28,13:25"
+#define ui_alien_fire "14:28,12:25"
+#define ui_alien_oxygen "14:28,11:25"
+
+//Middle right (status indicators)
+#define ui_nutrition "14:28,5:11"
+#define ui_temp "14:28,6:13"
+#define ui_health "14:28,7:15"
+#define ui_internal "14:28,8:17"
+ //borgs
+#define ui_borg_health "14:28,6:13" //borgs have the health display where humans have the pressure damage indicator.
+#define ui_alien_health "14:28,6:13" //aliens have the health display where humans have the pressure damage indicator.
+
+//Pop-up inventory
+#define ui_shoes "2:8,1:5"
+
+#define ui_iclothing "1:6,2:7"
+#define ui_oclothing "2:8,2:7"
+#define ui_gloves "3:10,2:7"
+
+#define ui_glasses "1:6,3:9"
+#define ui_mask "2:8,3:9"
+#define ui_l_ear "3:10,3:9"
+#define ui_r_ear "3:10,4:11"
+
+#define ui_head "2:8,4:11"
+
+//Intent small buttons
+#define ui_help_small "12:8,1:1"
+#define ui_disarm_small "12:15,1:18"
+#define ui_grab_small "12:32,1:18"
+#define ui_harm_small "12:39,1:1"
+
+//#define ui_swapbutton "6:-16,1:5" //Unused
+
+//#define ui_headset "SOUTH,8"
+#define ui_hand "6:14,1:5"
+#define ui_hstore1 "5,5"
+//#define ui_resist "EAST+1,SOUTH-1"
+#define ui_sleep "EAST+1, NORTH-13"
+#define ui_rest "EAST+1, NORTH-14"
+
+
+#define ui_iarrowleft "SOUTH-1,11"
+#define ui_iarrowright "SOUTH-1,13"
diff --git a/code/_onclick/hud/alien.dm b/code/_onclick/hud/alien.dm
new file mode 100644
index 00000000000..01b10585273
--- /dev/null
+++ b/code/_onclick/hud/alien.dm
@@ -0,0 +1,241 @@
+/datum/hud/proc/alien_hud()
+
+ src.adding = list( )
+ src.other = list( )
+
+ var/obj/screen/using
+ var/obj/screen/inventory/inv_box
+
+ using = new /obj/screen()
+ using.name = "act_intent"
+ using.dir = SOUTHWEST
+ using.icon = 'icons/mob/screen1_alien.dmi'
+ using.icon_state = (mymob.a_intent == "hurt" ? "harm" : mymob.a_intent)
+ using.screen_loc = ui_acti
+ using.layer = 20
+ src.adding += using
+ action_intent = using
+
+//intent small hud objects
+ var/icon/ico
+
+ ico = new('icons/mob/screen1_alien.dmi', "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),1,ico.Height()/2,ico.Width()/2,ico.Height())
+ using = new /obj/screen( src )
+ using.name = "help"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ help_intent = using
+
+ ico = new('icons/mob/screen1_alien.dmi', "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,ico.Height()/2,ico.Width(),ico.Height())
+ using = new /obj/screen( src )
+ using.name = "disarm"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ disarm_intent = using
+
+ ico = new('icons/mob/screen1_alien.dmi', "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,1,ico.Width(),ico.Height()/2)
+ using = new /obj/screen( src )
+ using.name = "grab"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ grab_intent = using
+
+ ico = new('icons/mob/screen1_alien.dmi', "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),1,1,ico.Width()/2,ico.Height()/2)
+ using = new /obj/screen( src )
+ using.name = "harm"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ hurt_intent = using
+
+//end intent small hud objects
+
+ using = new /obj/screen()
+ using.name = "mov_intent"
+ using.dir = SOUTHWEST
+ using.icon = 'icons/mob/screen1_alien.dmi'
+ using.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
+ using.screen_loc = ui_movi
+ using.layer = 20
+ src.adding += using
+ move_intent = using
+
+ using = new /obj/screen()
+ using.name = "drop"
+ using.icon = 'icons/mob/screen1_alien.dmi'
+ using.icon_state = "act_drop"
+ using.screen_loc = ui_drop_throw
+ using.layer = 19
+ src.adding += using
+
+//equippable shit
+ //suit
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "o_clothing"
+ inv_box.dir = SOUTH
+ inv_box.icon = 'icons/mob/screen1_alien.dmi'
+ inv_box.icon_state = "equip"
+ inv_box.screen_loc = ui_alien_oclothing
+ inv_box.slot_id = slot_wear_suit
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "r_hand"
+ inv_box.dir = WEST
+ inv_box.icon = 'icons/mob/screen1_alien.dmi'
+ inv_box.icon_state = "hand_inactive"
+ if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use
+ using.icon_state = "hand_active"
+ inv_box.screen_loc = ui_rhand
+ inv_box.layer = 19
+ src.r_hand_hud_object = inv_box
+ inv_box.slot_id = slot_r_hand
+ src.adding += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "l_hand"
+ inv_box.dir = EAST
+ inv_box.icon = 'icons/mob/screen1_alien.dmi'
+ inv_box.icon_state = "hand_inactive"
+ if(mymob && mymob.hand) //This being 1 means the left hand is in use
+ inv_box.icon_state = "hand_active"
+ inv_box.screen_loc = ui_lhand
+ inv_box.layer = 19
+ inv_box.slot_id = slot_l_hand
+ src.l_hand_hud_object = inv_box
+ src.adding += inv_box
+
+ using = new /obj/screen/inventory()
+ using.name = "hand"
+ using.dir = SOUTH
+ using.icon = 'icons/mob/screen1_alien.dmi'
+ using.icon_state = "hand1"
+ using.screen_loc = ui_swaphand1
+ using.layer = 19
+ src.adding += using
+
+ using = new /obj/screen/inventory()
+ using.name = "hand"
+ using.dir = SOUTH
+ using.icon = 'icons/mob/screen1_alien.dmi'
+ using.icon_state = "hand2"
+ using.screen_loc = ui_swaphand2
+ using.layer = 19
+ src.adding += using
+
+ //pocket 1
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "storage1"
+ inv_box.icon = 'icons/mob/screen1_alien.dmi'
+ inv_box.icon_state = "pocket"
+ inv_box.screen_loc = ui_storage1
+ inv_box.slot_id = slot_l_store
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ //pocket 2
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "storage2"
+ inv_box.icon = 'icons/mob/screen1_alien.dmi'
+ inv_box.icon_state = "pocket"
+ inv_box.screen_loc = ui_storage2
+ inv_box.slot_id = slot_r_store
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ //head
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "head"
+ inv_box.icon = 'icons/mob/screen1_alien.dmi'
+ inv_box.icon_state = "hair"
+ inv_box.screen_loc = ui_alien_head
+ inv_box.slot_id = slot_head
+ inv_box.layer = 19
+ src.adding += inv_box
+//end of equippable shit
+
+/*
+ using = new /obj/screen()
+ using.name = "resist"
+ using.icon = 'icons/mob/screen1_alien.dmi'
+ using.icon_state = "act_resist"
+ using.screen_loc = ui_resist
+ using.layer = 19
+ src.adding += using
+*/
+
+ mymob.throw_icon = new /obj/screen()
+ mymob.throw_icon.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.throw_icon.icon_state = "act_throw_off"
+ mymob.throw_icon.name = "throw"
+ mymob.throw_icon.screen_loc = ui_drop_throw
+
+ mymob.oxygen = new /obj/screen()
+ mymob.oxygen.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.oxygen.icon_state = "oxy0"
+ mymob.oxygen.name = "oxygen"
+ mymob.oxygen.screen_loc = ui_alien_oxygen
+
+ mymob.toxin = new /obj/screen()
+ mymob.toxin.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.toxin.icon_state = "tox0"
+ mymob.toxin.name = "toxin"
+ mymob.toxin.screen_loc = ui_alien_toxin
+
+ mymob.fire = new /obj/screen()
+ mymob.fire.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.fire.icon_state = "fire0"
+ mymob.fire.name = "fire"
+ mymob.fire.screen_loc = ui_alien_fire
+
+ mymob.healths = new /obj/screen()
+ mymob.healths.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.healths.icon_state = "health0"
+ mymob.healths.name = "health"
+ mymob.healths.screen_loc = ui_alien_health
+
+ mymob.pullin = new /obj/screen()
+ mymob.pullin.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.pullin.icon_state = "pull0"
+ mymob.pullin.name = "pull"
+ mymob.pullin.screen_loc = ui_pull_resist
+
+ mymob.blind = new /obj/screen()
+ mymob.blind.icon = 'icons/mob/screen1_full.dmi'
+ mymob.blind.icon_state = "blackimageoverlay"
+ mymob.blind.name = " "
+ mymob.blind.screen_loc = "1,1"
+ mymob.blind.layer = 0
+
+ mymob.flash = new /obj/screen()
+ mymob.flash.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.flash.icon_state = "blank"
+ mymob.flash.name = "flash"
+ mymob.flash.screen_loc = "1,1 to 15,15"
+ mymob.flash.layer = 17
+
+ mymob.zone_sel = new /obj/screen/zone_sel()
+ mymob.zone_sel.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.zone_sel.overlays.Cut()
+ mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]")
+
+ mymob.client.screen = null
+
+ mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.toxin, mymob.fire, mymob.healths, mymob.pullin, mymob.blind, mymob.flash) //, mymob.hands, mymob.rest, mymob.sleep, mymob.mach )
+ mymob.client.screen += src.adding + src.other
\ No newline at end of file
diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm
new file mode 100644
index 00000000000..4e29827e892
--- /dev/null
+++ b/code/_onclick/hud/alien_larva.dm
@@ -0,0 +1,81 @@
+/datum/hud/proc/larva_hud()
+
+ src.adding = list()
+ src.other = list()
+
+ var/obj/screen/using
+
+ using = new /obj/screen()
+ using.name = "act_intent"
+ using.dir = SOUTHWEST
+ using.icon = 'icons/mob/screen1_alien.dmi'
+ using.icon_state = (mymob.a_intent == "hurt" ? "harm" : mymob.a_intent)
+ using.screen_loc = ui_acti
+ using.layer = 20
+ src.adding += using
+ action_intent = using
+
+ using = new /obj/screen()
+ using.name = "mov_intent"
+ using.dir = SOUTHWEST
+ using.icon = 'icons/mob/screen1_alien.dmi'
+ using.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
+ using.screen_loc = ui_movi
+ using.layer = 20
+ src.adding += using
+ move_intent = using
+
+ mymob.oxygen = new /obj/screen()
+ mymob.oxygen.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.oxygen.icon_state = "oxy0"
+ mymob.oxygen.name = "oxygen"
+ mymob.oxygen.screen_loc = ui_alien_oxygen
+
+ mymob.toxin = new /obj/screen()
+ mymob.toxin.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.toxin.icon_state = "tox0"
+ mymob.toxin.name = "toxin"
+ mymob.toxin.screen_loc = ui_alien_toxin
+
+
+ mymob.fire = new /obj/screen()
+ mymob.fire.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.fire.icon_state = "fire0"
+ mymob.fire.name = "fire"
+ mymob.fire.screen_loc = ui_alien_fire
+
+
+ mymob.healths = new /obj/screen()
+ mymob.healths.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.healths.icon_state = "health0"
+ mymob.healths.name = "health"
+ mymob.healths.screen_loc = ui_alien_health
+
+ mymob.pullin = new /obj/screen()
+ mymob.pullin.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.pullin.icon_state = "pull0"
+ mymob.pullin.name = "pull"
+ mymob.pullin.screen_loc = ui_pull_resist
+
+ mymob.blind = new /obj/screen()
+ mymob.blind.icon = 'icons/mob/screen1_full.dmi'
+ mymob.blind.icon_state = "blackimageoverlay"
+ mymob.blind.name = " "
+ mymob.blind.screen_loc = "1,1"
+ mymob.blind.layer = 0
+
+ mymob.flash = new /obj/screen()
+ mymob.flash.icon = 'icons/mob/screen1_alien.dmi'
+ mymob.flash.icon_state = "blank"
+ mymob.flash.name = "flash"
+ mymob.flash.screen_loc = "1,1 to 15,15"
+ mymob.flash.layer = 17
+
+ mymob.zone_sel = new /obj/screen/zone_sel()
+ mymob.zone_sel.overlays.Cut()
+ mymob.zone_sel.overlays += image("icon" = 'icons/mob/zone_sel.dmi', "icon_state" = text("[]", mymob.zone_sel.selecting))
+
+ mymob.client.screen = null
+
+ mymob.client.screen += list( mymob.zone_sel, mymob.oxygen, mymob.toxin, mymob.fire, mymob.healths, mymob.pullin, mymob.blind, mymob.flash) //, mymob.rest, mymob.sleep, mymob.mach )
+ mymob.client.screen += src.adding + src.other
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
new file mode 100644
index 00000000000..618858d5438
--- /dev/null
+++ b/code/_onclick/hud/hud.dm
@@ -0,0 +1,237 @@
+/*
+ The global hud:
+ Uses the same visual objects for all players.
+*/
+var/datum/global_hud/global_hud = new()
+
+/datum/hud/var/obj/screen/grab_intent
+/datum/hud/var/obj/screen/hurt_intent
+/datum/hud/var/obj/screen/disarm_intent
+/datum/hud/var/obj/screen/help_intent
+
+/datum/global_hud
+ var/obj/screen/druggy
+ var/obj/screen/blurry
+ var/list/vimpaired
+ var/list/darkMask
+
+/datum/global_hud/New()
+ //420erryday psychedellic colours screen overlay for when you are high
+ druggy = new /obj/screen()
+ druggy.screen_loc = "WEST,SOUTH to EAST,NORTH"
+ druggy.icon_state = "druggy"
+ druggy.layer = 17
+ druggy.mouse_opacity = 0
+
+ //that white blurry effect you get when you eyes are damaged
+ blurry = new /obj/screen()
+ blurry.screen_loc = "WEST,SOUTH to EAST,NORTH"
+ blurry.icon_state = "blurry"
+ blurry.layer = 17
+ blurry.mouse_opacity = 0
+
+ var/obj/screen/O
+ var/i
+ //that nasty looking dither you get when you're short-sighted
+ vimpaired = newlist(/obj/screen,/obj/screen,/obj/screen,/obj/screen)
+ O = vimpaired[1]
+ O.screen_loc = "1,1 to 5,15"
+ O = vimpaired[2]
+ O.screen_loc = "5,1 to 10,5"
+ O = vimpaired[3]
+ O.screen_loc = "6,11 to 10,15"
+ O = vimpaired[4]
+ O.screen_loc = "11,1 to 15,15"
+
+ //welding mask overlay black/dither
+ darkMask = newlist(/obj/screen, /obj/screen, /obj/screen, /obj/screen, /obj/screen, /obj/screen, /obj/screen, /obj/screen)
+ O = darkMask[1]
+ O.screen_loc = "3,3 to 5,13"
+ O = darkMask[2]
+ O.screen_loc = "5,3 to 10,5"
+ O = darkMask[3]
+ O.screen_loc = "6,11 to 10,13"
+ O = darkMask[4]
+ O.screen_loc = "11,3 to 13,13"
+ O = darkMask[5]
+ O.screen_loc = "1,1 to 15,2"
+ O = darkMask[6]
+ O.screen_loc = "1,3 to 2,15"
+ O = darkMask[7]
+ O.screen_loc = "14,3 to 15,15"
+ O = darkMask[8]
+ O.screen_loc = "3,14 to 13,15"
+
+ for(i = 1, i <= 4, i++)
+ O = vimpaired[i]
+ O.icon_state = "dither50"
+ O.layer = 17
+ O.mouse_opacity = 0
+
+ O = darkMask[i]
+ O.icon_state = "dither50"
+ O.layer = 17
+ O.mouse_opacity = 0
+
+ for(i = 5, i <= 8, i++)
+ O = darkMask[i]
+ O.icon_state = "black"
+ O.layer = 17
+ O.mouse_opacity = 0
+
+/*
+ The hud datum
+ Used to show and hide huds for all the different mob types,
+ including inventories and item quick actions.
+*/
+
+/datum/hud
+ var/mob/mymob
+
+ var/hud_shown = 1 //Used for the HUD toggle (F12)
+ var/inventory_shown = 1 //the inventory
+ var/show_intent_icons = 0
+ var/hotkey_ui_hidden = 0 //This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons)
+
+ var/obj/screen/lingchemdisplay
+ var/obj/screen/blobpwrdisplay
+ var/obj/screen/blobhealthdisplay
+ var/obj/screen/r_hand_hud_object
+ var/obj/screen/l_hand_hud_object
+ var/obj/screen/action_intent
+ var/obj/screen/move_intent
+
+ var/list/adding
+ var/list/other
+ var/list/obj/screen/hotkeybuttons
+
+ var/list/obj/screen/item_action/item_action_list = list() //Used for the item action ui buttons.
+
+
+datum/hud/New(mob/owner)
+ mymob = owner
+ instantiate()
+ ..()
+
+
+/datum/hud/proc/hidden_inventory_update()
+ if(!mymob) return
+ if(ishuman(mymob))
+ var/mob/living/carbon/human/H = mymob
+ if(inventory_shown && hud_shown)
+ if(H.shoes) H.shoes.screen_loc = ui_shoes
+ if(H.gloves) H.gloves.screen_loc = ui_gloves
+ if(H.l_ear) H.l_ear.screen_loc = ui_l_ear
+ if(H.r_ear) H.r_ear.screen_loc = ui_r_ear
+ if(H.glasses) H.glasses.screen_loc = ui_glasses
+ if(H.w_uniform) H.w_uniform.screen_loc = ui_iclothing
+ if(H.wear_suit) H.wear_suit.screen_loc = ui_oclothing
+ if(H.wear_mask) H.wear_mask.screen_loc = ui_mask
+ if(H.head) H.head.screen_loc = ui_head
+ else
+ if(H.shoes) H.shoes.screen_loc = null
+ if(H.gloves) H.gloves.screen_loc = null
+ if(H.l_ear) H.l_ear.screen_loc = null
+ if(H.r_ear) H.r_ear.screen_loc = null
+ if(H.glasses) H.glasses.screen_loc = null
+ if(H.w_uniform) H.w_uniform.screen_loc = null
+ if(H.wear_suit) H.wear_suit.screen_loc = null
+ if(H.wear_mask) H.wear_mask.screen_loc = null
+ if(H.head) H.head.screen_loc = null
+
+
+/datum/hud/proc/persistant_inventory_update()
+ if(!mymob)
+ return
+
+ if(ishuman(mymob))
+ var/mob/living/carbon/human/H = mymob
+ if(hud_shown)
+ if(H.s_store) H.s_store.screen_loc = ui_sstore1
+ if(H.wear_id) H.wear_id.screen_loc = ui_id
+ if(H.belt) H.belt.screen_loc = ui_belt
+ if(H.back) H.back.screen_loc = ui_back
+ if(H.l_store) H.l_store.screen_loc = ui_storage1
+ if(H.r_store) H.r_store.screen_loc = ui_storage2
+ else
+ if(H.s_store) H.s_store.screen_loc = null
+ if(H.wear_id) H.wear_id.screen_loc = null
+ if(H.belt) H.belt.screen_loc = null
+ if(H.back) H.back.screen_loc = null
+ if(H.l_store) H.l_store.screen_loc = null
+ if(H.r_store) H.r_store.screen_loc = null
+
+
+/datum/hud/proc/instantiate()
+ if(!ismob(mymob)) return 0
+ if(!mymob.client) return 0
+ var/ui_style = ui_style2icon(mymob.client.prefs.UI_style)
+
+ if(ishuman(mymob))
+ human_hud(ui_style) // Pass the player the UI style chosen in preferences
+ else if(ismonkey(mymob))
+ monkey_hud(ui_style)
+ else if(isbrain(mymob))
+ brain_hud(ui_style)
+ else if(islarva(mymob))
+ larva_hud()
+ else if(isalien(mymob))
+ alien_hud()
+ else if(isAI(mymob))
+ ai_hud()
+ else if(isrobot(mymob))
+ robot_hud()
+ else if(isobserver(mymob))
+ ghost_hud()
+
+
+//Triggered when F12 is pressed (Unless someone changed something in the DMF)
+/mob/verb/button_pressed_F12()
+ set name = "F12"
+ set hidden = 1
+
+ if(hud_used)
+ if(ishuman(src))
+ if(!src.client) return
+
+ if(hud_used.hud_shown)
+ hud_used.hud_shown = 0
+ if(src.hud_used.adding)
+ src.client.screen -= src.hud_used.adding
+ if(src.hud_used.other)
+ src.client.screen -= src.hud_used.other
+ if(src.hud_used.hotkeybuttons)
+ src.client.screen -= src.hud_used.hotkeybuttons
+ if(src.hud_used.item_action_list)
+ src.client.screen -= src.hud_used.item_action_list
+
+ //Due to some poor coding some things need special treatment:
+ //These ones are a part of 'adding', 'other' or 'hotkeybuttons' but we want them to stay
+ src.client.screen += src.hud_used.l_hand_hud_object //we want the hands to be visible
+ src.client.screen += src.hud_used.r_hand_hud_object //we want the hands to be visible
+ src.client.screen += src.hud_used.action_intent //we want the intent swticher visible
+ src.hud_used.action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is.
+
+ //These ones are not a part of 'adding', 'other' or 'hotkeybuttons' but we want them gone.
+ src.client.screen -= src.zone_sel //zone_sel is a mob variable for some reason.
+
+ else
+ hud_used.hud_shown = 1
+ if(src.hud_used.adding)
+ src.client.screen += src.hud_used.adding
+ if(src.hud_used.other && src.hud_used.inventory_shown)
+ src.client.screen += src.hud_used.other
+ if(src.hud_used.hotkeybuttons && !src.hud_used.hotkey_ui_hidden)
+ src.client.screen += src.hud_used.hotkeybuttons
+
+
+ src.hud_used.action_intent.screen_loc = ui_acti //Restore intent selection to the original position
+ src.client.screen += src.zone_sel //This one is a special snowflake
+
+ hud_used.hidden_inventory_update()
+ hud_used.persistant_inventory_update()
+ update_action_buttons()
+ else
+ usr << "\red Inventory hiding is currently only supported for human mobs, sorry."
+ else
+ usr << "\red This mob type does not use a HUD."
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
new file mode 100644
index 00000000000..32e9e1046ec
--- /dev/null
+++ b/code/_onclick/hud/human.dm
@@ -0,0 +1,475 @@
+/datum/hud/proc/human_hud(var/ui_style='icons/mob/screen1_old.dmi')
+
+ src.adding = list()
+ src.other = list()
+ src.hotkeybuttons = list() //These can be disabled for hotkey usersx
+
+ var/obj/screen/using
+ var/obj/screen/inventory/inv_box
+
+ using = new /obj/screen()
+ using.name = "act_intent"
+ using.dir = SOUTHWEST
+ using.icon = ui_style
+ using.icon_state = "intent_"+mymob.a_intent
+ using.screen_loc = ui_acti
+ using.layer = 20
+ src.adding += using
+ action_intent = using
+
+//intent small hud objects
+ var/icon/ico
+
+ ico = new(ui_style, "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),1,ico.Height()/2,ico.Width()/2,ico.Height())
+ using = new /obj/screen( src )
+ using.name = "help"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ help_intent = using
+
+ ico = new(ui_style, "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,ico.Height()/2,ico.Width(),ico.Height())
+ using = new /obj/screen( src )
+ using.name = "disarm"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ disarm_intent = using
+
+ ico = new(ui_style, "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,1,ico.Width(),ico.Height()/2)
+ using = new /obj/screen( src )
+ using.name = "grab"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ grab_intent = using
+
+ ico = new(ui_style, "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),1,1,ico.Width()/2,ico.Height()/2)
+ using = new /obj/screen( src )
+ using.name = "harm"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ hurt_intent = using
+
+//end intent small hud objects
+
+ using = new /obj/screen()
+ using.name = "mov_intent"
+ using.dir = SOUTHWEST
+ using.icon = ui_style
+ using.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
+ using.screen_loc = ui_movi
+ using.layer = 20
+ src.adding += using
+ move_intent = using
+
+ using = new /obj/screen()
+ using.name = "drop"
+ using.icon = ui_style
+ using.icon_state = "act_drop"
+ using.screen_loc = ui_drop_throw
+ using.layer = 19
+ src.hotkeybuttons += using
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "i_clothing"
+ inv_box.dir = SOUTH
+ inv_box.icon = ui_style
+ inv_box.slot_id = slot_w_uniform
+ inv_box.icon_state = "center"
+ inv_box.screen_loc = ui_iclothing
+ inv_box.layer = 19
+ src.other += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "o_clothing"
+ inv_box.dir = SOUTH
+ inv_box.icon = ui_style
+ inv_box.slot_id = slot_wear_suit
+ inv_box.icon_state = "equip"
+ inv_box.screen_loc = ui_oclothing
+ inv_box.layer = 19
+ src.other += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "r_hand"
+ inv_box.dir = WEST
+ inv_box.icon = ui_style
+ inv_box.icon_state = "hand_inactive"
+ if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use
+ inv_box.icon_state = "hand_active"
+ inv_box.screen_loc = ui_rhand
+ inv_box.slot_id = slot_r_hand
+ inv_box.layer = 19
+ src.r_hand_hud_object = inv_box
+ src.adding += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "l_hand"
+ inv_box.dir = EAST
+ inv_box.icon = ui_style
+ inv_box.icon_state = "hand_inactive"
+ if(mymob && mymob.hand) //This being 1 means the left hand is in use
+ inv_box.icon_state = "hand_active"
+ inv_box.screen_loc = ui_lhand
+ inv_box.slot_id = slot_l_hand
+ inv_box.layer = 19
+ src.l_hand_hud_object = inv_box
+ src.adding += inv_box
+
+ using = new /obj/screen/inventory()
+ using.name = "hand"
+ using.dir = SOUTH
+ using.icon = ui_style
+ using.icon_state = "hand1"
+ using.screen_loc = ui_swaphand1
+ using.layer = 19
+ src.adding += using
+
+ using = new /obj/screen/inventory()
+ using.name = "hand"
+ using.dir = SOUTH
+ using.icon = ui_style
+ using.icon_state = "hand2"
+ using.screen_loc = ui_swaphand2
+ using.layer = 19
+ src.adding += using
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "id"
+ inv_box.dir = NORTH
+ inv_box.icon = ui_style
+ inv_box.icon_state = "id"
+ inv_box.screen_loc = ui_id
+ inv_box.slot_id = slot_wear_id
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "mask"
+ inv_box.dir = NORTH
+ inv_box.icon = ui_style
+ inv_box.icon_state = "equip"
+ inv_box.screen_loc = ui_mask
+ inv_box.slot_id = slot_wear_mask
+ inv_box.layer = 19
+ src.other += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "back"
+ inv_box.dir = NORTH
+ inv_box.icon = ui_style
+ inv_box.icon_state = "back"
+ inv_box.screen_loc = ui_back
+ inv_box.slot_id = slot_back
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "storage1"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "pocket"
+ inv_box.screen_loc = ui_storage1
+ inv_box.slot_id = slot_l_store
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "storage2"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "pocket"
+ inv_box.screen_loc = ui_storage2
+ inv_box.slot_id = slot_r_store
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "suit storage"
+ inv_box.icon = ui_style
+ inv_box.dir = 8 //The sprite at dir=8 has the background whereas the others don't.
+ inv_box.icon_state = "belt"
+ inv_box.screen_loc = ui_sstore1
+ inv_box.slot_id = slot_s_store
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ using = new /obj/screen()
+ using.name = "resist"
+ using.icon = ui_style
+ using.icon_state = "act_resist"
+ using.screen_loc = ui_pull_resist
+ using.layer = 19
+ src.hotkeybuttons += using
+
+ using = new /obj/screen()
+ using.name = "toggle"
+ using.icon = ui_style
+ using.icon_state = "other"
+ using.screen_loc = ui_inventory
+ using.layer = 20
+ src.adding += using
+
+ using = new /obj/screen()
+ using.name = "equip"
+ using.icon = ui_style
+ using.icon_state = "act_equip"
+ using.screen_loc = ui_equip
+ using.layer = 20
+ src.adding += using
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "gloves"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "gloves"
+ inv_box.screen_loc = ui_gloves
+ inv_box.slot_id = slot_gloves
+ inv_box.layer = 19
+ src.other += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "eyes"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "glasses"
+ inv_box.screen_loc = ui_glasses
+ inv_box.slot_id = slot_glasses
+ inv_box.layer = 19
+ src.other += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "l_ear"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "ears"
+ inv_box.screen_loc = ui_l_ear
+ inv_box.slot_id = slot_l_ear
+ inv_box.layer = 19
+ src.other += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "r_ear"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "ears"
+ inv_box.screen_loc = ui_r_ear
+ inv_box.slot_id = slot_r_ear
+ inv_box.layer = 19
+ src.other += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "head"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "hair"
+ inv_box.screen_loc = ui_head
+ inv_box.slot_id = slot_head
+ inv_box.layer = 19
+ src.other += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "shoes"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "shoes"
+ inv_box.screen_loc = ui_shoes
+ inv_box.slot_id = slot_shoes
+ inv_box.layer = 19
+ src.other += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "belt"
+ inv_box.icon = ui_style
+ inv_box.icon_state = "belt"
+ inv_box.screen_loc = ui_belt
+ inv_box.slot_id = slot_belt
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ mymob.throw_icon = new /obj/screen()
+ mymob.throw_icon.icon = ui_style
+ mymob.throw_icon.icon_state = "act_throw_off"
+ mymob.throw_icon.name = "throw"
+ mymob.throw_icon.screen_loc = ui_drop_throw
+ src.hotkeybuttons += mymob.throw_icon
+
+ mymob.oxygen = new /obj/screen()
+ mymob.oxygen.icon = ui_style
+ mymob.oxygen.icon_state = "oxy0"
+ mymob.oxygen.name = "oxygen"
+ mymob.oxygen.screen_loc = ui_oxygen
+
+ mymob.pressure = new /obj/screen()
+ mymob.pressure.icon = ui_style
+ mymob.pressure.icon_state = "pressure0"
+ mymob.pressure.name = "pressure"
+ mymob.pressure.screen_loc = ui_pressure
+
+ mymob.toxin = new /obj/screen()
+ mymob.toxin.icon = ui_style
+ mymob.toxin.icon_state = "tox0"
+ mymob.toxin.name = "toxin"
+ mymob.toxin.screen_loc = ui_toxin
+
+ mymob.internals = new /obj/screen()
+ mymob.internals.icon = ui_style
+ mymob.internals.icon_state = "internal0"
+ mymob.internals.name = "internal"
+ mymob.internals.screen_loc = ui_internal
+
+ mymob.fire = new /obj/screen()
+ mymob.fire.icon = ui_style
+ mymob.fire.icon_state = "fire0"
+ mymob.fire.name = "fire"
+ mymob.fire.screen_loc = ui_fire
+
+ mymob.bodytemp = new /obj/screen()
+ mymob.bodytemp.icon = ui_style
+ mymob.bodytemp.icon_state = "temp1"
+ mymob.bodytemp.name = "body temperature"
+ mymob.bodytemp.screen_loc = ui_temp
+
+ mymob.healths = new /obj/screen()
+ mymob.healths.icon = ui_style
+ mymob.healths.icon_state = "health0"
+ mymob.healths.name = "health"
+ mymob.healths.screen_loc = ui_health
+
+ mymob.nutrition_icon = new /obj/screen()
+ mymob.nutrition_icon.icon = ui_style
+ mymob.nutrition_icon.icon_state = "nutrition0"
+ mymob.nutrition_icon.name = "nutrition"
+ mymob.nutrition_icon.screen_loc = ui_nutrition
+
+ mymob.pullin = new /obj/screen()
+ mymob.pullin.icon = ui_style
+ mymob.pullin.icon_state = "pull0"
+ mymob.pullin.name = "pull"
+ mymob.pullin.screen_loc = ui_pull_resist
+ src.hotkeybuttons += mymob.pullin
+
+ mymob.blind = new /obj/screen()
+ mymob.blind.icon = 'icons/mob/screen1_full.dmi'
+ mymob.blind.icon_state = "blackimageoverlay"
+ mymob.blind.name = " "
+ mymob.blind.screen_loc = "1,1"
+ mymob.blind.mouse_opacity = 0
+ mymob.blind.layer = 0
+
+ mymob.damageoverlay = new /obj/screen()
+ mymob.damageoverlay.icon = 'icons/mob/screen1_full.dmi'
+ mymob.damageoverlay.icon_state = "oxydamageoverlay0"
+ mymob.damageoverlay.name = "dmg"
+ mymob.damageoverlay.screen_loc = "1,1"
+ mymob.damageoverlay.mouse_opacity = 0
+ mymob.damageoverlay.layer = 18.1 //The black screen overlay sets layer to 18 to display it, this one has to be just on top.
+
+ mymob.flash = new /obj/screen()
+ mymob.flash.icon = ui_style
+ mymob.flash.icon_state = "blank"
+ mymob.flash.name = "flash"
+ mymob.flash.screen_loc = "1,1 to 15,15"
+ mymob.flash.layer = 17
+
+ mymob.pain = new /obj/screen( null )
+
+ mymob.zone_sel = new /obj/screen/zone_sel( null )
+ mymob.zone_sel.icon = ui_style
+ mymob.zone_sel.overlays.Cut()
+ mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]")
+
+ //Handle the gun settings buttons
+ mymob.gun_setting_icon = new /obj/screen/gun/mode(null)
+ if (mymob.client)
+ if (mymob.client.gun_mode) // If in aim mode, correct the sprite
+ mymob.gun_setting_icon.dir = 2
+ for(var/obj/item/weapon/gun/G in mymob) // If targeting someone, display other buttons
+ if (G.target)
+ mymob.item_use_icon = new /obj/screen/gun/item(null)
+ if (mymob.client.target_can_click)
+ mymob.item_use_icon.dir = 1
+ src.adding += mymob.item_use_icon
+ mymob.gun_move_icon = new /obj/screen/gun/move(null)
+ if (mymob.client.target_can_move)
+ mymob.gun_move_icon.dir = 1
+ mymob.gun_run_icon = new /obj/screen/gun/run(null)
+ if (mymob.client.target_can_run)
+ mymob.gun_run_icon.dir = 1
+ src.adding += mymob.gun_run_icon
+ src.adding += mymob.gun_move_icon
+
+
+ mymob.client.screen = null
+
+ mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.pressure, mymob.toxin, mymob.bodytemp, mymob.internals, mymob.fire, mymob.healths, mymob.nutrition_icon, mymob.pullin, mymob.blind, mymob.flash, mymob.damageoverlay, mymob.gun_setting_icon) //, mymob.hands, mymob.rest, mymob.sleep) //, mymob.mach )
+ mymob.client.screen += src.adding + src.hotkeybuttons
+ inventory_shown = 0;
+
+ return
+
+
+/mob/living/carbon/human/verb/toggle_hotkey_verbs()
+ set category = "OOC"
+ set name = "Toggle hotkey buttons"
+ set desc = "This disables or enables the user interface buttons which can be used with hotkeys."
+
+ if(hud_used.hotkey_ui_hidden)
+ client.screen += hud_used.hotkeybuttons
+ hud_used.hotkey_ui_hidden = 0
+ else
+ client.screen -= hud_used.hotkeybuttons
+ hud_used.hotkey_ui_hidden = 1
+
+
+/mob/living/carbon/human/update_action_buttons()
+ var/num = 1
+ if(!hud_used) return
+ if(!client) return
+
+ if(!hud_used.hud_shown) //Hud toggled to minimal
+ return
+
+ client.screen -= hud_used.item_action_list
+
+ for(var/obj/item/I in src)
+ if(I.action_button_name)
+ if(hud_used.item_action_list.len < num)
+ var/obj/screen/item_action/N = new(hud_used)
+ hud_used.item_action_list += N
+
+ var/obj/screen/item_action/A = hud_used.item_action_list[num]
+
+ A.icon = ui_style2icon(client.prefs.UI_style)
+ A.icon_state = "template"
+
+ A.overlays = list()
+ var/image/img = image(I.icon, A, I.icon_state)
+ img.pixel_x = 0
+ img.pixel_y = 0
+ A.overlays += img
+
+ A.name = I.action_button_name
+ A.owner = I
+
+ client.screen += hud_used.item_action_list[num]
+
+ switch(num)
+ if(1)
+ A.screen_loc = ui_action_slot1
+ if(2)
+ A.screen_loc = ui_action_slot2
+ if(3)
+ A.screen_loc = ui_action_slot3
+ if(4)
+ A.screen_loc = ui_action_slot4
+ if(5)
+ A.screen_loc = ui_action_slot5
+ break //5 slots available, so no more can be added.
+ num++
diff --git a/code/_onclick/hud/monkey.dm b/code/_onclick/hud/monkey.dm
new file mode 100644
index 00000000000..41e8e3bd2e4
--- /dev/null
+++ b/code/_onclick/hud/monkey.dm
@@ -0,0 +1,248 @@
+/datum/hud/proc/monkey_hud(var/ui_style='icons/mob/screen1_old.dmi')
+
+ src.adding = list()
+ src.other = list()
+
+ var/obj/screen/using
+ var/obj/screen/inventory/inv_box
+
+ using = new /obj/screen()
+ using.name = "act_intent"
+ using.dir = SOUTHWEST
+ using.icon = ui_style
+ using.icon_state = (mymob.a_intent == "hurt" ? "harm" : mymob.a_intent)
+ using.screen_loc = ui_acti
+ using.layer = 20
+ src.adding += using
+ action_intent = using
+
+//intent small hud objects
+ var/icon/ico
+
+ ico = new(ui_style, "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),1,ico.Height()/2,ico.Width()/2,ico.Height())
+ using = new /obj/screen( src )
+ using.name = "help"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ help_intent = using
+
+ ico = new(ui_style, "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,ico.Height()/2,ico.Width(),ico.Height())
+ using = new /obj/screen( src )
+ using.name = "disarm"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ disarm_intent = using
+
+ ico = new(ui_style, "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),ico.Width()/2,1,ico.Width(),ico.Height()/2)
+ using = new /obj/screen( src )
+ using.name = "grab"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ grab_intent = using
+
+ ico = new(ui_style, "black")
+ ico.MapColors(0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, -1,-1,-1,-1)
+ ico.DrawBox(rgb(255,255,255,1),1,1,ico.Width()/2,ico.Height()/2)
+ using = new /obj/screen( src )
+ using.name = "harm"
+ using.icon = ico
+ using.screen_loc = ui_acti
+ using.layer = 21
+ src.adding += using
+ hurt_intent = using
+
+//end intent small hud objects
+
+ using = new /obj/screen()
+ using.name = "mov_intent"
+ using.dir = SOUTHWEST
+ using.icon = ui_style
+ using.icon_state = (mymob.m_intent == "run" ? "running" : "walking")
+ using.screen_loc = ui_movi
+ using.layer = 20
+ src.adding += using
+ move_intent = using
+
+ using = new /obj/screen()
+ using.name = "drop"
+ using.icon = ui_style
+ using.icon_state = "act_drop"
+ using.screen_loc = ui_drop_throw
+ using.layer = 19
+ src.adding += using
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "r_hand"
+ inv_box.dir = WEST
+ inv_box.icon = ui_style
+ inv_box.icon_state = "hand_inactive"
+ if(mymob && !mymob.hand) //This being 0 or null means the right hand is in use
+ inv_box.icon_state = "hand_active"
+ inv_box.screen_loc = ui_rhand
+ inv_box.slot_id = slot_r_hand
+ inv_box.layer = 19
+ src.r_hand_hud_object = inv_box
+ src.adding += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "l_hand"
+ inv_box.dir = EAST
+ inv_box.icon = ui_style
+ inv_box.icon_state = "hand_inactive"
+ if(mymob && mymob.hand) //This being 1 means the left hand is in use
+ inv_box.icon_state = "hand_active"
+ inv_box.screen_loc = ui_lhand
+ inv_box.slot_id = slot_l_hand
+ inv_box.layer = 19
+ src.l_hand_hud_object = inv_box
+ src.adding += inv_box
+
+ using = new /obj/screen()
+ using.name = "hand"
+ using.dir = SOUTH
+ using.icon = ui_style
+ using.icon_state = "hand1"
+ using.screen_loc = ui_swaphand1
+ using.layer = 19
+ src.adding += using
+
+ using = new /obj/screen()
+ using.name = "hand"
+ using.dir = SOUTH
+ using.icon = ui_style
+ using.icon_state = "hand2"
+ using.screen_loc = ui_swaphand2
+ using.layer = 19
+ src.adding += using
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "mask"
+ inv_box.dir = NORTH
+ inv_box.icon = ui_style
+ inv_box.icon_state = "equip"
+ inv_box.screen_loc = ui_monkey_mask
+ inv_box.slot_id = slot_wear_mask
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ inv_box = new /obj/screen/inventory()
+ inv_box.name = "back"
+ inv_box.dir = NORTHEAST
+ inv_box.icon = ui_style
+ inv_box.icon_state = "equip"
+ inv_box.screen_loc = ui_back
+ inv_box.slot_id = slot_back
+ inv_box.layer = 19
+ src.adding += inv_box
+
+ mymob.throw_icon = new /obj/screen()
+ mymob.throw_icon.icon = ui_style
+ mymob.throw_icon.icon_state = "act_throw_off"
+ mymob.throw_icon.name = "throw"
+ mymob.throw_icon.screen_loc = ui_drop_throw
+
+ mymob.oxygen = new /obj/screen()
+ mymob.oxygen.icon = ui_style
+ mymob.oxygen.icon_state = "oxy0"
+ mymob.oxygen.name = "oxygen"
+ mymob.oxygen.screen_loc = ui_oxygen
+
+ mymob.pressure = new /obj/screen()
+ mymob.pressure.icon = ui_style
+ mymob.pressure.icon_state = "pressure0"
+ mymob.pressure.name = "pressure"
+ mymob.pressure.screen_loc = ui_pressure
+
+ mymob.toxin = new /obj/screen()
+ mymob.toxin.icon = ui_style
+ mymob.toxin.icon_state = "tox0"
+ mymob.toxin.name = "toxin"
+ mymob.toxin.screen_loc = ui_toxin
+
+ mymob.internals = new /obj/screen()
+ mymob.internals.icon = ui_style
+ mymob.internals.icon_state = "internal0"
+ mymob.internals.name = "internal"
+ mymob.internals.screen_loc = ui_internal
+
+ mymob.fire = new /obj/screen()
+ mymob.fire.icon = ui_style
+ mymob.fire.icon_state = "fire0"
+ mymob.fire.name = "fire"
+ mymob.fire.screen_loc = ui_fire
+
+ mymob.bodytemp = new /obj/screen()
+ mymob.bodytemp.icon = ui_style
+ mymob.bodytemp.icon_state = "temp1"
+ mymob.bodytemp.name = "body temperature"
+ mymob.bodytemp.screen_loc = ui_temp
+
+ mymob.healths = new /obj/screen()
+ mymob.healths.icon = ui_style
+ mymob.healths.icon_state = "health0"
+ mymob.healths.name = "health"
+ mymob.healths.screen_loc = ui_health
+
+ mymob.pullin = new /obj/screen()
+ mymob.pullin.icon = ui_style
+ mymob.pullin.icon_state = "pull0"
+ mymob.pullin.name = "pull"
+ mymob.pullin.screen_loc = ui_pull_resist
+
+ mymob.blind = new /obj/screen()
+ mymob.blind.icon = 'icons/mob/screen1_full.dmi'
+ mymob.blind.icon_state = "blackimageoverlay"
+ mymob.blind.name = " "
+ mymob.blind.screen_loc = "1,1"
+ mymob.blind.layer = 0
+
+ mymob.flash = new /obj/screen()
+ mymob.flash.icon = ui_style
+ mymob.flash.icon_state = "blank"
+ mymob.flash.name = "flash"
+ mymob.flash.screen_loc = "1,1 to 15,15"
+ mymob.flash.layer = 17
+
+ mymob.zone_sel = new /obj/screen/zone_sel()
+ mymob.zone_sel.icon = ui_style
+ mymob.zone_sel.overlays.Cut()
+ mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]")
+
+ //Handle the gun settings buttons
+ mymob.gun_setting_icon = new /obj/screen/gun/mode(null)
+ if (mymob.client)
+ if (mymob.client.gun_mode) // If in aim mode, correct the sprite
+ mymob.gun_setting_icon.dir = 2
+ for(var/obj/item/weapon/gun/G in mymob) // If targeting someone, display other buttons
+ if (G.target)
+ mymob.item_use_icon = new /obj/screen/gun/item(null)
+ if (mymob.client.target_can_click)
+ mymob.item_use_icon.dir = 1
+ src.adding += mymob.item_use_icon
+ mymob.gun_move_icon = new /obj/screen/gun/move(null)
+ if (mymob.client.target_can_move)
+ mymob.gun_move_icon.dir = 1
+ mymob.gun_run_icon = new /obj/screen/gun/run(null)
+ if (mymob.client.target_can_run)
+ mymob.gun_run_icon.dir = 1
+ src.adding += mymob.gun_run_icon
+ src.adding += mymob.gun_move_icon
+
+ mymob.client.screen = null
+
+ mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.pressure, mymob.toxin, mymob.bodytemp, mymob.internals, mymob.fire, mymob.healths, mymob.pullin, mymob.blind, mymob.flash, mymob.gun_setting_icon) //, mymob.hands, mymob.rest, mymob.sleep, mymob.mach )
+ mymob.client.screen += src.adding + src.other
+
+ return
diff --git a/code/_onclick/hud/other_mobs.dm b/code/_onclick/hud/other_mobs.dm
new file mode 100644
index 00000000000..cd19e78d7e1
--- /dev/null
+++ b/code/_onclick/hud/other_mobs.dm
@@ -0,0 +1,35 @@
+
+/datum/hud/proc/unplayer_hud()
+ return
+
+/datum/hud/proc/ghost_hud()
+ return
+
+/datum/hud/proc/brain_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
+ mymob.blind = new /obj/screen()
+ mymob.blind.icon = 'icons/mob/screen1_full.dmi'
+ mymob.blind.icon_state = "blackimageoverlay"
+ mymob.blind.name = " "
+ mymob.blind.screen_loc = "1,1"
+ mymob.blind.layer = 0
+
+/datum/hud/proc/ai_hud()
+ return
+
+/datum/hud/proc/blob_hud(ui_style = 'icons/mob/screen1_Midnight.dmi')
+
+ blobpwrdisplay = new /obj/screen()
+ blobpwrdisplay.name = "blob power"
+ blobpwrdisplay.icon_state = "block"
+ blobpwrdisplay.screen_loc = ui_health
+ blobpwrdisplay.layer = 20
+
+ blobhealthdisplay = new /obj/screen()
+ blobhealthdisplay.name = "blob health"
+ blobhealthdisplay.icon_state = "block"
+ blobhealthdisplay.screen_loc = ui_internal
+ blobhealthdisplay.layer = 20
+
+ mymob.client.screen = null
+
+ mymob.client.screen += list(blobpwrdisplay, blobhealthdisplay)
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
new file mode 100644
index 00000000000..62cf2247c3a
--- /dev/null
+++ b/code/_onclick/hud/robot.dm
@@ -0,0 +1,170 @@
+/datum/hud/proc/robot_hud()
+
+ src.adding = list()
+ src.other = list()
+
+ var/obj/screen/using
+
+
+//Radio
+ using = new /obj/screen()
+ using.name = "radio"
+ using.dir = SOUTHWEST
+ using.icon = 'icons/mob/screen1_robot.dmi'
+ using.icon_state = "radio"
+ using.screen_loc = ui_movi
+ using.layer = 20
+ src.adding += using
+
+//Module select
+
+ using = new /obj/screen()
+ using.name = "module1"
+ using.dir = SOUTHWEST
+ using.icon = 'icons/mob/screen1_robot.dmi'
+ using.icon_state = "inv1"
+ using.screen_loc = ui_inv1
+ using.layer = 20
+ src.adding += using
+ mymob:inv1 = using
+
+ using = new /obj/screen()
+ using.name = "module2"
+ using.dir = SOUTHWEST
+ using.icon = 'icons/mob/screen1_robot.dmi'
+ using.icon_state = "inv2"
+ using.screen_loc = ui_inv2
+ using.layer = 20
+ src.adding += using
+ mymob:inv2 = using
+
+ using = new /obj/screen()
+ using.name = "module3"
+ using.dir = SOUTHWEST
+ using.icon = 'icons/mob/screen1_robot.dmi'
+ using.icon_state = "inv3"
+ using.screen_loc = ui_inv3
+ using.layer = 20
+ src.adding += using
+ mymob:inv3 = using
+
+//End of module select
+
+//Intent
+ using = new /obj/screen()
+ using.name = "act_intent"
+ using.dir = SOUTHWEST
+ using.icon = 'icons/mob/screen1_robot.dmi'
+ using.icon_state = (mymob.a_intent == "hurt" ? "harm" : mymob.a_intent)
+ using.screen_loc = ui_acti
+ using.layer = 20
+ src.adding += using
+ action_intent = using
+
+//Cell
+ mymob:cells = new /obj/screen()
+ mymob:cells.icon = 'icons/mob/screen1_robot.dmi'
+ mymob:cells.icon_state = "charge-empty"
+ mymob:cells.name = "cell"
+ mymob:cells.screen_loc = ui_toxin
+
+//Health
+ mymob.healths = new /obj/screen()
+ mymob.healths.icon = 'icons/mob/screen1_robot.dmi'
+ mymob.healths.icon_state = "health0"
+ mymob.healths.name = "health"
+ mymob.healths.screen_loc = ui_borg_health
+
+//Installed Module
+ mymob.hands = new /obj/screen()
+ mymob.hands.icon = 'icons/mob/screen1_robot.dmi'
+ mymob.hands.icon_state = "nomod"
+ mymob.hands.name = "module"
+ mymob.hands.screen_loc = ui_borg_module
+
+//Module Panel
+ using = new /obj/screen()
+ using.name = "panel"
+ using.icon = 'icons/mob/screen1_robot.dmi'
+ using.icon_state = "panel"
+ using.screen_loc = ui_borg_panel
+ using.layer = 19
+ src.adding += using
+
+//Store
+ mymob.throw_icon = new /obj/screen()
+ mymob.throw_icon.icon = 'icons/mob/screen1_robot.dmi'
+ mymob.throw_icon.icon_state = "store"
+ mymob.throw_icon.name = "store"
+ mymob.throw_icon.screen_loc = ui_borg_store
+
+//Temp
+ mymob.bodytemp = new /obj/screen()
+ mymob.bodytemp.icon_state = "temp0"
+ mymob.bodytemp.name = "body temperature"
+ mymob.bodytemp.screen_loc = ui_temp
+
+
+ mymob.oxygen = new /obj/screen()
+ mymob.oxygen.icon = 'icons/mob/screen1_robot.dmi'
+ mymob.oxygen.icon_state = "oxy0"
+ mymob.oxygen.name = "oxygen"
+ mymob.oxygen.screen_loc = ui_oxygen
+
+ mymob.fire = new /obj/screen()
+ mymob.fire.icon = 'icons/mob/screen1_robot.dmi'
+ mymob.fire.icon_state = "fire0"
+ mymob.fire.name = "fire"
+ mymob.fire.screen_loc = ui_fire
+
+ mymob.pullin = new /obj/screen()
+ mymob.pullin.icon = 'icons/mob/screen1_robot.dmi'
+ mymob.pullin.icon_state = "pull0"
+ mymob.pullin.name = "pull"
+ mymob.pullin.screen_loc = ui_borg_pull
+
+ mymob.blind = new /obj/screen()
+ mymob.blind.icon = 'icons/mob/screen1_full.dmi'
+ mymob.blind.icon_state = "blackimageoverlay"
+ mymob.blind.name = " "
+ mymob.blind.screen_loc = "1,1"
+ mymob.blind.layer = 0
+
+ mymob.flash = new /obj/screen()
+ mymob.flash.icon = 'icons/mob/screen1_robot.dmi'
+ mymob.flash.icon_state = "blank"
+ mymob.flash.name = "flash"
+ mymob.flash.screen_loc = "1,1 to 15,15"
+ mymob.flash.layer = 17
+
+ mymob.zone_sel = new /obj/screen/zone_sel()
+ mymob.zone_sel.icon = 'icons/mob/screen1_robot.dmi'
+ mymob.zone_sel.overlays.Cut()
+ mymob.zone_sel.overlays += image('icons/mob/zone_sel.dmi', "[mymob.zone_sel.selecting]")
+
+ //Handle the gun settings buttons
+ mymob.gun_setting_icon = new /obj/screen/gun/mode(null)
+ if (mymob.client)
+ if (mymob.client.gun_mode) // If in aim mode, correct the sprite
+ mymob.gun_setting_icon.dir = 2
+ for(var/obj/item/weapon/gun/G in mymob) // If targeting someone, display other buttons
+ if (G.target)
+ mymob.item_use_icon = new /obj/screen/gun/item(null)
+ if (mymob.client.target_can_click)
+ mymob.item_use_icon.dir = 1
+ src.adding += mymob.item_use_icon
+ mymob.gun_move_icon = new /obj/screen/gun/move(null)
+ if (mymob.client.target_can_move)
+ mymob.gun_move_icon.dir = 1
+ mymob.gun_run_icon = new /obj/screen/gun/run(null)
+ if (mymob.client.target_can_run)
+ mymob.gun_run_icon.dir = 1
+ src.adding += mymob.gun_run_icon
+ src.adding += mymob.gun_move_icon
+
+ mymob.client.screen = null
+
+ mymob.client.screen += list( mymob.throw_icon, mymob.zone_sel, mymob.oxygen, mymob.fire, mymob.hands, mymob.healths, mymob:cells, mymob.pullin, mymob.blind, mymob.flash, mymob.gun_setting_icon) //, mymob.rest, mymob.sleep, mymob.mach )
+ mymob.client.screen += src.adding + src.other
+
+ return
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
new file mode 100644
index 00000000000..54a7974d586
--- /dev/null
+++ b/code/_onclick/hud/screen_objects.dm
@@ -0,0 +1,444 @@
+/*
+ Screen objects
+ Todo: improve/re-implement
+
+ Screen objects are only used for the hud and should not appear anywhere "in-game".
+ They are used with the client/screen list and the screen_loc var.
+ For more information, see the byond documentation on the screen_loc and screen vars.
+*/
+/obj/screen
+ name = ""
+ icon = 'icons/mob/screen1.dmi'
+ layer = 20.0
+ unacidable = 1
+ var/obj/master = null //A reference to the object in the slot. Grabs or items, generally.
+ var/gun_click_time = -100 //I'm lazy.
+
+
+/obj/screen/text
+ icon = null
+ icon_state = null
+ mouse_opacity = 0
+ screen_loc = "CENTER-7,CENTER-7"
+ maptext_height = 480
+ maptext_width = 480
+
+
+/obj/screen/inventory
+ var/slot_id //The indentifier for the slot. It has nothing to do with ID cards.
+
+
+/obj/screen/close
+ name = "close"
+
+/obj/screen/close/Click()
+ if(master)
+ if(istype(master, /obj/item/weapon/storage))
+ var/obj/item/weapon/storage/S = master
+ S.close(usr)
+ return 1
+
+
+/obj/screen/item_action
+ var/obj/item/owner
+
+/obj/screen/item_action/Click()
+ if(!usr || !owner)
+ return 1
+ if(usr.next_move >= world.time)
+ return
+ usr.next_move = world.time + 10
+
+ if(usr.stat || usr.restrained() || usr.stunned || usr.lying)
+ return 1
+
+ if(!(owner in usr))
+ return 1
+
+ owner.ui_action_click()
+ return 1
+
+//This is the proc used to update all the action buttons. It just returns for all mob types except humans.
+/mob/proc/update_action_buttons()
+ return
+
+
+/obj/screen/grab
+ name = "grab"
+
+/obj/screen/grab/Click()
+ var/obj/item/weapon/grab/G = master
+ G.s_click(src)
+ return 1
+
+/obj/screen/grab/attack_hand()
+ return
+
+/obj/screen/grab/attackby()
+ return
+
+
+/obj/screen/storage
+ name = "storage"
+
+/obj/screen/storage/Click()
+ if(world.time <= usr.next_move)
+ return 1
+ if(usr.stat || usr.paralysis || usr.stunned || usr.weakened)
+ return 1
+ if(master)
+ var/obj/item/I = usr.get_active_hand()
+ if(I)
+ master.attackby(I, usr)
+ usr.next_move = world.time+2
+ return 1
+
+/obj/screen/gun
+ name = "gun"
+ icon = 'icons/mob/screen1.dmi'
+ master = null
+ dir = 2
+
+ move
+ name = "Allow Walking"
+ icon_state = "no_walk0"
+ screen_loc = ui_gun2
+
+ run
+ name = "Allow Running"
+ icon_state = "no_run0"
+ screen_loc = ui_gun3
+
+ item
+ name = "Allow Item Use"
+ icon_state = "no_item0"
+ screen_loc = ui_gun1
+
+ mode
+ name = "Toggle Gun Mode"
+ icon_state = "gun0"
+ screen_loc = ui_gun_select
+ //dir = 1
+
+/obj/screen/zone_sel
+ name = "damage zone"
+ icon_state = "zone_sel"
+ screen_loc = ui_zonesel
+ var/selecting = "chest"
+
+/obj/screen/zone_sel/Click(location, control,params)
+ var/list/PL = params2list(params)
+ var/icon_x = text2num(PL["icon-x"])
+ var/icon_y = text2num(PL["icon-y"])
+ var/old_selecting = selecting //We're only going to update_icon() if there's been a change
+
+ switch(icon_y)
+ if(1 to 3) //Feet
+ switch(icon_x)
+ if(10 to 15)
+ selecting = "r_foot"
+ if(17 to 22)
+ selecting = "l_foot"
+ else
+ return 1
+ if(4 to 9) //Legs
+ switch(icon_x)
+ if(10 to 15)
+ selecting = "r_leg"
+ if(17 to 22)
+ selecting = "l_leg"
+ else
+ return 1
+ if(10 to 13) //Hands and groin
+ switch(icon_x)
+ if(8 to 11)
+ selecting = "r_hand"
+ if(12 to 20)
+ selecting = "groin"
+ if(21 to 24)
+ selecting = "l_hand"
+ else
+ return 1
+ if(14 to 22) //Chest and arms to shoulders
+ switch(icon_x)
+ if(8 to 11)
+ selecting = "r_arm"
+ if(12 to 20)
+ selecting = "chest"
+ if(21 to 24)
+ selecting = "l_arm"
+ else
+ return 1
+ if(23 to 30) //Head, but we need to check for eye or mouth
+ if(icon_x in 12 to 20)
+ selecting = "head"
+ switch(icon_y)
+ if(23 to 24)
+ if(icon_x in 15 to 17)
+ selecting = "mouth"
+ if(26) //Eyeline, eyes are on 15 and 17
+ if(icon_x in 14 to 18)
+ selecting = "eyes"
+ if(25 to 27)
+ if(icon_x in 15 to 17)
+ selecting = "eyes"
+
+ if(old_selecting != selecting)
+ update_icon()
+ return 1
+
+/obj/screen/zone_sel/update_icon()
+ overlays.Cut()
+ overlays += image('icons/mob/zone_sel.dmi', "[selecting]")
+
+
+/obj/screen/Click(location, control, params)
+ if(!usr) return 1
+
+ switch(name)
+ if("toggle")
+ if(usr.hud_used.inventory_shown)
+ usr.hud_used.inventory_shown = 0
+ usr.client.screen -= usr.hud_used.other
+ else
+ usr.hud_used.inventory_shown = 1
+ usr.client.screen += usr.hud_used.other
+
+ usr.hud_used.hidden_inventory_update()
+
+ if("equip")
+ if(ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ H.quick_equip()
+
+ if("resist")
+ if(isliving(usr))
+ var/mob/living/L = usr
+ L.resist()
+
+ if("mov_intent")
+ if(iscarbon(usr))
+ var/mob/living/carbon/C = usr
+ if(C.legcuffed)
+ C << "You are legcuffed! You cannot run until you get [C.legcuffed] removed!"
+ C.m_intent = "walk" //Just incase
+ C.hud_used.move_intent.icon_state = "walking"
+ return 1
+ switch(usr.m_intent)
+ if("run")
+ usr.m_intent = "walk"
+ usr.hud_used.move_intent.icon_state = "walking"
+ if("walk")
+ usr.m_intent = "run"
+ usr.hud_used.move_intent.icon_state = "running"
+ if(istype(usr,/mob/living/carbon/alien/humanoid))
+ usr.update_icons()
+ if("m_intent")
+ if(!usr.m_int)
+ switch(usr.m_intent)
+ if("run")
+ usr.m_int = "13,14"
+ if("walk")
+ usr.m_int = "14,14"
+ if("face")
+ usr.m_int = "15,14"
+ else
+ usr.m_int = null
+ if("walk")
+ usr.m_intent = "walk"
+ usr.m_int = "14,14"
+ if("face")
+ usr.m_intent = "face"
+ usr.m_int = "15,14"
+ if("run")
+ usr.m_intent = "run"
+ usr.m_int = "13,14"
+ if("Reset Machine")
+ usr.unset_machine()
+ if("internal")
+ if(iscarbon(usr))
+ var/mob/living/carbon/C = usr
+ if(!C.stat && !C.stunned && !C.paralysis && !C.restrained())
+ if(C.internal)
+ C.internal = null
+ C << "No longer running on internals."
+ if(C.internals)
+ C.internals.icon_state = "internal0"
+ else
+ if(!istype(C.wear_mask, /obj/item/clothing/mask))
+ C << "You are not wearing a mask."
+ return 1
+ else
+ if(istype(C.l_hand, /obj/item/weapon/tank))
+ C << "You are now running on internals from the [C.l_hand] on your left hand."
+ C.internal = C.l_hand
+ else if(istype(C.r_hand, /obj/item/weapon/tank))
+ C << "You are now running on internals from the [C.r_hand] on your right hand."
+ C.internal = C.r_hand
+ else if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ if(istype(H.s_store, /obj/item/weapon/tank))
+ H << "You are now running on internals from the [H.s_store] on your [H.wear_suit]."
+ H.internal = H.s_store
+ else if(istype(H.belt, /obj/item/weapon/tank))
+ H << "You are now running on internals from the [H.belt] on your belt."
+ H.internal = H.belt
+ else if(istype(H.l_store, /obj/item/weapon/tank))
+ H << "You are now running on internals from the [H.l_store] in your left pocket."
+ H.internal = H.l_store
+ else if(istype(H.r_store, /obj/item/weapon/tank))
+ H << "You are now running on internals from the [H.r_store] in your right pocket."
+ H.internal = H.r_store
+
+ //Seperate so CO2 jetpacks are a little less cumbersome.
+ if(!C.internal && istype(C.back, /obj/item/weapon/tank))
+ C << "You are now running on internals from the [C.back] on your back."
+ C.internal = C.back
+
+ if(C.internal)
+ if(C.internals)
+ C.internals.icon_state = "internal1"
+ else
+ C << "You don't have an oxygen tank."
+ if("act_intent")
+ usr.a_intent_change("right")
+ if("help")
+ usr.a_intent = "help"
+ usr.hud_used.action_intent.icon_state = "intent_help"
+ if("harm")
+ usr.a_intent = "hurt"
+ usr.hud_used.action_intent.icon_state = "intent_hurt"
+ if("grab")
+ usr.a_intent = "grab"
+ usr.hud_used.action_intent.icon_state = "intent_grab"
+ if("disarm")
+ usr.a_intent = "disarm"
+ usr.hud_used.action_intent.icon_state = "intent_disarm"
+
+ if("pull")
+ usr.stop_pulling()
+ if("throw")
+ if(!usr.stat && isturf(usr.loc) && !usr.restrained())
+ usr:toggle_throw_mode()
+ if("drop")
+ usr.drop_item_v()
+
+ if("module")
+ if(issilicon(usr))
+ if(usr:module)
+ return 1
+ usr:pick_module()
+
+ if("radio")
+ if(issilicon(usr))
+ usr:radio_menu()
+ if("panel")
+ if(issilicon(usr))
+ usr:installed_modules()
+
+ if("store")
+ if(issilicon(usr))
+ usr:uneq_active()
+
+ if("module1")
+ if(istype(usr, /mob/living/silicon/robot))
+ usr:toggle_module(1)
+
+ if("module2")
+ if(istype(usr, /mob/living/silicon/robot))
+ usr:toggle_module(2)
+
+ if("module3")
+ if(istype(usr, /mob/living/silicon/robot))
+ usr:toggle_module(3)
+
+ if("Allow Walking")
+ if(gun_click_time > world.time - 30) //give them 3 seconds between mode changes.
+ return
+ if(!istype(usr.equipped(),/obj/item/weapon/gun))
+ usr << "You need your gun in your active hand to do that!"
+ return
+ usr.client.AllowTargetMove()
+ gun_click_time = world.time
+
+ if("Disallow Walking")
+ if(gun_click_time > world.time - 30) //give them 3 seconds between mode changes.
+ return
+ if(!istype(usr.equipped(),/obj/item/weapon/gun))
+ usr << "You need your gun in your active hand to do that!"
+ return
+ usr.client.AllowTargetMove()
+ gun_click_time = world.time
+
+ if("Allow Running")
+ if(gun_click_time > world.time - 30) //give them 3 seconds between mode changes.
+ return
+ if(!istype(usr.equipped(),/obj/item/weapon/gun))
+ usr << "You need your gun in your active hand to do that!"
+ return
+ usr.client.AllowTargetRun()
+ gun_click_time = world.time
+
+ if("Disallow Running")
+ if(gun_click_time > world.time - 30) //give them 3 seconds between mode changes.
+ return
+ if(!istype(usr.equipped(),/obj/item/weapon/gun))
+ usr << "You need your gun in your active hand to do that!"
+ return
+ usr.client.AllowTargetRun()
+ gun_click_time = world.time
+
+ if("Allow Item Use")
+ if(gun_click_time > world.time - 30) //give them 3 seconds between mode changes.
+ return
+ if(!istype(usr.equipped(),/obj/item/weapon/gun))
+ usr << "You need your gun in your active hand to do that!"
+ return
+ usr.client.AllowTargetClick()
+ gun_click_time = world.time
+
+
+ if("Disallow Item Use")
+ if(gun_click_time > world.time - 30) //give them 3 seconds between mode changes.
+ return
+ if(!istype(usr.equipped(),/obj/item/weapon/gun))
+ usr << "You need your gun in your active hand to do that!"
+ return
+ usr.client.AllowTargetClick()
+ gun_click_time = world.time
+
+ if("Toggle Gun Mode")
+ usr.client.ToggleGunMode()
+
+ else
+ return 0
+ return 1
+
+/obj/screen/inventory/Click()
+ // At this point in client Click() code we have passed the 1/10 sec check and little else
+ // We don't even know if it's a middle click
+ if(world.time <= usr.next_move)
+ return 1
+ if(usr.stat || usr.paralysis || usr.stunned || usr.weakened)
+ return 1
+ switch(name)
+ if("r_hand")
+ if(iscarbon(usr))
+ var/mob/living/carbon/C = usr
+ C.activate_hand("r")
+ usr.next_move = world.time+2
+ if("l_hand")
+ if(iscarbon(usr))
+ var/mob/living/carbon/C = usr
+ C.activate_hand("l")
+ usr.next_move = world.time+2
+ if("swap")
+ usr:swap_hand()
+ if("hand")
+ usr:swap_hand()
+ else
+ if(usr.attack_ui(slot_id))
+ usr.update_inv_l_hand(0)
+ usr.update_inv_r_hand(0)
+ usr.next_move = world.time+6
+ return 1
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
new file mode 100644
index 00000000000..11022a232ac
--- /dev/null
+++ b/code/_onclick/item_attack.dm
@@ -0,0 +1,165 @@
+
+// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
+/obj/item/proc/attack_self(mob/user)
+ return
+
+// No comment
+/atom/proc/attackby(obj/item/W, mob/user)
+ return
+/atom/movable/attackby(obj/item/W, mob/user)
+ if(!(W.flags&NOBLUDGEON))
+ visible_message("[src] has been hit by [user] with [W].")
+
+/mob/living/attackby(obj/item/I, mob/user)
+ if(istype(I) && ismob(user))
+ I.attack(src, user)
+
+
+// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
+// Click parameters is the params string from byond Click() code, see that documentation.
+/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+ return
+
+
+/obj/item/proc/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
+
+ if (!istype(M)) // not sure if this is the right thing...
+ return
+ var/messagesource = M
+
+ if (can_operate(M)) //Checks if mob is lying down on table for surgery
+ if (do_surgery(M,user,src))
+ return
+
+ if (istype(M,/mob/living/carbon/brain))
+ messagesource = M:container
+ if (hitsound)
+ playsound(loc, hitsound, 50, 1, -1)
+ /////////////////////////
+ user.lastattacked = M
+ M.lastattacker = user
+
+ user.attack_log += "\[[time_stamp()]\] Attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])"
+ M.attack_log += "\[[time_stamp()]\] Attacked by [user.name] ([user.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])"
+ log_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(damtype)])" )
+
+ //spawn(1800) // this wont work right
+ // M.lastattacker = null
+ /////////////////////////
+
+ var/power = force
+ if(HULK in user.mutations)
+ power *= 2
+
+ if(!istype(M, /mob/living/carbon/human))
+ if(istype(M, /mob/living/carbon/slime))
+ var/mob/living/carbon/slime/slime = M
+ if(prob(25))
+ user << "\red [src] passes right through [M]!"
+ return
+
+ if(power > 0)
+ slime.attacked += 10
+
+ if(slime.Discipline && prob(50)) // wow, buddy, why am I getting attacked??
+ slime.Discipline = 0
+
+ if(power >= 3)
+ if(istype(slime, /mob/living/carbon/slime/adult))
+ if(prob(5 + round(power/2)))
+
+ if(slime.Victim)
+ if(prob(80) && !slime.client)
+ slime.Discipline++
+ slime.Victim = null
+ slime.anchored = 0
+
+ spawn()
+ if(slime)
+ slime.SStun = 1
+ sleep(rand(5,20))
+ if(slime)
+ slime.SStun = 0
+
+ spawn(0)
+ if(slime)
+ slime.canmove = 0
+ step_away(slime, user)
+ if(prob(25 + power))
+ sleep(2)
+ if(slime && user)
+ step_away(slime, user)
+ slime.canmove = 1
+
+ else
+ if(prob(10 + power*2))
+ if(slime)
+ if(slime.Victim)
+ if(prob(80) && !slime.client)
+ slime.Discipline++
+
+ if(slime.Discipline == 1)
+ slime.attacked = 0
+
+ spawn()
+ if(slime)
+ slime.SStun = 1
+ sleep(rand(5,20))
+ if(slime)
+ slime.SStun = 0
+
+ slime.Victim = null
+ slime.anchored = 0
+
+
+ spawn(0)
+ if(slime && user)
+ step_away(slime, user)
+ slime.canmove = 0
+ if(prob(25 + power*4))
+ sleep(2)
+ if(slime && user)
+ step_away(slime, user)
+ slime.canmove = 1
+
+
+ var/showname = "."
+ if(user)
+ showname = " by [user]."
+ if(!(user in viewers(M, null)))
+ showname = "."
+
+ for(var/mob/O in viewers(messagesource, null))
+ if(attack_verb.len)
+ O.show_message("\red [M] has been [pick(attack_verb)] with [src][showname] ", 1)
+ else
+ O.show_message("\red [M] has been attacked with [src][showname] ", 1)
+
+ if(!showname && user)
+ if(user.client)
+ user << "\red You attack [M] with [src]. "
+
+
+
+ if(istype(M, /mob/living/carbon/human))
+ M:attacked_by(src, user, def_zone)
+ else
+ switch(damtype)
+ if("brute")
+ if(istype(src, /mob/living/carbon/slime))
+ M.adjustBrainLoss(power)
+
+ else
+
+ M.take_organ_damage(power)
+ if (prob(33)) // Added blood for whacking non-humans too
+ var/turf/location = M.loc
+ if (istype(location, /turf/simulated))
+ location:add_blood_floor(M)
+ if("fire")
+ if (!(COLD_RESISTANCE in M.mutations))
+ M.take_organ_damage(0, power)
+ M << "Aargh it burns!"
+ M.updatehealth()
+ add_fingerprint(user)
+ return 1
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
new file mode 100644
index 00000000000..c326d83df41
--- /dev/null
+++ b/code/_onclick/observer.dm
@@ -0,0 +1,104 @@
+/client/var/inquisitive_ghost = 1
+/mob/dead/observer/verb/toggle_inquisition() // warning: unexpected inquisition
+ set name = "Toggle Inquisitiveness"
+ set desc = "Sets whether your ghost examines everything on click by default"
+ set category = "Ghost"
+ if(!client) return
+ client.inquisitive_ghost = !client.inquisitive_ghost
+ if(client.inquisitive_ghost)
+ src << "\blue You will now examine everything you click on."
+ else
+ src << "\blue You will no longer examine things you click on."
+
+/mob/dead/observer/DblClickOn(var/atom/A, var/params)
+ if(client.buildmode)
+ build_click(src, client.buildmode, params, A)
+ return
+ if(can_reenter_corpse && mind && mind.current)
+ if(A == mind.current || (mind.current in A)) // double click your corpse or whatever holds it
+ reenter_corpse() // (cloning scanner, body bag, closet, mech, etc)
+ return // seems legit.
+
+ // Things you might plausibly want to follow
+ if((ismob(A) && A != src) || istype(A,/obj/machinery/bot) || istype(A,/obj/machinery/singularity))
+ ManualFollow(A)
+
+ // Otherwise jump
+ else
+ loc = get_turf(A)
+
+/mob/dead/observer/ClickOn(var/atom/A, var/params)
+ if(client.buildmode)
+ build_click(src, client.buildmode, params, A)
+ return
+ if(world.time <= next_move) return
+ next_move = world.time + 8
+ // You are responsible for checking config.ghost_interaction when you override this function
+ // Not all of them require checking, see below
+ A.attack_ghost(src)
+
+// This is the ghost's follow verb with an argument
+/mob/dead/observer/proc/ManualFollow(var/atom/target)
+ following = target
+ if(target)
+ src << "\blue Now following [target]"
+ spawn(0)
+ var/turf/pos = get_turf(src)
+ while(loc == pos && target && following == target)
+
+ var/turf/T = get_turf(target)
+ if(!T)
+ break
+ if(following != target)
+ break
+ if(!client)
+ break
+ loc = T
+ pos = loc
+ sleep(15)
+ following = null
+
+// Oh by the way this didn't work with old click code which is why clicking shit didn't spam you
+/atom/proc/attack_ghost(mob/dead/observer/user as mob)
+ if(user.client && user.client.inquisitive_ghost)
+ examine()
+ return
+
+// ---------------------------------------
+// And here are some good things for free:
+// Now you can click through portals, wormholes, gateways, and teleporters while observing. -Sayu
+
+/obj/machinery/teleport/hub/attack_ghost(mob/user as mob)
+ var/atom/l = loc
+ var/obj/machinery/computer/teleporter/com = locate(/obj/machinery/computer/teleporter, locate(l.x - 2, l.y, l.z))
+ if(com.locked)
+ user.loc = get_turf(com.locked)
+
+/obj/effect/portal/attack_ghost(mob/user as mob)
+ if(target)
+ user.loc = get_turf(target)
+
+/obj/machinery/gateway/centerstation/attack_ghost(mob/user as mob)
+ if(awaygate)
+ user.loc = awaygate.loc
+ else
+ user << "[src] has no destination."
+
+/obj/machinery/gateway/centeraway/attack_ghost(mob/user as mob)
+ if(stationgate)
+ user.loc = stationgate.loc
+ else
+ user << "[src] has no destination."
+
+// -------------------------------------------
+// This was supposed to be used by adminghosts
+// I think it is a *terrible* idea
+// but I'm leaving it here anyway
+// commented out, of course.
+/*
+/atom/proc/attack_admin(mob/user as mob)
+ if(!user || !user.client || !user.client.holder)
+ return
+ attack_hand(user)
+
+*/
diff --git a/code/_onclick/oldcode.dm b/code/_onclick/oldcode.dm
new file mode 100644
index 00000000000..2d52a26390a
--- /dev/null
+++ b/code/_onclick/oldcode.dm
@@ -0,0 +1,376 @@
+/atom/DblClick(location, control, params) //TODO: DEFERRED: REWRITE
+ if(!usr) return
+
+ // ------- TIME SINCE LAST CLICK -------
+ if (world.time <= usr:lastDblClick+1)
+ return
+ else
+ usr:lastDblClick = world.time
+
+ //Putting it here for now. It diverts stuff to the mech clicking procs. Putting it here stops us drilling items in our inventory Carn
+ if(istype(usr.loc,/obj/mecha))
+ if(usr.client && (src in usr.client.screen))
+ return
+ var/obj/mecha/Mech = usr.loc
+ Mech.click_action(src,usr)
+ return
+
+ // ------- DIR CHANGING WHEN CLICKING ------
+ if( iscarbon(usr) && !usr.buckled )
+ if( src.x && src.y && usr.x && usr.y )
+ var/dx = src.x - usr.x
+ var/dy = src.y - usr.y
+
+ if(dy || dx)
+ if(abs(dx) < abs(dy))
+ if(dy > 0) usr.dir = NORTH
+ else usr.dir = SOUTH
+ else
+ if(dx > 0) usr.dir = EAST
+ else usr.dir = WEST
+ else
+ if(pixel_y > 16) usr.dir = NORTH
+ else if(pixel_y < -16) usr.dir = SOUTH
+ else if(pixel_x > 16) usr.dir = EAST
+ else if(pixel_x < -16) usr.dir = WEST
+
+
+
+
+ // ------- AI -------
+ else if (istype(usr, /mob/living/silicon/ai))
+ var/mob/living/silicon/ai/ai = usr
+ if (ai.control_disabled)
+ return
+
+ // ------- CYBORG -------
+ else if (istype(usr, /mob/living/silicon/robot))
+ var/mob/living/silicon/robot/bot = usr
+ if (bot.lockcharge) return
+ ..()
+
+
+ // ------- SHIFT-CLICK -------
+
+ if(params)
+ var/parameters = params2list(params)
+
+ if(parameters["shift"]){
+ if(!isAI(usr))
+ ShiftClick(usr)
+ else
+ AIShiftClick(usr)
+ return
+ }
+
+ // ------- ALT-CLICK -------
+
+ if(parameters["alt"]){
+ if(!isAI(usr))
+ AltClick(usr)
+ else
+ AIAltClick(usr)
+ return
+ }
+
+ // ------- CTRL-CLICK -------
+
+ if(parameters["ctrl"]){
+ if(!isAI(usr))
+ CtrlClick(usr)
+ else
+ AICtrlClick(usr)
+ return
+ }
+
+ // ------- MIDDLE-CLICK -------
+
+ if(parameters["middle"]){
+ if(!isAI(usr))
+ MiddleClick(usr)
+ return
+ }
+
+ // ------- THROW -------
+ if(usr.in_throw_mode)
+ return usr:throw_item(src)
+
+ // ------- ITEM IN HAND DEFINED -------
+ var/obj/item/W = usr.get_active_hand()
+/* Now handled by get_active_hand()
+ // ------- ROBOT -------
+ if(istype(usr, /mob/living/silicon/robot))
+ if(!isnull(usr:module_active))
+ W = usr:module_active
+ else
+ W = null
+*/
+ // ------- ATTACK SELF -------
+ if (W == src && usr.stat == 0)
+ W.attack_self(usr)
+ if(usr.hand)
+ usr.update_inv_l_hand(0) //update in-hand overlays
+ else
+ usr.update_inv_r_hand(0)
+ return
+
+ // ------- PARALYSIS, STUN, WEAKENED, DEAD, (And not AI) -------
+ if (((usr.paralysis || usr.stunned || usr.weakened) && !istype(usr, /mob/living/silicon/ai)) || usr.stat != 0)
+ return
+
+ // ------- CLICKING STUFF IN CONTAINERS -------
+ if ((!( src in usr.contents ) && (((!( isturf(src) ) && (!( isturf(src.loc) ) && (src.loc && !( isturf(src.loc.loc) )))) || !( isturf(usr.loc) )) && (src.loc != usr.loc && (!( istype(src, /obj/screen) ) && !( usr.contents.Find(src.loc) ))))))
+ if (istype(usr, /mob/living/silicon/ai))
+ var/mob/living/silicon/ai/ai = usr
+ if (ai.control_disabled || ai.malfhacking)
+ return
+ else
+ return
+
+ // ------- 1 TILE AWAY -------
+ var/t5
+ // ------- AI CAN CLICK ANYTHING -------
+ if(istype(usr, /mob/living/silicon/ai))
+ t5 = 1
+ // ------- CYBORG CAN CLICK ANYTHING WHEN NOT HOLDING STUFF -------
+ else if(istype(usr, /mob/living/silicon/robot) && !W)
+ t5 = 1
+ else
+ t5 = in_range(src, usr) || src.loc == usr
+
+// world << "according to dblclick(), t5 is [t5]"
+
+ // ------- ACTUALLY DETERMINING STUFF -------
+ if (((t5 || (W && (W.flags & USEDELAY))) && !( istype(src, /obj/screen) )))
+
+ // ------- ( CAN USE ITEM OR HAS 1 SECOND USE DELAY ) AND NOT CLICKING ON SCREEN -------
+
+ if (usr.next_move < world.time)
+ usr.prev_move = usr.next_move
+ usr.next_move = world.time + 10
+ else
+ // ------- ALREADY USED ONE ITEM WITH USE DELAY IN THE PREVIOUS SECOND -------
+ return
+
+ // ------- DELAY CHECK PASSED -------
+
+ if ((src.loc && (get_dist(src, usr) < 2 || src.loc == usr.loc)))
+
+ // ------- CLICKED OBJECT EXISTS IN GAME WORLD, DISTANCE FROM PERSON TO OBJECT IS 1 SQUARE OR THEY'RE ON THE SAME SQUARE -------
+
+ var/direct = get_dir(usr, src)
+ var/obj/item/weapon/dummy/D = new /obj/item/weapon/dummy( usr.loc )
+ var/ok = 0
+ if ( (direct - 1) & direct)
+
+ // ------- CLICKED OBJECT IS LOCATED IN A DIAGONAL POSITION FROM THE PERSON -------
+
+ var/turf/Step_1
+ var/turf/Step_2
+ switch(direct)
+ if(5.0)
+ Step_1 = get_step(usr, NORTH)
+ Step_2 = get_step(usr, EAST)
+
+ if(6.0)
+ Step_1 = get_step(usr, SOUTH)
+ Step_2 = get_step(usr, EAST)
+
+ if(9.0)
+ Step_1 = get_step(usr, NORTH)
+ Step_2 = get_step(usr, WEST)
+
+ if(10.0)
+ Step_1 = get_step(usr, SOUTH)
+ Step_2 = get_step(usr, WEST)
+
+ else
+ if(Step_1 && Step_2)
+
+ // ------- BOTH CARDINAL DIRECTIONS OF THE DIAGONAL EXIST IN THE GAME WORLD -------
+
+ var/check_1 = 0
+ var/check_2 = 0
+ if(step_to(D, Step_1))
+ check_1 = 1
+ for(var/obj/border_obstacle in Step_1)
+ if(border_obstacle.flags & ON_BORDER)
+ if(!border_obstacle.CheckExit(D, src))
+ check_1 = 0
+ // ------- YOU TRIED TO CLICK ON AN ITEM THROUGH A WINDOW (OR SIMILAR THING THAT LIMITS ON BORDERS) ON ONE OF THE DIRECITON TILES -------
+ for(var/obj/border_obstacle in get_turf(src))
+ if((border_obstacle.flags & ON_BORDER) && (src != border_obstacle))
+ if(!border_obstacle.CanPass(D, D.loc, 1, 0))
+ // ------- YOU TRIED TO CLICK ON AN ITEM THROUGH A WINDOW (OR SIMILAR THING THAT LIMITS ON BORDERS) ON THE TILE YOU'RE ON -------
+ check_1 = 0
+
+ D.loc = usr.loc
+ if(step_to(D, Step_2))
+ check_2 = 1
+
+ for(var/obj/border_obstacle in Step_2)
+ if(border_obstacle.flags & ON_BORDER)
+ if(!border_obstacle.CheckExit(D, src))
+ check_2 = 0
+ for(var/obj/border_obstacle in get_turf(src))
+ if((border_obstacle.flags & ON_BORDER) && (src != border_obstacle))
+ if(!border_obstacle.CanPass(D, D.loc, 1, 0))
+ check_2 = 0
+
+
+ if(check_1 || check_2)
+ ok = 1
+ // ------- YOU CAN REACH THE ITEM THROUGH AT LEAST ONE OF THE TWO DIRECTIONS. GOOD. -------
+
+ /*
+ More info:
+ If you're trying to click an item in the north-east of your mob, the above section of code will first check if tehre's a tile to the north or you and to the east of you
+ These two tiles are Step_1 and Step_2. After this, a new dummy object is created on your location. It then tries to move to Step_1, If it succeeds, objects on the turf you're on and
+ the turf that Step_1 is are checked for items which have the ON_BORDER flag set. These are itmes which limit you on only one tile border. Windows, for the most part.
+ CheckExit() and CanPass() are use to determine this. The dummy object is then moved back to your location and it tries to move to Step_2. Same checks are performed here.
+ If at least one of the two checks succeeds, it means you can reach the item and ok is set to 1.
+ */
+ else
+ // ------- OBJECT IS ON A CARDINAL TILE (NORTH, SOUTH, EAST OR WEST OR THE TILE YOU'RE ON) -------
+ if(loc == usr.loc)
+ ok = 1
+ // ------- OBJECT IS ON THE SAME TILE AS YOU -------
+ else
+ ok = 1
+
+ //Now, check objects to block exit that are on the border
+ for(var/obj/border_obstacle in usr.loc)
+ if(border_obstacle.flags & ON_BORDER)
+ if(!border_obstacle.CheckExit(D, src))
+ ok = 0
+
+ //Next, check objects to block entry that are on the border
+ for(var/obj/border_obstacle in get_turf(src))
+ if((border_obstacle.flags & ON_BORDER) && (src != border_obstacle))
+ if(!border_obstacle.CanPass(D, D.loc, 1, 0))
+ ok = 0
+ /*
+ See the previous More info, for... more info...
+ */
+
+ //del(D)
+ // Garbage Collect Dummy
+ D.loc = null
+ D = null
+
+ // ------- DUMMY OBJECT'S SERVED IT'S PURPOSE, IT'S REWARDED WITH A SWIFT DELETE -------
+ if (!( ok ))
+ // ------- TESTS ABOVE DETERMINED YOU CANNOT REACH THE TILE -------
+ return 0
+
+ if (!( usr.restrained() || (usr.lying && usr.buckled!=src) ))
+ // ------- YOU ARE NOT REASTRAINED -------
+
+ if (W)
+ // ------- YOU HAVE AN ITEM IN YOUR HAND - HANDLE ATTACKBY AND AFTERATTACK -------
+ var/ignoreAA = 0 //Ignore afterattack(). Surgery uses this.
+ if (t5)
+ ignoreAA = src.attackby(W, usr)
+ if (W && !ignoreAA)
+ W.afterattack(src, usr, (t5 ? 1 : 0), params)
+
+ else
+ // ------- YOU DO NOT HAVE AN ITEM IN YOUR HAND -------
+ if (istype(usr, /mob/living/carbon/human))
+ // ------- YOU ARE HUMAN -------
+ src.attack_hand(usr, usr.hand)
+ else
+ // ------- YOU ARE NOT HUMAN. WHAT ARE YOU - DETERMINED HERE AND PROPER ATTACK_MOBTYPE CALLED -------
+ if (istype(usr, /mob/living/carbon/monkey))
+ src.attack_paw(usr, usr.hand)
+ else if (istype(usr, /mob/living/carbon/alien/humanoid))
+ if(usr.m_intent == "walk" && istype(usr, /mob/living/carbon/alien/humanoid/hunter))
+ usr.m_intent = "run"
+ usr.hud_used.move_intent.icon_state = "running"
+ usr.update_icons()
+ src.attack_alien(usr, usr.hand)
+ else if (istype(usr, /mob/living/carbon/alien/larva))
+ src.attack_larva(usr)
+ else if (istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot))
+ src.attack_ai(usr, usr.hand)
+ else if(istype(usr, /mob/living/carbon/slime))
+ src.attack_slime(usr)
+ else if(istype(usr, /mob/living/simple_animal))
+ src.attack_animal(usr)
+ else
+ // ------- YOU ARE RESTRAINED. DETERMINE WHAT YOU ARE AND ATTACK WITH THE PROPER HAND_X PROC -------
+ if (istype(usr, /mob/living/carbon/human))
+ src.hand_h(usr, usr.hand)
+ else if (istype(usr, /mob/living/carbon/monkey))
+ src.hand_p(usr, usr.hand)
+ else if (istype(usr, /mob/living/carbon/alien/humanoid))
+ src.hand_al(usr, usr.hand)
+ else if (istype(usr, /mob/living/silicon/ai) || istype(usr, /mob/living/silicon/robot))
+ src.hand_a(usr, usr.hand)
+
+ else
+ // ------- ITEM INACESSIBLE OR CLICKING ON SCREEN -------
+ if (istype(src, /obj/screen))
+ // ------- IT'S THE HUD YOU'RE CLICKING ON -------
+ usr.prev_move = usr.next_move
+ usr:lastDblClick = world.time + 2
+ if (usr.next_move < world.time)
+ usr.next_move = world.time + 2
+ else
+ return
+
+ // ------- 2 DECISECOND DELAY FOR CLICKING PASSED -------
+
+ if (!( usr.restrained() ))
+
+ // ------- YOU ARE NOT RESTRAINED -------
+ if ((W && !( istype(src, /obj/screen) )))
+ // ------- IT SHOULD NEVER GET TO HERE, DUE TO THE ISTYPE(SRC, /OBJ/SCREEN) FROM PREVIOUS IF-S - I TESTED IT WITH A DEBUG OUTPUT AND I COULDN'T GET THIST TO SHOW UP. -------
+ src.attackby(W, usr)
+ if (W)
+ W.afterattack(src, usr,, params)
+ else
+ // ------- YOU ARE NOT RESTRAINED, AND ARE CLICKING A HUD OBJECT -------
+ if (istype(usr, /mob/living/carbon/human))
+ src.attack_hand(usr, usr.hand)
+ else if (istype(usr, /mob/living/carbon/monkey))
+ src.attack_paw(usr, usr.hand)
+ else if (istype(usr, /mob/living/carbon/alien/humanoid))
+ src.attack_alien(usr, usr.hand)
+ else
+ // ------- YOU ARE RESTRAINED CLICKING ON A HUD OBJECT -------
+ if (istype(usr, /mob/living/carbon/human))
+ src.hand_h(usr, usr.hand)
+ else if (istype(usr, /mob/living/carbon/monkey))
+ src.hand_p(usr, usr.hand)
+ else if (istype(usr, /mob/living/carbon/alien/humanoid))
+ src.hand_al(usr, usr.hand)
+ else
+ // ------- YOU ARE CLICKING ON AN OBJECT THAT'S INACCESSIBLE TO YOU AND IS NOT YOUR HUD -------
+ if((LASER in usr:mutations) && usr:a_intent == "harm" && world.time >= usr.next_move)
+ // ------- YOU HAVE THE LASER MUTATION, YOUR INTENT SET TO HURT AND IT'S BEEN MORE THAN A DECISECOND SINCE YOU LAS TATTACKED -------
+
+ var/turf/T = get_turf(usr)
+ var/turf/U = get_turf(src)
+
+
+ if(istype(usr, /mob/living/carbon/human))
+ usr:nutrition -= rand(1,5)
+ usr:handle_regular_hud_updates()
+
+ var/obj/item/projectile/beam/A = new /obj/item/projectile/beam( usr.loc )
+ A.icon = 'icons/effects/genetics.dmi'
+ A.icon_state = "eyelasers"
+ playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1)
+
+ A.firer = usr
+ A.def_zone = usr:get_organ_target()
+ A.original = src
+ A.current = T
+ A.yo = U.y - T.y
+ A.xo = U.x - T.x
+ spawn( 1 )
+ A.process()
+
+ usr.next_move = world.time + 6
+ return
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
new file mode 100644
index 00000000000..04612128eff
--- /dev/null
+++ b/code/_onclick/other_mobs.dm
@@ -0,0 +1,124 @@
+/*
+ Humans:
+ Adds an exception for gloves, to allow special glove types like the ninja ones.
+
+ Otherwise pretty standard.
+*/
+/mob/living/carbon/human/UnarmedAttack(var/atom/A, var/proximity)
+ var/obj/item/clothing/gloves/G = gloves // not typecast specifically enough in defines
+
+ // Special glove functions:
+ // If the gloves do anything, have them return 1 to stop
+ // normal attack_hand() here.
+ if(proximity && istype(G) && G.Touch(A,1))
+ return
+
+ A.attack_hand(src)
+/atom/proc/attack_hand(mob/user as mob)
+ return
+
+/mob/living/carbon/human/RestrainedClickOn(var/atom/A)
+ return
+
+/mob/living/carbon/human/RangedAttack(var/atom/A)
+ if(!gloves && !mutations.len) return
+ var/obj/item/clothing/gloves/G = gloves
+ if((LASER in mutations) && a_intent == "harm")
+ LaserEyes(A) // moved into a proc below
+
+ else if(istype(G) && G.Touch(A,0)) // for magic gloves
+ return
+
+ else if(TK in mutations)
+ switch(get_dist(src,A))
+ if(1 to 5) // not adjacent may mean blocked by window
+ next_move += 2
+ if(5 to 7)
+ next_move += 5
+ if(8 to 15)
+ next_move += 10
+ if(16 to 128)
+ return
+ A.attack_tk(src)
+
+/*
+ Animals & All Unspecified
+*/
+/mob/living/UnarmedAttack(var/atom/A)
+ A.attack_animal(src)
+/atom/proc/attack_animal(mob/user as mob)
+ return
+/mob/living/RestrainedClickOn(var/atom/A)
+ return
+
+/*
+ Monkeys
+*/
+/mob/living/carbon/monkey/UnarmedAttack(var/atom/A)
+ A.attack_paw(src)
+/atom/proc/attack_paw(mob/user as mob)
+ return
+
+/*
+ Monkey RestrainedClickOn() was apparently the
+ one and only use of all of the restrained click code
+ (except to stop you from doing things while handcuffed);
+ moving it here instead of various hand_p's has simplified
+ things considerably
+*/
+/mob/living/carbon/monkey/RestrainedClickOn(var/atom/A)
+ if(a_intent != "harm" || !ismob(A)) return
+ if(istype(wear_mask, /obj/item/clothing/mask/muzzle))
+ return
+ var/mob/living/carbon/ML = A
+ var/dam_zone = ran_zone(pick("chest", "l_hand", "r_hand", "l_leg", "r_leg"))
+ var/armor = ML.run_armor_check(dam_zone, "melee")
+ if(prob(75))
+ ML.apply_damage(rand(1,3), BRUTE, dam_zone, armor)
+ for(var/mob/O in viewers(ML, null))
+ O.show_message("\red [name] has bit [ML]!", 1)
+ if(armor >= 2) return
+ if(ismonkey(ML))
+ for(var/datum/disease/D in viruses)
+ if(istype(D, /datum/disease/jungle_fever))
+ ML.contract_disease(D,1,0)
+ else
+ for(var/mob/O in viewers(ML, null))
+ O.show_message("\red [src] has attempted to bite [ML]!", 1)
+
+/*
+ Aliens
+ Defaults to same as monkey in most places
+*/
+/mob/living/carbon/alien/UnarmedAttack(var/atom/A)
+ A.attack_alien(src)
+/atom/proc/attack_alien(mob/user as mob)
+ attack_paw(user)
+ return
+/mob/living/carbon/alien/RestrainedClickOn(var/atom/A)
+ return
+
+// Babby aliens
+/mob/living/carbon/alien/larva/UnarmedAttack(var/atom/A)
+ A.attack_larva(src)
+/atom/proc/attack_larva(mob/user as mob)
+ return
+
+
+/*
+ Slimes
+ Nothing happening here
+*/
+/mob/living/carbon/slime/UnarmedAttack(var/atom/A)
+ A.attack_slime(src)
+/atom/proc/attack_slime(mob/user as mob)
+ return
+/mob/living/carbon/slime/RestrainedClickOn(var/atom/A)
+ return
+
+/*
+ New Players:
+ Have no reason to click on anything at all.
+*/
+/mob/new_player/ClickOn()
+ return
diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm
new file mode 100644
index 00000000000..0abb637cce9
--- /dev/null
+++ b/code/_onclick/telekinesis.dm
@@ -0,0 +1,208 @@
+/*
+ Telekinesis
+
+ This needs more thinking out, but I might as well.
+*/
+var/const/tk_maxrange = 15
+
+/*
+ Telekinetic attack:
+
+ By default, emulate the user's unarmed attack
+*/
+/atom/proc/attack_tk(mob/user)
+ if(user.stat) return
+ user.UnarmedAttack(src,0) // attack_hand, attack_paw, etc
+ return
+
+/*
+ This is similar to item attack_self, but applies to anything
+ that you can grab with a telekinetic grab.
+
+ It is used for manipulating things at range, for example, opening and closing closets.
+ There are not a lot of defaults at this time, add more where appropriate.
+*/
+/atom/proc/attack_self_tk(mob/user)
+ return
+
+/obj/attack_tk(mob/user)
+ if(user.stat) return
+ if(anchored)
+ ..()
+ return
+
+ var/obj/item/tk_grab/O = new(src)
+ user.put_in_active_hand(O)
+ O.host = user
+ O.focus_object(src)
+ return
+
+/obj/item/attack_tk(mob/user)
+ if(user.stat || !isturf(loc)) return
+ if((TK in user.mutations) && !user.get_active_hand()) // both should already be true to get here
+ var/obj/item/tk_grab/O = new(src)
+ user.put_in_active_hand(O)
+ O.host = user
+ O.focus_object(src)
+ else
+ warning("Strange attack_tk(): TK([TK in user.mutations]) empty hand([!user.get_active_hand()])")
+ return
+
+
+/mob/attack_tk(mob/user)
+ return // needs more thinking about
+
+/*
+ TK Grab Item (the workhorse of old TK)
+
+ * If you have not grabbed something, do a normal tk attack
+ * If you have something, throw it at the target. If it is already adjacent, do a normal attackby()
+ * If you click what you are holding, or attack_self(), do an attack_self_tk() on it.
+ * Deletes itself if it is ever not in your hand, or if you should have no access to TK.
+*/
+/obj/item/tk_grab
+ name = "Telekinetic Grab"
+ desc = "Magic"
+ icon = 'icons/obj/magic.dmi'//Needs sprites
+ icon_state = "2"
+ flags = NOBLUDGEON
+ //item_state = null
+ w_class = 10.0
+ layer = 20
+
+ var/last_throw = 0
+ var/atom/movable/focus = null
+ var/mob/living/host = null
+
+
+ dropped(mob/user as mob)
+ if(focus && user && loc != user && loc != user.loc) // drop_item() gets called when you tk-attack a table/closet with an item
+ if(focus.Adjacent(loc))
+ focus.loc = loc
+
+ del(src)
+ return
+
+
+ //stops TK grabs being equipped anywhere but into hands
+ equipped(var/mob/user, var/slot)
+ if( (slot == slot_l_hand) || (slot== slot_r_hand) ) return
+ del(src)
+ return
+
+
+ attack_self(mob/user as mob)
+ if(focus)
+ focus.attack_self_tk(user)
+
+ afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, proximity)//TODO: go over this
+ if(!target || !user) return
+ if(last_throw+3 > world.time) return
+ if(!host || host != user)
+ del(src)
+ return
+ if(!(TK in host.mutations))
+ del(src)
+ return
+ if(isobj(target) && !isturf(target.loc))
+ return
+
+ var/d = get_dist(user, target)
+ if(focus) d = max(d,get_dist(user,focus)) // whichever is further
+ switch(d)
+ if(0)
+ ;
+ if(1 to 5) // not adjacent may mean blocked by window
+ if(!proximity)
+ user.next_move += 2
+ if(5 to 7)
+ user.next_move += 5
+ if(8 to tk_maxrange)
+ user.next_move += 10
+ else
+ user << "\blue Your mind won't reach that far."
+ return
+
+ if(!focus)
+ focus_object(target, user)
+ return
+
+ if(target == focus)
+ target.attack_self_tk(user)
+ return // todo: something like attack_self not laden with assumptions inherent to attack_self
+
+
+ if(!istype(target, /turf) && istype(focus,/obj/item) && target.Adjacent(focus))
+ var/obj/item/I = focus
+ var/resolved = target.attackby(I, user, user:get_organ_target())
+ if(!resolved && target && I)
+ I.afterattack(target,user,1) // for splashing with beakers
+
+
+ else
+ apply_focus_overlay()
+ focus.throw_at(target, 10, 1)
+ last_throw = world.time
+ return
+
+ attack(mob/living/M as mob, mob/living/user as mob, def_zone)
+ return
+
+
+ proc/focus_object(var/obj/target, var/mob/living/user)
+ if(!istype(target,/obj)) return//Cant throw non objects atm might let it do mobs later
+ if(target.anchored || !isturf(target.loc))
+ del src
+ return
+ focus = target
+ update_icon()
+ apply_focus_overlay()
+ return
+
+
+ proc/apply_focus_overlay()
+ if(!focus) return
+ var/obj/effect/overlay/O = new /obj/effect/overlay(locate(focus.x,focus.y,focus.z))
+ O.name = "sparkles"
+ O.anchored = 1
+ O.density = 0
+ O.layer = FLY_LAYER
+ O.dir = pick(cardinal)
+ O.icon = 'icons/effects/effects.dmi'
+ O.icon_state = "nothing"
+ flick("empdisable",O)
+ spawn(5)
+ O.delete()
+ return
+
+
+ update_icon()
+ overlays.Cut()
+ if(focus && focus.icon && focus.icon_state)
+ overlays += icon(focus.icon,focus.icon_state)
+ return
+
+/*Not quite done likely needs to use something thats not get_step_to
+ proc/check_path()
+ var/turf/ref = get_turf(src.loc)
+ var/turf/target = get_turf(focus.loc)
+ if(!ref || !target) return 0
+ var/distance = get_dist(ref, target)
+ if(distance >= 10) return 0
+ for(var/i = 1 to distance)
+ ref = get_step_to(ref, target, 0)
+ if(ref != target) return 0
+ return 1
+*/
+
+//equip_to_slot_or_del(obj/item/W, slot, del_on_fail = 1)
+/*
+ if(istype(user, /mob/living/carbon))
+ if(user:mutations & TK && get_dist(source, user) <= 7)
+ if(user:get_active_hand()) return 0
+ var/X = source:x
+ var/Y = source:y
+ var/Z = source:z
+
+*/
+
diff --git a/code/modules/clothing/gloves/ninja.dm b/code/modules/clothing/gloves/ninja.dm
new file mode 100644
index 00000000000..15e7c40c3b3
--- /dev/null
+++ b/code/modules/clothing/gloves/ninja.dm
@@ -0,0 +1,113 @@
+/*
+ Dear ninja gloves
+
+ This isn't because I like you
+ this is because your father is a bastard
+
+ ...
+ I guess you're a little cool.
+ -Sayu
+*/
+
+/obj/item/clothing/gloves/space_ninja
+ desc = "These nano-enhanced gloves insulate from electricity and provide fire resistance."
+ name = "ninja gloves"
+ icon_state = "s-ninja"
+ item_state = "s-ninja"
+ siemens_coefficient = 0
+ var/draining = 0
+ var/candrain = 0
+ var/mindrain = 200
+ var/maxdrain = 400
+
+/*
+ This runs the gamut of what ninja gloves can do
+ The other option would be a dedicated ninja touch bullshit proc on everything
+ which would probably more efficient, but ninjas are pretty rare.
+ This was mostly introduced to keep ninja code from contaminating other code;
+ with this in place it would be easier to untangle the rest of it.
+
+ For the drain proc, see events/ninja.dm
+*/
+/obj/item/clothing/gloves/space_ninja/Touch(var/atom/A,var/proximity)
+ if(!candrain || draining) return 0
+
+ var/mob/living/carbon/human/H = loc
+ if(!istype(H)) return 0 // what
+ var/obj/item/clothing/suit/space/space_ninja/suit = H.wear_suit
+ if(!istype(suit)) return 0
+ if(isturf(A)) return 0
+
+ if(!proximity) // todo: you could add ninja stars or computer hacking here
+ return 0
+
+ // Move an AI into and out of things
+ if(istype(A,/mob/living/silicon/ai))
+ if(suit.s_control)
+ A.add_fingerprint(H)
+ suit.transfer_ai("AICORE", "NINJASUIT", A, H)
+ return 1
+ else
+ H << "\red ERROR: \black Remote access channel disabled."
+ return 0
+
+ if(istype(A,/obj/structure/AIcore/deactivated))
+ if(suit.s_control)
+ A.add_fingerprint(H)
+ suit.transfer_ai("INACTIVE","NINJASUIT",A, H)
+ return 1
+ else
+ H << "\red ERROR: \black Remote access channel disabled."
+ return 0
+ if(istype(A,/obj/machinery/computer/aifixer))
+ if(suit.s_control)
+ A.add_fingerprint(H)
+ suit.transfer_ai("AIFIXER","NINJASUIT",A, H)
+ return 1
+ else
+ H << "\red ERROR: \black Remote access channel disabled."
+ return 0
+
+ // steal energy from powered things
+ if(istype(A,/mob/living/silicon/robot))
+ A.add_fingerprint(H)
+ drain("CYBORG",A,suit)
+ return 1
+ if(istype(A,/obj/machinery/power/apc))
+ A.add_fingerprint(H)
+ drain("APC",A,suit)
+ return 1
+ if(istype(A,/obj/structure/cable))
+ A.add_fingerprint(H)
+ drain("WIRE",A,suit)
+ return 1
+ if(istype(A,/obj/structure/grille))
+ var/obj/structure/cable/C = locate() in A.loc
+ if(C)
+ drain("WIRE",C,suit)
+ return 1
+ if(istype(A,/obj/machinery/power/smes))
+ A.add_fingerprint(H)
+ drain("SMES",A,suit)
+ return 1
+ if(istype(A,/obj/mecha))
+ A.add_fingerprint(H)
+ drain("MECHA",A,suit)
+ return 1
+
+ // download research
+ if(istype(A,/obj/machinery/computer/rdconsole))
+ A.add_fingerprint(H)
+ drain("RESEARCH",A,suit)
+ return 1
+ if(istype(A,/obj/machinery/r_n_d/server))
+ A.add_fingerprint(H)
+ var/obj/machinery/r_n_d/server/S = A
+ if(S.disabled)
+ return 1
+ if(S.shocked)
+ S.shock(H,50)
+ return 1
+ drain("RESEARCH",A,suit)
+ return 1
+