diff --git a/baystation12.dme b/baystation12.dme
index 85fa384377..e5ad012bbc 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -1290,6 +1290,9 @@
#include "code\modules\surgery\ribcage.dm"
#include "code\modules\surgery\robolimbs.dm"
#include "code\modules\surgery\surgery.dm"
+#include "code\modules\vehicles\cargo_train.dm"
+#include "code\modules\vehicles\train.dm"
+#include "code\modules\vehicles\vehicle.dm"
#include "code\modules\virus2\analyser.dm"
#include "code\modules\virus2\antibodies.dm"
#include "code\modules\virus2\centrifuge.dm"
diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm
index 7d4db127c8..f8047e5f2e 100644
--- a/code/game/objects/items/weapons/cards_ids.dm
+++ b/code/game/objects/items/weapons/cards_ids.dm
@@ -100,7 +100,8 @@
/obj/machinery/bot,
/obj/machinery/door,
/obj/machinery/telecomms,
- /obj/machinery/mecha_part_fabricator
+ /obj/machinery/mecha_part_fabricator,
+ /obj/vehicle
)
@@ -200,7 +201,7 @@
access = list(access_maint_tunnels, access_syndicate, access_external_airlocks)
origin_tech = "syndicate=3"
var/registered_user=null
-
+
/obj/item/weapon/card/id/syndicate/New(mob/user as mob)
..()
if(!isnull(user)) // Runtime prevention on laggy starts or where users log out because of lag at round start.
@@ -208,7 +209,7 @@
else
registered_name = "Agent Card"
assignment = "Agent"
- name = "[registered_name]'s ID Card ([assignment])"
+ name = "[registered_name]'s ID Card ([assignment])"
/obj/item/weapon/card/id/syndicate/afterattack(var/obj/item/weapon/O as obj, mob/user as mob, proximity)
if(!proximity) return
@@ -239,7 +240,7 @@
registered_user = user
else if(!registered_user || registered_user == user)
- if(!registered_user) registered_user = user //
+ if(!registered_user) registered_user = user //
switch(alert("Would you like to display the ID, or retitle it?","Choose.","Rename","Show"))
if("Rename")
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 7b254cf890..2925449d0e 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -440,12 +440,17 @@
return
// called when something steps onto a human
-// this could be made more general, but for now just handle mulebot
+// this handles mulebots and vehicles
/mob/living/carbon/human/HasEntered(var/atom/movable/AM)
- var/obj/machinery/bot/mulebot/MB = AM
- if(istype(MB))
+ if(istype(AM, /obj/machinery/bot/mulebot))
+ var/obj/machinery/bot/mulebot/MB = AM
MB.RunOver(src)
+ if(istype(AM, /obj/vehicle))
+ var/obj/vehicle/V = AM
+ V.RunOver(src)
+
+
//gets assignment from ID or ID inside PDA or PDA itself
//Useful when player do something with computers
/mob/living/carbon/human/proc/get_assignment(var/if_no_id = "No id", var/if_no_job = "No job")
diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm
new file mode 100644
index 0000000000..559c9dbc35
--- /dev/null
+++ b/code/modules/vehicles/cargo_train.dm
@@ -0,0 +1,266 @@
+/obj/vehicle/train/cargo/engine
+ name = "cargo train tug"
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "mulebot1" //mulebot icons until I get some proper icons
+ on = 1
+ powered = 1
+ locked = 0
+
+ load_item_visible = 1
+ load_offset_x = 0
+ load_offset_y = 9
+
+ var/car_limit = 3 //how many cars an engine can pull before performance degrades
+ var/lead_engine = 0 //if the engine is the lead engine - set automatically
+
+/obj/vehicle/train/cargo/trolley
+ name = "cargo train trolley"
+ icon = 'icons/obj/aibots.dmi'
+ icon_state = "mulebot0"
+ anchored = 0
+ passenger_allowed = 0
+ locked = 0
+
+ load_item_visible = 1
+ load_offset_x = 0
+ load_offset_y = 9
+
+//-------------------------------------------
+// Standard procs
+//-------------------------------------------
+/obj/vehicle/train/cargo/engine/New()
+ ..()
+ cell = new /obj/item/weapon/cell/high
+ verbs -= /atom/movable/verb/pull
+
+/obj/vehicle/train/cargo/engine/initialize()
+ ..()
+ if(!lead)
+ lead_engine = 1
+
+/obj/vehicle/train/cargo/engine/Move()
+ if(on && cell.charge < power_use)
+ turn_off()
+ update_stats()
+ if(load && lead_engine)
+ load << "The drive motor briefly whines, then crawls to a stop."
+ if(lead_engine && !on)
+ return 0
+
+ return ..()
+
+/obj/vehicle/train/cargo/trolley/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(open && istype(W, /obj/item/weapon/wirecutters))
+ passenger_allowed = !passenger_allowed
+ user.visible_message("[user] [passenger_allowed ? "cuts" : "mends"] a cable in [src].","You [passenger_allowed ? "cut" : "mend"] the load limiter cable.")
+ else
+ ..()
+
+/obj/vehicle/train/cargo/update_icon()
+ if(open)
+ icon_state = "mulebot-hatch"
+ else
+ icon_state = initial(icon_state)
+
+/obj/vehicle/train/cargo/engine/Emag(mob/user as mob)
+ ..()
+ flick("mulebot-emagged", src)
+
+/obj/vehicle/train/cargo/trolley/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H)
+ return
+
+/obj/vehicle/train/cargo/engine/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H)
+ ..()
+ update_stats()
+
+/obj/vehicle/train/cargo/engine/remove_cell(var/mob/living/carbon/human/H)
+ ..()
+ update_stats()
+
+/obj/vehicle/train/cargo/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
+
+ ..()
+
+//-------------------------------------------
+// Train procs
+//-------------------------------------------
+/obj/vehicle/train/cargo/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/cargo/trolley/RunOver(var/mob/living/carbon/human/H)
+ ..()
+ attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])")
+
+/obj/vehicle/train/cargo/engine/RunOver(var/mob/living/carbon/human/H)
+ ..()
+
+ if(lead_engine && 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])")
+ else
+ attack_log += text("\[[time_stamp()]\] ran over [H.name] ([H.ckey])")
+
+
+//-------------------------------------------
+// Interaction procs
+//-------------------------------------------
+/obj/vehicle/train/cargo/trolley/verb/rotate()
+ set name = "Rotate"
+ set category = "Object"
+ set src in view(1)
+
+ if(anchored)
+ usr << "You cannot turn the trolley while it is latched onto a train."
+ return
+
+ var/cur_dir = null
+ switch(dir)
+ if(NORTH)
+ cur_dir = "North"
+ if(SOUTH)
+ cur_dir = "South"
+ if(EAST)
+ cur_dir = "East"
+ if(WEST)
+ cur_dir = "West"
+
+ var/new_dir = input("Select a new direction:", "Rotate", cur_dir) in list("North", "South", "East", "West")
+
+ switch(new_dir)
+ if("North")
+ dir = NORTH
+ if("South")
+ dir = SOUTH
+ if("East")
+ dir = EAST
+ if("West")
+ dir = WEST
+
+
+/obj/vehicle/train/cargo/engine/relaymove(mob/user, direction)
+ if(user != load)
+ return 0
+
+ if(lead_engine)
+ if(direction == reverse_direction(dir))
+ return 0
+ if(Move(get_step(src, direction)))
+ return 1
+ return 0
+ else
+ return ..()
+
+
+/obj/vehicle/train/cargo/engine/verb/start_engine()
+ set name = "Start engine"
+ set category = "Object"
+ set src in view(1)
+
+ if(on)
+ usr << "The engine is already running."
+ return
+
+ if(turn_on())
+ usr << "You start [src]."
+ else
+ if(cell.charge < power_use)
+ usr << "[src] is out of power."
+ else
+ usr << "[src] won't start."
+
+//-------------------------------------------
+// Latching/unlatching procs
+//-------------------------------------------
+/obj/vehicle/train/cargo/trolley/latch(var/obj/vehicle/train/T)
+ if(..())
+ //if this is a trolley, and is now part of a train, anchor it so it cant be pushed around
+ if(lead || tow)
+ anchored = 1
+ return 1
+ else
+ return 0
+
+/obj/vehicle/train/cargo/trolley/unlatch()
+ if(..())
+ //if this carraige isn't part of a train anymore; unanchor it so it can be pushed around
+ if(!tow && !lead)
+ anchored = 0
+ return 1
+ else
+ return 0
+
+
+/obj/vehicle/train/cargo/engine/latch(var/obj/vehicle/train/T)
+ if(..())
+ //check if this is not the lead engine
+ if(lead)
+ lead_engine = 0
+ return 1
+ else
+ return 0
+
+/obj/vehicle/train/cargo/engine/unlatch()
+ if(..())
+ //check if this is now the lead engine
+ if(!lead)
+ lead_engine = 1
+ return 1
+ else
+ return 0
+
+
+//-------------------------------------------
+// Loading/unloading procs
+//-------------------------------------------
+/obj/vehicle/train/cargo/trolley/load(var/atom/movable/C)
+ if(ismob(C) && !passenger_allowed)
+ return 0
+ if(!istype(C,/obj/machinery) && !istype(C,/obj/structure/closet) && !istype(C,/obj/structure/largecrate) && !istype(C,/obj/structure/reagent_dispensers) && !istype(C,/obj/structure/ore_box) && !ismob(C))
+ return 0
+
+ return ..()
+
+/obj/vehicle/train/cargo/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/cargo/engine/update_train_stats()
+ ..()
+
+ speed_calc()
+
+ if(!lead) //check if this is the lead engine
+ lead_engine = 1
+
+/obj/vehicle/train/cargo/engine/proc/speed_calc()
+ if(!lead_engine)
+ 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 *= 0.75 //makes cargo trains 25% faster than running when not overweight
\ No newline at end of file
diff --git a/code/modules/vehicles/train.dm b/code/modules/vehicles/train.dm
new file mode 100644
index 0000000000..521fde0cd7
--- /dev/null
+++ b/code/modules/vehicles/train.dm
@@ -0,0 +1,200 @@
+/obj/vehicle/train
+ name = "train"
+ dir = 4
+
+ move_delay = 1
+
+ health = 100
+ maxhealth = 100
+ fire_dam_coeff = 0.7
+ brute_dam_coeff = 0.5
+
+ var/passenger_allowed = 1
+
+ var/active_engines = 0
+ var/train_length = 0
+
+ var/obj/vehicle/train/lead
+ var/obj/vehicle/train/tow
+
+
+//-------------------------------------------
+// Standard procs
+//-------------------------------------------
+/obj/vehicle/train/initialize()
+ for(var/obj/vehicle/train/T in orange(1, src))
+ latch(T)
+
+/obj/vehicle/train/Move()
+ var/old_loc = get_turf(src)
+ if(..())
+ if(tow)
+ tow.Move(old_loc)
+ return 1
+ else
+ return 0
+
+/obj/vehicle/train/Bump(atom/Obstacle)
+ if(!istype(Obstacle, /atom/movable) || !anchored)
+ return
+
+ var/atom/movable/A = Obstacle
+
+ if(!A.anchored)
+ var/turf/T = get_step(A, dir)
+ if(isturf(T))
+ if(!emagged) //if not emagged, bump people away, else just run over them
+ A.Move(T)
+ else if(!ismob(A)) //always bump objects even if emagged
+ A.Move(T)
+
+ if(istype(A, /mob/living))
+ var/mob/living/M = A
+ if(istype(load, /mob/living/carbon/human))
+ load << "\red You hit [M]!"
+ visible_message("\red [src] knocks over [M]!")
+ M.apply_effects(5, 5) //knock people down if you hit them
+ if(emagged) //and do damage if it's emagged
+ M.apply_damages(5 * train_length / move_delay) // according to how fast the train is going and how heavy it is
+
+
+//-------------------------------------------
+// Interaction procs
+//-------------------------------------------
+/obj/vehicle/train/relaymove(mob/user, direction)
+ var/turf/T = get_step_to(src, get_step(src, direction))
+ if(!T)
+ user << "You can't find a clear area to step onto."
+ return 0
+
+ if(user != load)
+ if(user in src) //for handling players stuck in src
+ unload(user, direction, 1)
+ return 1
+ return 0
+
+ unload(user, direction)
+
+ user << "\blue You climb down from [src]."
+
+ return 1
+
+/obj/vehicle/train/MouseDrop_T(var/atom/movable/C, mob/user as mob)
+ if(!usr.canmove || usr.stat || usr.restrained() || !Adjacent(usr) || !user.Adjacent(C))
+ return
+
+ if(istype(C,/obj/vehicle/train))
+ if(latch(C))
+ user << "\blue You successfully connect the [C] to [src]."
+ else
+ user << "\red You were unable to connect the [C] to [src]."
+ return
+
+ if(!load(C))
+ user << "\red You were unable to load [C] on [src]."
+
+/obj/vehicle/train/attack_hand(mob/user as mob)
+ if(!user.canmove || user.stat || user.restrained() || !Adjacent(user))
+ return 0
+
+ if(user != load && (user in src))
+ unload(user, null, 1) //for handling players stuck in src
+ else if(load)
+ unload(user) //unload if loaded
+ else if(!load)
+ load(user) //else try climbing on board
+ else
+ return 0
+
+/obj/vehicle/train/verb/unlatch_v()
+ set name = "Unlatch"
+ set category = "Object"
+ set src in view(1)
+
+ if(!usr.canmove || usr.stat || usr.restrained() || !Adjacent(usr))
+ return
+
+ if(unlatch())
+ usr << "\blue You unlatch [src]."
+ else
+ usr << "\red [src] is already unlatched."
+
+
+//-------------------------------------------
+// Latching/unlatching procs
+//-------------------------------------------
+/obj/vehicle/train/proc/latch(var/obj/vehicle/train/T)
+ if(!istype(T) || !Adjacent(T))
+ return 0
+
+ if(dir != T.dir) //cars need to be inline to latch
+ return 0
+
+ var/T_dir = get_dir(src, T)
+
+ if(dir & T_dir) //if car is ahead
+ if(!lead && !T.tow)
+ lead = T
+ T.tow = src
+ else
+ return 0
+ else if(reverse_direction(dir) & T_dir) //else if car is behind
+ if(!tow && !T.lead)
+ tow = T
+ T.lead = src
+ else
+ return 0
+ else
+ return 0
+
+ update_stats()
+
+ return 1
+
+/obj/vehicle/train/proc/unlatch()
+ if(!lead && !tow)
+ return 0
+
+ if(tow)
+ tow.lead = null
+ tow.update_stats()
+ tow = null
+ if(lead)
+ lead.tow = null
+ lead.update_stats()
+ lead = null
+
+ update_stats()
+
+ return 1
+
+
+
+//-------------------------------------------------------
+// Stat update procs
+//
+// Used for updating the stats for how long the train is.
+// These are useful for calculating speed based on the
+// size of the train, to limit super long trains.
+//-------------------------------------------------------
+/obj/vehicle/train/update_stats()
+ if(!tow)
+ update_train_stats()
+ else
+ return tow.update_stats()
+
+/obj/vehicle/train/proc/update_train_stats()
+ if(powered && on)
+ active_engines = 1 //increment active engine count if this is a running engine
+ else
+ active_engines = 0
+
+ train_length = 1
+
+ if(tow)
+ active_engines += tow.active_engines
+ train_length += tow.train_length
+
+ //update the next section of train ahead of us
+ if(lead)
+ lead.update_train_stats()
\ No newline at end of file
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
new file mode 100644
index 0000000000..6ae7f3ee14
--- /dev/null
+++ b/code/modules/vehicles/vehicle.dm
@@ -0,0 +1,378 @@
+/obj/vehicle
+ name = "vehicle"
+ icon = 'icons/obj/vehicles.dmi'
+ layer = MOB_LAYER
+ density = 1
+ anchored = 1
+ animate_movement=1
+ luminosity = 3
+
+ var/attack_log = null
+ var/on = 0
+ var/health = 0 //do not forget to set health for your vehicle!
+ var/maxhealth = 0
+ var/fire_dam_coeff = 1.0
+ var/brute_dam_coeff = 1.0
+ var/open = 0 //Maint panel
+ var/locked = 1
+ var/stat = 0
+ var/emagged = 0
+ var/powered = 0 //set if vehicle is powered and should use fuel when moving
+ var/move_delay = 1 //set this to limit the speed of the vehicle
+
+ var/obj/item/weapon/cell/cell
+ var/power_use = 5 //set this to adjust the amount of power the vehicle uses per move
+
+ var/atom/movable/load //all vehicles can take a load, since they should all be a least drivable
+ var/load_item_visible = 1 //set if the loaded item should be overlayed on the vehicle sprite
+ var/load_offset_x = 0 //pixel_x offset for item overlay
+ var/load_offset_y = 0 //pixel_y offset for item overlay
+
+//-------------------------------------------
+// Standard procs
+//-------------------------------------------
+/obj/vehicle/New()
+ ..()
+ //spawn the cell you want in each vehicle
+
+/obj/vehicle/Move()
+ if(world.timeofday > l_move_time + move_delay)
+ if(on && powered && cell.charge < power_use)
+ turn_off()
+
+ var/init_anc = anchored
+ anchored = 0
+ if(..())
+ if(on && powered)
+ cell.use(power_use)
+ anchored = init_anc
+
+ return 1
+ else
+ return 0
+
+/obj/vehicle/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/weapon/screwdriver))
+ if(!locked)
+ open = !open
+ update_icon()
+ user << "Maintenance panel is now [open ? "opened" : "closed"]."
+ else if(istype(W, /obj/item/weapon/crowbar) && cell && open)
+ remove_cell(user)
+
+ else if(istype(W, /obj/item/weapon/cell) && !cell && open)
+ insert_cell(W, user)
+ else if(istype(W, /obj/item/weapon/weldingtool))
+ var/obj/item/weapon/weldingtool/T = W
+ if(T.welding)
+ if(health < maxhealth)
+ if(open)
+ health = min(maxhealth, health+10)
+ user.visible_message("\red [user] repairs [src]!","\blue You repair [src]!")
+ else
+ user << "Unable to repair with the maintenance panel closed."
+ else
+ user << "[src] does not need a repair."
+ else
+ user << "Unable to repair while [src] is off."
+ else if(istype(W, /obj/item/weapon/card/emag) && !emagged)
+ Emag(user)
+ else if(hasvar(W,"force") && hasvar(W,"damtype"))
+ switch(W.damtype)
+ if("fire")
+ health -= W.force * fire_dam_coeff
+ if("brute")
+ health -= W.force * brute_dam_coeff
+ ..()
+ healthcheck()
+ else
+ ..()
+
+/obj/vehicle/attack_animal(var/mob/living/simple_animal/M as mob)
+ if(M.melee_damage_upper == 0) return
+ health -= M.melee_damage_upper
+ src.visible_message("\red [M] has [M.attacktext] [src]!")
+ M.attack_log += text("\[[time_stamp()]\] attacked [src.name]")
+ if(prob(10))
+ new /obj/effect/decal/cleanable/blood/oil(src.loc)
+ healthcheck()
+
+/obj/vehicle/bullet_act(var/obj/item/projectile/Proj)
+ health -= Proj.damage
+ ..()
+ healthcheck()
+
+/obj/vehicle/meteorhit()
+ explode()
+ return
+
+/obj/vehicle/blob_act()
+ src.health -= rand(20,40)*fire_dam_coeff
+ healthcheck()
+ return
+
+/obj/vehicle/ex_act(severity)
+ switch(severity)
+ if(1.0)
+ explode()
+ return
+ if(2.0)
+ health -= rand(5,10)*fire_dam_coeff
+ health -= rand(10,20)*brute_dam_coeff
+ healthcheck()
+ return
+ if(3.0)
+ if (prob(50))
+ health -= rand(1,5)*fire_dam_coeff
+ health -= rand(1,5)*brute_dam_coeff
+ healthcheck()
+ return
+ return
+
+/obj/vehicle/emp_act(severity)
+ var/was_on = on
+ stat |= EMPED
+ var/obj/effect/overlay/pulse2 = new/obj/effect/overlay ( src.loc )
+ pulse2.icon = 'icons/effects/effects.dmi'
+ pulse2.icon_state = "empdisable"
+ pulse2.name = "emp sparks"
+ pulse2.anchored = 1
+ pulse2.dir = pick(cardinal)
+
+ spawn(10)
+ pulse2.delete()
+ if(on)
+ turn_off()
+ spawn(severity*300)
+ stat &= ~EMPED
+ if(was_on)
+ turn_on()
+
+/obj/vehicle/attack_ai(mob/user as mob)
+ return
+
+
+//-------------------------------------------
+// Vehicle procs
+//-------------------------------------------
+/obj/vehicle/proc/turn_on()
+ if(stat)
+ return 0
+ if(powered && cell.charge < power_use)
+ return 0
+ on = 1
+ luminosity = initial(luminosity)
+ update_icon()
+ return 1
+
+/obj/vehicle/proc/turn_off()
+ on = 0
+ luminosity = 0
+ update_icon()
+
+/obj/vehicle/proc/Emag(mob/user as mob)
+ emagged = 1
+
+ if(locked)
+ locked = 0
+ user << "You bypass [src]'s controls."
+
+/obj/vehicle/proc/explode()
+ src.visible_message("\red [src] blows apart!", 1)
+ var/turf/Tsec = get_turf(src)
+
+ new /obj/item/stack/rods(Tsec)
+ new /obj/item/stack/rods(Tsec)
+ new /obj/item/weapon/cable_coil/cut(Tsec)
+
+ if(cell)
+ cell.loc = Tsec
+ cell.update_icon()
+ cell = null
+
+ unload()
+
+ new /obj/effect/gibspawner/robot(Tsec)
+ new /obj/effect/decal/cleanable/blood/oil(src.loc)
+
+ del(src)
+
+/obj/vehicle/proc/healthcheck()
+ if(health <= 0)
+ explode()
+
+/obj/vehicle/proc/powercheck()
+ if(!cell && !powered)
+ return
+
+ if(!cell && powered)
+ turn_off()
+ return
+
+ if(cell.charge < power_use)
+ turn_off()
+ return
+
+ if(cell && powered)
+ turn_on()
+ return
+
+/obj/vehicle/proc/insert_cell(var/obj/item/weapon/cell/C, var/mob/living/carbon/human/H)
+ if(cell)
+ return
+ if(!istype(C))
+ return
+
+ H.drop_from_inventory(C)
+ cell = C
+ C.loc = null //this wont be GC'd since it's referrenced above
+ powercheck()
+ usr << "You install [C] in [src]."
+
+/obj/vehicle/proc/remove_cell(var/mob/living/carbon/human/H)
+ if(!cell)
+ return
+
+ usr << "You remove [cell] from [src]."
+ cell.loc = get_turf(H)
+ cell = null
+ powercheck()
+
+/obj/vehicle/proc/RunOver(var/mob/living/carbon/human/H)
+ return //write specifics for different vehicles
+
+//-------------------------------------------
+// Loading/unloading procs
+//
+// Set specific item restriction checks in
+// the vehicle load() definition before
+// calling this parent proc.
+//-------------------------------------------
+/obj/vehicle/proc/load(var/atom/movable/C)
+ //define allowed items for loading in specific vehicle definitions
+
+ if(!isturf(C.loc)) //To prevent loading things from someone's inventory, which wouldn't get handled properly.
+ return 0
+ if(load || C.anchored)
+ return 0
+
+ // if a create/closet, close before loading
+ var/obj/structure/closet/crate = C
+ if(istype(crate))
+ crate.close()
+
+ C.loc = loc
+ sleep(2)
+ if(C.loc != loc) //To prevent you from going onto more than one train.
+ return 0
+ C.loc = src
+
+ load = C
+
+ if(load_item_visible)
+ C.pixel_x += load_offset_x
+ C.pixel_y += load_offset_y
+ C.layer = layer
+
+ overlays += C
+
+ //we can set these back now since we have already cloned the icon into the overlay
+ C.pixel_x = initial(C.pixel_x)
+ C.pixel_y = initial(C.pixel_y)
+ C.layer = initial(C.layer)
+
+ if(ismob(C))
+ var/mob/M = C
+ if(M.client)
+ M.client.perspective = EYE_PERSPECTIVE
+ M.client.eye = src
+
+ return 1
+
+
+/obj/vehicle/proc/unload(var/mob/user, var/direction, var/exception = 0)
+ if(!load)
+ // in case non-load items end up in contents, dump everything else too
+ for(var/atom/movable/AM in src)
+ AM.loc = get_turf(src)
+ AM.pixel_x = initial(AM.pixel_x)
+ AM.pixel_y = initial(AM.pixel_y)
+ AM.layer = initial(AM.layer)
+ if(ismob(AM))
+ var/mob/M = AM
+ if(M.client)
+ M.client.perspective = MOB_PERSPECTIVE
+ M.client.eye = src
+ return 0
+
+ var/turf/dest = null
+
+ //find a turf to unload to
+ if(direction) //if direction specified, unload in that direction
+ dest = get_step(src, direction)
+ else if(user) //if a user has unloaded the vehicle, unload at their feet
+ dest = get_turf(user)
+
+ if(!dest)
+ dest = get_step_to(src, get_step(src, turn(dir, 90))) //try unloading to the side of the vehicle first if neither of the above are present
+
+ //if these all result in the same turf as the vehicle or nullspace, pick a new turf with open space
+ if(!dest || dest == get_turf(src))
+ var/list/options = new()
+ for(var/test_dir in alldirs)
+ var/new_dir = get_step_to(src, get_step(src, test_dir))
+ if(new_dir)
+ options += new_dir
+ if(options.len)
+ dest = pick(options)
+ else
+ dest = get_turf(src) //otherwise just dump it on the same turf as the vehicle
+
+ if(!isturf(dest)) //if there still is nowhere to unload, cancel out since the vehicle is probably in nullspace
+ return 0
+
+
+ if(exception) //for handling any players that end up in src.contents that are trying to climb off
+ user.loc = dest
+ user.pixel_x = initial(user.pixel_x)
+ user.pixel_y = initial(user.pixel_y)
+ user.layer = initial(user.layer)
+
+ if(ismob(user))
+ var/mob/M = user
+ if(M.client)
+ M.client.perspective = MOB_PERSPECTIVE
+ M.client.eye = src
+
+ src.contents -= user
+
+ return 1
+
+ overlays.Cut()
+
+ load.loc = dest
+
+ /*
+ load.pixel_x = initial(load.pixel_x)
+ load.pixel_y = initial(load.pixel_y)
+ load.layer = initial(load.layer)
+ */
+
+ if(ismob(load))
+ var/mob/M = load
+ if(M.client)
+ M.client.perspective = MOB_PERSPECTIVE
+ M.client.eye = src
+
+ load = null
+
+ unload() //recursive check for anything left in contents
+
+ return 1
+
+
+//-------------------------------------------------------
+// Stat update procs
+//-------------------------------------------------------
+/obj/vehicle/proc/update_stats()
+ return
\ No newline at end of file