diff --git a/baystation12.dme b/baystation12.dme
index d0ec0e3ae0a..91a79ef86af 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -1467,6 +1467,7 @@
#include "code\modules\surgery\surgery.dm"
#include "code\modules\vehicles\ambulance.dm"
#include "code\modules\vehicles\cargo_train.dm"
+#include "code\modules\vehicles\janicart.dm"
#include "code\modules\vehicles\train.dm"
#include "code\modules\vehicles\vehicle.dm"
#include "code\modules\virus2\analyser.dm"
diff --git a/code/modules/vehicles/janicart.dm b/code/modules/vehicles/janicart.dm
new file mode 100644
index 00000000000..7b476c80129
--- /dev/null
+++ b/code/modules/vehicles/janicart.dm
@@ -0,0 +1,357 @@
+/obj/vehicle/train/janitor/engine
+ name = "janitor train tug"
+ desc = "A ridable electric car designed for pulling janitor trolleys."
+ icon = 'icons/obj/vehicles.dmi'
+ icon_state = "pussywagon" //mulebot icons until I get some proper icons
+ on = 0
+ powered = 1
+ locked = 0
+ layer = MOB_LAYER + 0.1
+ standing_mob = 1
+ load_item_visible = 1
+ load_offset_x = 0
+ load_offset_y = 7
+
+ var/car_limit = 3 //how many cars an engine can pull before performance degrades
+ active_engines = 1
+ var/obj/item/weapon/key/janitor_train/key
+ flags = OPENCONTAINER
+ var/amount_per_transfer_from_this = 5 //shit I dunno, adding this so syringes stop runtime erroring. --NeoFite
+ var/obj/item/weapon/storage/bag/trash/mybag = null
+
+/obj/item/weapon/key/janitor_train
+ name = "key"
+ desc = "A keyring with a small steel key, and a yellow fob reading \"Choo Choo!\"."
+ icon = 'icons/obj/vehicles.dmi'
+ icon_state = "keys"
+ w_class = 1
+
+/obj/vehicle/train/janitor/trolley
+ name = "janitor train trolley"
+ icon = 'icons/obj/janitor.dmi'
+ icon_state = "trashcart"
+ anchored = 0
+ passenger_allowed = 0
+ locked = 0
+ standing_mob = 0
+ load_item_visible = 1
+ load_offset_x = 1
+ load_offset_y = 7
+
+ var/openTop = 0
+
+//-------------------------------------------
+// Standard procs
+//-------------------------------------------
+/obj/vehicle/train/janitor/engine/New()
+ ..()
+ cell = new /obj/item/weapon/cell/high
+ verbs -= /atom/movable/verb/pull
+ key = new()
+ var/datum/reagents/R = new/datum/reagents(100)
+ reagents = R
+ R.my_atom = src
+
+/obj/vehicle/train/janitor/engine/Move()
+ if(on && cell.charge < power_use)
+ turn_off()
+ update_stats()
+ if(load && is_train_head())
+ load << "The drive motor briefly whines, then drones to a stop."
+
+ if(is_train_head() && !on)
+ return 0
+
+ handle_rotation()
+ update_mob()
+
+ return ..()
+
+/obj/vehicle/train/janitor/trolley/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ openTop = !openTop
+ user.visible_message("[user] [openTop ? "opens" : "closes"] a the top of [src].","You [openTop ? "open" : "close"] the the top of [src].")
+ update_icon()
+ ..()
+
+/obj/vehicle/train/janitor/trolley/update_icon()
+ if(openTop)
+ icon_state = "trashcartopen"
+ else
+ icon_state = initial(icon_state)
+
+/obj/vehicle/train/janitor/engine/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/weapon/key/janitor_train))
+ if(!key)
+ user.drop_item()
+ key = W
+ W.loc = src
+ verbs += /obj/vehicle/train/janitor/engine/verb/remove_key
+ return
+ else if(istype(W, /obj/item/weapon/mop))
+ if(reagents.total_volume >= 2)
+ reagents.trans_to(W, 2)
+ user << "You wet the mop in the pimpin' ride."
+ playsound(src.loc, 'sound/effects/slosh.ogg', 25, 1)
+ if(reagents.total_volume < 1)
+ user << "This pimpin' ride is out of water!"
+ return
+ else if(istype(W, /obj/item/weapon/storage/bag/trash))
+ user << "You hook the trashbag onto the pimpin' ride."
+ user.drop_item()
+ W.loc = src
+ mybag = W
+ return
+ ..()
+
+/obj/vehicle/train/janitor/engine/attack_hand(mob/user)
+ if(mybag)
+ mybag.loc = get_turf(user)
+ user.put_in_hands(mybag)
+ mybag = null
+ else
+ ..()
+
+/obj/vehicle/train/janitor/update_icon()
+ if(open)
+ icon_state = "mulebot-hatch"
+ else
+ icon_state = initial(icon_state)
+
+/obj/vehicle/train/janitor/engine/Emag(mob/user as mob)
+ ..()
+ flick("mulebot-emagged", src)
+
+/obj/vehicle/train/janitor/trolley/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H)
+ return
+
+/obj/vehicle/train/janitor/engine/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H)
+ ..()
+ update_stats()
+
+/obj/vehicle/train/janitor/engine/remove_cell(var/mob/living/carbon/human/H)
+ ..()
+ update_stats()
+
+/obj/vehicle/train/janitor/engine/Bump(atom/Obstacle)
+ var/obj/machinery/door/D = Obstacle
+ var/mob/living/carbon/human/H = load
+ if(istype(D) && istype(H))
+ D.Bumped(H) //a little hacky, but hey, it works, and repects access rights
+
+ ..()
+
+/obj/vehicle/train/janitor/trolley/Bump(atom/Obstacle)
+ if(!lead)
+ return //so people can't knock others over by pushing a trolley around
+ ..()
+
+/obj/vehicle/train/janitor/engine/proc/handle_rotation()
+ if(dir == SOUTH)
+ layer = FLY_LAYER
+ else
+ layer = OBJ_LAYER
+
+/obj/vehicle/train/janitor/engine/proc/update_mob()
+ if(load)
+ load.dir = dir
+ switch(dir)
+ if(SOUTH)
+ load.pixel_x = 0
+ load.pixel_y = 7
+ if(WEST)
+ load.pixel_x = 13
+ load.pixel_y = 7
+ if(NORTH)
+ load.pixel_x = 0
+ load.pixel_y = 4
+ if(EAST)
+ load.pixel_x = -13
+ load.pixel_y = 7
+
+
+//-------------------------------------------
+// Train procs
+//-------------------------------------------
+/obj/vehicle/train/janitor/engine/turn_on()
+ if(!key)
+ return
+ else
+ ..()
+ update_stats()
+
+/obj/vehicle/train/janitor/RunOver(var/mob/living/carbon/human/H)
+ var/list/parts = list("head", "chest", "l_leg", "r_leg", "l_arm", "r_arm")
+
+ H.apply_effects(5, 5)
+ for(var/i = 0, i < rand(1,3), i++)
+ H.apply_damage(rand(1,5), BRUTE, pick(parts))
+
+/obj/vehicle/train/janitor/trolley/RunOver(var/mob/living/carbon/human/H)
+ ..()
+ attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])")
+
+/obj/vehicle/train/janitor/engine/RunOver(var/mob/living/carbon/human/H)
+ ..()
+
+ if(is_train_head() && istype(load, /mob/living/carbon/human))
+ var/mob/living/carbon/human/D = load
+ D << "\red \b You ran over [H]!"
+ visible_message("\red \The [src] ran over [H]!")
+ attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey]), driven by [D.name] ([D.ckey])")
+ msg_admin_attack("[D.name] ([D.ckey]) ran over [H.name] ([H.ckey]). (JMP)")
+ else
+ attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])")
+
+
+//-------------------------------------------
+// Interaction procs
+//-------------------------------------------
+/obj/vehicle/train/janitor/engine/relaymove(mob/user, direction)
+ if(user != load)
+ return 0
+
+ if(is_train_head())
+ if(direction == reverse_direction(dir))
+ return 0
+ if(Move(get_step(src, direction)))
+ return 1
+ return 0
+ else
+ return ..()
+
+
+/obj/vehicle/train/janitor/engine/examine()
+ ..()
+
+ usr << "\icon[src] This [name] contains [reagents.total_volume] unit\s of [reagents]!"
+ if(mybag)
+ usr << "\A [mybag] is hanging on the [name]."
+
+ if(!istype(usr, /mob/living/carbon/human))
+ return
+
+ if(get_dist(usr,src) <= 1)
+ usr << "The power light is [on ? "on" : "off"].\nThere are[key ? "" : " no"] keys in the ignition."
+
+/obj/vehicle/train/janitor/engine/verb/check_power()
+ set name = "Check power level"
+ set category = "Object"
+ set src in view(1)
+
+ if(!istype(usr, /mob/living/carbon/human))
+ return
+
+ if(!cell)
+ usr << "There is no power cell installed in [src]."
+ return
+
+ usr << "The power meter reads [round(cell.percent(), 0.01)]%"
+
+/obj/vehicle/train/janitor/engine/verb/start_engine()
+ set name = "Start engine"
+ set category = "Object"
+ set src in view(1)
+
+ if(!istype(usr, /mob/living/carbon/human))
+ return
+
+ if(on)
+ usr << "The engine is already running."
+ return
+
+ turn_on()
+ if (on)
+ usr << "You start [src]'s engine."
+ else
+ if(cell.charge < power_use)
+ usr << "[src] is out of power."
+ else
+ usr << "[src]'s engine won't start."
+
+/obj/vehicle/train/janitor/engine/verb/stop_engine()
+ set name = "Stop engine"
+ set category = "Object"
+ set src in view(1)
+
+ if(!istype(usr, /mob/living/carbon/human))
+ return
+
+ if(!on)
+ usr << "The engine is already stopped."
+ return
+
+ turn_off()
+ if (!on)
+ usr << "You stop [src]'s engine."
+
+/obj/vehicle/train/janitor/engine/verb/remove_key()
+ set name = "Remove key"
+ set category = "Object"
+ set src in view(1)
+
+ if(!istype(usr, /mob/living/carbon/human))
+ return
+
+ if(!key || (load && load != usr))
+ return
+
+ if(on)
+ turn_off()
+
+ key.loc = usr.loc
+ if(!usr.get_active_hand())
+ usr.put_in_hands(key)
+ key = null
+
+ verbs -= /obj/vehicle/train/janitor/engine/verb/remove_key
+
+//-------------------------------------------
+// Loading/unloading procs
+//-------------------------------------------
+/obj/vehicle/train/janitor/trolley/load(var/atom/movable/C)
+ return 0
+
+/obj/vehicle/train/janitor/engine/load(var/atom/movable/C)
+ if(!ismob(C))
+ return 0
+
+ return ..()
+
+
+//-------------------------------------------------------
+// Stat update procs
+//
+// Update the trains stats for speed calculations.
+// The longer the train, the slower it will go. car_limit
+// sets the max number of cars one engine can pull at
+// full speed. Adding more cars beyond this will slow the
+// train proportionate to the length of the train. Adding
+// more engines increases this limit by car_limit per
+// engine.
+//-------------------------------------------------------
+/obj/vehicle/train/janitor/engine/update_train_stats()
+ ..()
+
+ update_move_delay()
+
+/obj/vehicle/train/janitor/trolley/update_train_stats()
+ ..()
+
+ if(!lead && !tow)
+ anchored = 0
+ if(verbs.Find(/atom/movable/verb/pull))
+ return
+ else
+ verbs += /atom/movable/verb/pull
+ else
+ anchored = 1
+ verbs -= /atom/movable/verb/pull
+
+/obj/vehicle/train/janitor/engine/proc/update_move_delay()
+ if(!is_train_head() || !on)
+ move_delay = initial(move_delay) //so that engines that have been turned off don't lag behind
+ else
+ move_delay = max(0, (-car_limit * active_engines) + train_length - active_engines) //limits base overweight so you cant overspeed trains
+ move_delay *= (1 / max(1, active_engines)) * 2 //overweight penalty (scaled by the number of engines)
+ move_delay += config.run_speed //base reference speed
+ move_delay *= 1.05
diff --git a/icons/obj/janitor.dmi b/icons/obj/janitor.dmi
index 07b236e1abc..92a8c6c528f 100644
Binary files a/icons/obj/janitor.dmi and b/icons/obj/janitor.dmi differ
diff --git a/maps/cyberiad.dmm b/maps/cyberiad.dmm
index 184d31c5f31..97b189a25ec 100644
--- a/maps/cyberiad.dmm
+++ b/maps/cyberiad.dmm
@@ -4767,8 +4767,8 @@
"bNI" = (/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor,/area/hallway/primary/aft)
"bNJ" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor{dir = 2; icon_state = "yellowcorner"},/area/hallway/primary/aft)
"bNK" = (/obj/machinery/power/apc{dir = 8; name = "Custodial Closet APC"; pixel_x = -24},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 4},/turf/simulated/floor,/area/janitor)
-"bNL" = (/obj/structure/stool,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/effect/landmark/start{name = "Janitor"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 9},/turf/simulated/floor,/area/janitor)
-"bNM" = (/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor,/area/janitor)
+"bNL" = (/obj/structure/stool,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/effect/landmark/start{name = "Janitor"},/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{dir = 9},/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/turf/simulated/floor,/area/janitor)
+"bNM" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/janitor)
"bNN" = (/obj/effect/landmark/start{name = "Janitor"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor,/area/janitor)
"bNO" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/turf/simulated/floor,/area/janitor)
"bNP" = (/obj/structure/mopbucket,/obj/item/weapon/mop,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor,/area/janitor)
@@ -4831,10 +4831,10 @@
"bOU" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden,/obj/structure/disposalpipe/segment,/turf/simulated/floor{dir = 8; icon_state = "cautioncorner"},/area/hallway/primary/aft)
"bOV" = (/obj/machinery/atmospherics/unary/vent_pump{on = 1},/turf/simulated/floor,/area/hallway/primary/aft)
"bOW" = (/obj/machinery/firealarm{dir = 4; pixel_x = 24},/turf/simulated/floor{dir = 2; icon_state = "yellowcorner"},/area/hallway/primary/aft)
-"bOX" = (/obj/structure/table,/obj/item/weapon/paper_bin{pixel_x = -3; pixel_y = 7},/obj/item/weapon/pen,/turf/simulated/floor,/area/janitor)
-"bOY" = (/obj/structure/table,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/machinery/requests_console{department = "Janitorial"; departmentType = 1; pixel_y = -29},/obj/item/weapon/reagent_containers/spray/cleaner,/turf/simulated/floor,/area/janitor)
-"bOZ" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/obj/machinery/light,/turf/simulated/floor,/area/janitor)
-"bPa" = (/obj/structure/stool/bed/chair/cart/janicart,/turf/simulated/floor,/area/janitor)
+"bOX" = (/obj/structure/table,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/item/weapon/grenade/chem_grenade/cleaner,/obj/machinery/requests_console{department = "Janitorial"; departmentType = 1; pixel_y = -29},/obj/item/weapon/reagent_containers/spray/cleaner,/turf/simulated/floor,/area/janitor)
+"bOY" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/turf/simulated/floor,/area/janitor)
+"bOZ" = (/obj/machinery/light,/obj/vehicle/train/janitor/trolley,/turf/simulated/floor,/area/janitor)
+"bPa" = (/obj/vehicle/train/janitor/engine,/turf/simulated/floor,/area/janitor)
"bPb" = (/obj/item/weapon/legcuffs/beartrap,/obj/item/weapon/legcuffs/beartrap,/obj/item/weapon/storage/box/mousetraps,/obj/item/weapon/storage/box/mousetraps,/turf/simulated/floor,/area/janitor)
"bPc" = (/obj/structure/reagent_dispensers/watertank,/obj/machinery/atmospherics/unary/vent_pump{dir = 4; on = 1},/turf/simulated/floor,/area/janitor)
"bPd" = (/obj/machinery/atmospherics/pipe/simple/supply/hidden{dir = 4},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating,/area/maintenance/asmaint)