diff --git a/code/game/objects/items/weapons/inducer.dm b/code/game/objects/items/weapons/inducer.dm
new file mode 100644
index 0000000000..fdd44795ad
--- /dev/null
+++ b/code/game/objects/items/weapons/inducer.dm
@@ -0,0 +1,183 @@
+/obj/item/weapon/inducer
+ name = "inducer"
+ desc = "A tool for inductively charging internal power cells."
+ icon = 'icons/obj/tools.dmi'
+ icon_state = "inducer-engi"
+ item_state = "inducer-engi"
+ origin_tech = "engineering=4;magnets=4;powerstorage=4"
+ force = 7
+ var/powertransfer = 1000
+ var/opened = FALSE
+ var/cell_type = /obj/item/weapon/stock_parts/cell/high
+ var/obj/item/weapon/stock_parts/cell/cell
+ var/recharging = FALSE
+
+/obj/item/weapon/inducer/Initialize()
+ . = ..()
+ if(!cell && cell_type)
+ cell = new cell_type
+
+/obj/item/weapon/inducer/proc/induce(obj/item/weapon/stock_parts/cell/target, coefficient)
+ var/totransfer = min(cell.charge,(powertransfer * coefficient))
+ var/transferred = target.give(totransfer)
+ cell.use(transferred)
+ cell.update_icon()
+ target.update_icon()
+
+/obj/item/weapon/inducer/get_cell()
+ return cell
+
+/obj/item/weapon/inducer/emp_act(severity)
+ ..()
+ if(cell)
+ cell.emp_act()
+
+/obj/item/weapon/inducer/attack_obj(obj/O, mob/living/carbon/user)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
+
+ if(cantbeused(user))
+ return
+
+ if(recharge(O, user))
+ return
+
+ return ..()
+
+/obj/item/weapon/inducer/proc/cantbeused(mob/user)
+ if(!user.IsAdvancedToolUser())
+ to_chat(user, "You don't have the dexterity to use \the [src]!")
+ return TRUE
+
+ if(!cell)
+ to_chat(user, "\The [src] doesn't have a power cell installed!")
+ return TRUE
+
+ if(!cell.charge)
+ to_chat(user, "\The [src]'s battery is dead!")
+ return TRUE
+ return FALSE
+
+
+/obj/item/weapon/inducer/attackby(obj/item/weapon/W, mob/user)
+ if(istype(W,/obj/item/weapon/screwdriver))
+ playsound(src, W.usesound, 50, 1)
+ if(!opened)
+ to_chat(user, "You unscrew the battery compartment.")
+ opened = TRUE
+ update_icon()
+ return
+ else
+ to_chat(user, "You close the battery compartment.")
+ opened = FALSE
+ update_icon()
+ return
+ if(istype(W,/obj/item/weapon/stock_parts/cell))
+ if(opened)
+ if(!cell)
+ if(!user.transferItemToLoc(W, src))
+ return
+ to_chat(user, "You insert \the [W] into \the [src].")
+ cell = W
+ update_icon()
+ return
+ else
+ to_chat(user, "\The [src] already has \a [cell] installed!")
+ return
+
+ if(cantbeused(user))
+ return
+
+ if(recharge(W, user))
+ return
+
+ return ..()
+
+/obj/item/weapon/inducer/proc/recharge(atom/movable/A, mob/user)
+ if(recharging)
+ return TRUE
+ else
+ recharging = TRUE
+ var/obj/item/weapon/stock_parts/cell/C = A.get_cell()
+ var/obj/item/weapon/gun/energy/E
+ var/obj/O
+ var/coefficient = 1
+ if(istype(A, /obj/item/weapon/gun/energy))
+ coefficient = 0.075 // 14 loops to recharge an egun from 0-1000
+ E = A
+ if(istype(A, /obj))
+ O = A
+ if(C)
+ if(C.charge >= C.maxcharge)
+ to_chat(user, "\The [A] is fully charged!")
+ recharging = FALSE
+ return TRUE
+ user.visible_message("[user] starts recharging \the [A] with \the [src]","You start recharging [A] with \the [src]")
+ while(C.charge < C.maxcharge)
+ if(E)
+ E.chambered = null // Prevents someone from firing continuously while recharging the gun.
+ if(do_after(user, 10, target = user) && cell.charge)
+ induce(C, coefficient)
+ do_sparks(1, FALSE, A)
+ if(O)
+ O.update_icon()
+ else
+ break
+ if(E)
+ E.recharge_newshot() //We're done charging, so we'll let someone fire it now.
+ user.visible_message("[user] recharged \the [A]!","You recharged \the [A]!")
+ recharging = FALSE
+ return TRUE
+
+
+/obj/item/weapon/inducer/attack(mob/M, mob/user)
+ if(user.a_intent == INTENT_HARM)
+ return ..()
+
+ if(cantbeused(user))
+ return
+
+ if(recharge(M, user))
+ return
+ return ..()
+
+
+/obj/item/weapon/inducer/attack_self(mob/user)
+ if(opened && cell)
+ user.visible_message("[user] removes \the [cell] from \the [src]!","You remove \the [cell].")
+ cell.update_icon()
+ user.put_in_hands(cell)
+ cell = null
+ update_icon()
+
+
+/obj/item/weapon/inducer/examine(mob/living/M)
+ ..()
+ if(cell)
+ to_chat(M, "It's display shows: [cell.charge]W")
+ else
+ to_chat(M,"It's display is dark.")
+ if(opened)
+ to_chat(M,"It's battery compartment is open.")
+
+/obj/item/weapon/inducer/update_icon()
+ cut_overlays()
+ if(opened)
+ if(!cell)
+ add_overlay("inducer-nobat")
+ else
+ add_overlay("inducer-bat")
+
+/obj/item/weapon/inducer/sci
+ icon_state = "inducer-sci"
+ item_state = "inducer-sci"
+ desc = "A tool for inductively charging internal power cells. This one has a science color scheme, and is less potent than it's engineering counterpart."
+ cell_type = null
+ powertransfer = 500
+ opened = TRUE
+
+/obj/item/weapon/inducer/sci/Initialize()
+ . = ..()
+ update_icon()
+
+
diff --git a/code/game/objects/structures/manned_turret.dm b/code/game/objects/structures/manned_turret.dm
new file mode 100644
index 0000000000..f2f767f4e6
--- /dev/null
+++ b/code/game/objects/structures/manned_turret.dm
@@ -0,0 +1,209 @@
+/////// MANNED TURRET ////////
+
+/obj/machinery/manned_turret
+ name = "machine gun turret"
+ desc = "While the trigger is held down, this gun will redistribute recoil to allow its user to easily shift targets."
+ icon = 'icons/obj/turrets.dmi'
+ icon_state = "machinegun"
+ can_buckle = TRUE
+ density = TRUE
+ max_integrity = 100
+ obj_integrity = 100
+ buckle_lying = FALSE
+ layer = ABOVE_MOB_LAYER
+ var/view_range = 10
+ var/cooldown = 0
+ var/projectile_type = /obj/item/projectile/bullet/weakbullet3
+ var/rate_of_fire = 1
+ var/number_of_shots = 40
+ var/cooldown_duration = 90
+ var/atom/target
+ var/turf/target_turf
+ var/warned = FALSE
+ var/list/calculated_projectile_vars
+
+/obj/machinery/manned_turret/Destroy()
+ target = null
+ target_turf = null
+ ..()
+
+//BUCKLE HOOKS
+
+/obj/machinery/manned_turret/unbuckle_mob(mob/living/buckled_mob,force = FALSE)
+ playsound(src,'sound/mecha/mechmove01.ogg', 50, 1)
+ for(var/obj/item/I in buckled_mob.held_items)
+ if(istype(I, /obj/item/gun_control))
+ qdel(I)
+ if(istype(buckled_mob))
+ buckled_mob.pixel_x = 0
+ buckled_mob.pixel_y = 0
+ if(buckled_mob.client)
+ buckled_mob.reset_perspective()
+ anchored = FALSE
+ . = ..()
+ STOP_PROCESSING(SSfastprocess, src)
+
+/obj/machinery/manned_turret/user_buckle_mob(mob/living/M, mob/living/carbon/user)
+ if(user.incapacitated() || !istype(user))
+ return
+ M.forceMove(get_turf(src))
+ ..()
+ for(var/V in M.held_items)
+ var/obj/item/I = V
+ if(istype(I))
+ if(M.dropItemToGround(I))
+ var/obj/item/gun_control/TC = new(src)
+ M.put_in_hands(TC)
+ else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand
+ var/obj/item/gun_control/TC = new(src)
+ M.put_in_hands(TC)
+ M.pixel_y = 14
+ layer = ABOVE_MOB_LAYER
+ setDir(SOUTH)
+ playsound(src,'sound/mecha/mechmove01.ogg', 50, 1)
+ anchored = TRUE
+ if(user.client)
+ user.client.change_view(view_range)
+ START_PROCESSING(SSfastprocess, src)
+
+/obj/machinery/manned_turret/process()
+ if(!LAZYLEN(buckled_mobs))
+ return PROCESS_KILL
+ update_positioning()
+
+/obj/machinery/manned_turret/proc/update_positioning()
+ var/mob/living/controller = buckled_mobs[1]
+ if(!istype(controller))
+ return
+ var/client/C = controller.client
+ if(C)
+ var/atom/A = C.mouseObject
+ var/turf/T = get_turf(A)
+ if(istype(T)) //They're hovering over something in the map.
+ direction_track(controller, T)
+ calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(controller, C.mouseParams)
+
+/obj/machinery/manned_turret/proc/direction_track(mob/user, atom/targeted)
+ setDir(get_dir(src,targeted))
+ user.setDir(dir)
+ switch(dir)
+ if(NORTH)
+ layer = BELOW_MOB_LAYER
+ user.pixel_x = 0
+ user.pixel_y = -14
+ if(NORTHEAST)
+ layer = BELOW_MOB_LAYER
+ user.pixel_x = -8
+ user.pixel_y = -4
+ if(EAST)
+ layer = ABOVE_MOB_LAYER
+ user.pixel_x = -14
+ user.pixel_y = 0
+ if(SOUTHEAST)
+ layer = BELOW_MOB_LAYER
+ user.pixel_x = -8
+ user.pixel_y = 4
+ if(SOUTH)
+ layer = ABOVE_MOB_LAYER
+ user.pixel_x = 0
+ user.pixel_y = 14
+ if(SOUTHWEST)
+ layer = BELOW_MOB_LAYER
+ user.pixel_x = 8
+ user.pixel_y = 4
+ if(WEST)
+ layer = ABOVE_MOB_LAYER
+ user.pixel_x = 14
+ user.pixel_y = 0
+ if(NORTHWEST)
+ layer = BELOW_MOB_LAYER
+ user.pixel_x = 8
+ user.pixel_y = -4
+
+/obj/machinery/manned_turret/proc/checkfire(atom/targeted_atom, mob/user)
+ target = targeted_atom
+ if(target == user || target == get_turf(src))
+ return
+ if(world.time < cooldown)
+ if(!warned && world.time > (cooldown - cooldown_duration + rate_of_fire*number_of_shots)) // To capture the window where one is done firing
+ warned = TRUE
+ playsound(src, 'sound/weapons/sear.ogg', 100, 1)
+ return
+ else
+ cooldown = world.time + cooldown_duration
+ warned = FALSE
+ volley(user)
+
+/obj/machinery/manned_turret/proc/volley(mob/user)
+ target_turf = get_turf(target)
+ for(var/i in 1 to number_of_shots)
+ addtimer(CALLBACK(src, /obj/machinery/manned_turret/.proc/fire_helper, user), i*rate_of_fire)
+
+/obj/machinery/manned_turret/proc/fire_helper(mob/user)
+ update_positioning() //REFRESH MOUSE TRACKING!!
+ var/turf/targets_from = get_turf(src)
+ if(QDELETED(target))
+ target = target_turf
+ var/obj/item/projectile/P = new projectile_type(targets_from)
+ P.current = targets_from
+ P.starting = targets_from
+ P.firer = user
+ P.original = target
+ playsound(src, 'sound/weapons/Gunshot_smg.ogg', 75, 1)
+ P.xo = target.x - targets_from.x
+ P.yo = target.y - targets_from.y
+ P.Angle = calculated_projectile_vars[1] + rand(-9, 9)
+ P.p_x = calculated_projectile_vars[2]
+ P.p_y = calculated_projectile_vars[3]
+ P.fire()
+
+/obj/machinery/manned_turret/ultimate // Admin-only proof of concept for autoclicker automatics
+ name = "Infinity Gun"
+ view_range = 12
+ projectile_type = /obj/item/projectile/bullet/weakbullet3
+
+/obj/machinery/manned_turret/ultimate/checkfire(atom/targeted_atom, mob/user)
+ target = targeted_atom
+ if(target == user || target == get_turf(src))
+ return
+ target_turf = get_turf(target)
+ fire_helper(user)
+
+/obj/item/gun_control
+ name = "turret controls"
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "offhand"
+ w_class = WEIGHT_CLASS_HUGE
+ flags = ABSTRACT | NODROP | NOBLUDGEON
+ resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
+ var/obj/machinery/manned_turret/turret
+
+/obj/item/gun_control/Initialize()
+ . = ..()
+ turret = loc
+ if(!istype(turret))
+ return INITIALIZE_HINT_QDEL
+
+/obj/item/gun_control/Destroy()
+ turret = null
+ ..()
+
+/obj/item/gun_control/CanItemAutoclick()
+ return TRUE
+
+/obj/item/gun_control/attack_obj(obj/O, mob/living/user)
+ user.changeNext_move(CLICK_CD_MELEE)
+ O.attacked_by(src, user)
+
+/obj/item/gun_control/attack(mob/living/M, mob/living/user)
+ user.lastattacked = M
+ M.lastattacker = user
+ M.attacked_by(src, user)
+ add_fingerprint(user)
+
+/obj/item/gun_control/afterattack(atom/targeted_atom, mob/user, flag, params)
+ ..()
+ var/obj/machinery/manned_turret/E = user.buckled
+ E.calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(user, params)
+ E.direction_track(user, targeted_atom)
+ E.checkfire(targeted_atom, user)