diff --git a/aurora.dme b/aurora.dme
index 858cb0a4..d823f29d 100644
--- a/aurora.dme
+++ b/aurora.dme
@@ -1275,6 +1275,7 @@
#include "code\modules\projectiles\guns\projectile\bow.dm"
#include "code\modules\projectiles\guns\projectile\pistol.dm"
#include "code\modules\projectiles\guns\projectile\pneumatic.dm"
+#include "code\modules\projectiles\guns\projectile\reloadlaser.dm"
#include "code\modules\projectiles\guns\projectile\revolver.dm"
#include "code\modules\projectiles\guns\projectile\rocket.dm"
#include "code\modules\projectiles\guns\projectile\shotgun.dm"
@@ -1441,6 +1442,9 @@
#include "code\modules\telesci\gps.dm"
#include "code\modules\telesci\telepad.dm"
#include "code\modules\telesci\telesci_computer.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/datums/supplypacks.dm b/code/datums/supplypacks.dm
index f09a659a..6616fda5 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -251,6 +251,22 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containername = "MULEbot Crate"
group = "Operations"
+/datum/supply_packs/cargotrain
+ name = "Cargo Train Tug"
+ contains = list(/obj/vehicle/train/cargo/engine)
+ cost = 30
+ containertype = /obj/structure/largecrate
+ containername = "Cargo Train Tug Crate"
+ group = "Operations"
+
+/datum/supply_packs/cargotrailer
+ name = "Cargo Train Trolley"
+ contains = list(/obj/vehicle/train/cargo/trolley)
+ cost = 20
+ containertype = /obj/structure/largecrate
+ containername = "Cargo Train Trolley Crate"
+ group = "Operations"
+
/datum/supply_packs/lisa
name = "Corgi Crate"
contains = list()
diff --git a/code/game/objects/items/devices/suit_cooling.dm b/code/game/objects/items/devices/suit_cooling.dm
index 6355fd26..0da99369 100644
--- a/code/game/objects/items/devices/suit_cooling.dm
+++ b/code/game/objects/items/devices/suit_cooling.dm
@@ -5,57 +5,57 @@
icon = 'icons/obj/device.dmi'
icon_state = "suitcooler0"
slot_flags = SLOT_BACK //you can carry it on your back if you want, but it won't do anything unless attached to suit storage
-
+
//copied from tank.dm
flags = FPRINT | TABLEPASS | CONDUCT
force = 5.0
throwforce = 10.0
throw_speed = 1
throw_range = 4
-
+
origin_tech = "magnets=2;materials=2"
-
+
var/on = 0 //is it turned on?
var/cover_open = 0 //is the cover open?
var/obj/item/weapon/cell/cell
var/max_cooling = 12 //in degrees per second - probably don't need to mess with heat capacity here
- var/charge_consumption = 16.6 //charge per second at max_cooling
+ var/charge_consumption = 2 //16.6 //charge per second at max_cooling //16.6 is the original value. It eats batteries too fast.
var/thermostat = T20C
-
+
//TODO: make it heat up the surroundings when not in space
/obj/item/device/suit_cooling_unit/New()
processing_objects |= src
-
+
cell = new/obj/item/weapon/cell() //comes with the crappy default power cell - high-capacity ones shouldn't be hard to find
cell.loc = src
/obj/item/device/suit_cooling_unit/process()
- if (!on || !cell)
+ if (!on || !cell)
return
-
+
if (!ismob(loc))
return
-
+
if (!attached_to_suit(loc)) //make sure they have a suit and we are attached to it
return
-
+
var/mob/living/carbon/human/H = loc
-
+
var/efficiency = 1 - H.get_pressure_weakness() //you need to have a good seal for effective cooling
var/env_temp = get_environment_temperature() //wont save you from a fire
var/temp_adj = min(H.bodytemperature - max(thermostat, env_temp), max_cooling)
-
+
if (temp_adj < 0.5) //only cools, doesn't heat, also we don't need extreme precision
return
-
+
var/charge_usage = (temp_adj/max_cooling)*charge_consumption
-
+
H.bodytemperature -= temp_adj*efficiency
-
+
cell.use(charge_usage)
-
- if(cell.charge <= 0)
+
+ if(cell.charge <= charge_usage)
turn_off()
/obj/item/device/suit_cooling_unit/proc/get_environment_temperature()
@@ -70,22 +70,22 @@
var/turf/T = get_turf(src)
if(istype(T, /turf/space))
return 0 //space has no temperature, this just makes sure the cooling unit works in space
-
+
var/datum/gas_mixture/environment = T.return_air()
if (!environment)
return 0
-
+
return environment.temperature
/obj/item/device/suit_cooling_unit/proc/attached_to_suit(mob/M)
- if (!ishuman(M))
+ if (!ishuman(M))
return 0
-
+
var/mob/living/carbon/human/H = M
-
+
if (!H.wear_suit || H.s_store != src)
return 0
-
+
return 1
/obj/item/device/suit_cooling_unit/proc/turn_on()
@@ -93,7 +93,7 @@
return
if(cell.charge <= 0)
return
-
+
on = 1
updateicon()
@@ -149,7 +149,7 @@
user << "You insert the [cell]."
updateicon()
return
-
+
return ..()
/obj/item/device/suit_cooling_unit/proc/updateicon()
@@ -163,9 +163,9 @@
/obj/item/device/suit_cooling_unit/examine()
set src in view(1)
-
+
..()
-
+
if (on)
if (attached_to_suit(src.loc))
usr << "It's switched on and running."
@@ -173,13 +173,13 @@
usr << "It's switched on, but not attached to anything."
else
usr << "It is switched off."
-
+
if (cover_open)
if(cell)
usr << "The panel is open, exposing the [cell]."
else
usr << "The panel is open."
-
+
if (cell)
usr << "The charge meter reads [round(cell.percent())]%."
else
diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm
index 931edd3d..71b1629f 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/aurora/bluespacetech.dm b/code/modules/aurora/bluespacetech.dm
index 0de534d1..024a96e5 100644
--- a/code/modules/aurora/bluespacetech.dm
+++ b/code/modules/aurora/bluespacetech.dm
@@ -256,6 +256,20 @@
var/verb = "says in a subdued tone"
..(message, verb)
+ verb/bstwalk()
+ set name = "Ruin Everything"
+ set desc = "Uses bluespace technology to phase through solid matter and also move fast."
+ set category = "BST"
+ set popup_menu = 0
+
+ if(!src.incorporeal_move)
+ src.incorporeal_move = 2
+ src << "\blue You will now phase through solid matter."
+ else
+ src.incorporeal_move = 0
+ src << "\blue You will no-longer phase through solid matter."
+ return
+
//Equipment. All should have canremove set to 0
//All items with a /bst need the attack_hand() proc overrided to stop people getting overpowered items.
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index b56c078d..3bd9bff6 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -335,7 +335,7 @@ BLIND // can't see anything
permeability_coefficient = 0.02
flags = FPRINT | TABLEPASS | STOPSPRESSUREDMAGE | THICKMATERIAL
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
- allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency_oxygen,/obj/item/device/suit_cooling_unit)
+ allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit)
slowdown = 3
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 50)
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL
diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm
index c729c4a4..32ff5a09 100644
--- a/code/modules/clothing/spacesuits/miscellaneous.dm
+++ b/code/modules/clothing/spacesuits/miscellaneous.dm
@@ -22,7 +22,7 @@
allowed = list(/obj/item/weapon/tank/emergency_oxygen, /obj/item/device/flashlight,/obj/item/weapon/gun/energy, /obj/item/weapon/gun/projectile, /obj/item/ammo_magazine, /obj/item/ammo_casing, /obj/item/weapon/melee/baton,/obj/item/weapon/handcuffs)
slowdown = 1.5
armor = list(melee = 65, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50)
- flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL
+ flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT|HIDETAIL
cold_protection = UPPER_TORSO | LOWER_TORSO | LEGS | FEET | ARMS | HANDS
min_cold_protection_temperature = SPACE_SUIT_MIN_COLD_PROTECTION_TEMPERATURE
siemens_coefficient = 0.7
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 6d81acee..49f0c755 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -478,10 +478,9 @@
var/obj/machinery/bot/mulebot/MB = AM
MB.RunOver(src)
-/* if(istype(AM, /obj/vehicle))
+ 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
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index ca8015e6..3e58626b 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -203,7 +203,8 @@
if(!mob.canmove)
- return
+ if (mob.buckled && (istype(mob.buckled, /obj/structure/stool/bed/chair/wheelchair) || istype(mob.buckled, /obj/vehicle))) // Exception for wheelchairs
+ else return
//if(istype(mob.loc, /turf/space) || (mob.flags & NOGRAV))
// if(!mob.Process_Spacemove(0)) return 0
@@ -257,6 +258,9 @@
if(mob.machine.relaymove(mob,direct))
return
+ if(istype(mob.buckled, /obj/vehicle))
+ return mob.buckled.relaymove(mob,direct)
+
if(mob.pulledby || mob.buckled) // Wheelchair driving!
if(istype(mob.loc, /turf/space))
return // No wheelchair driving in space
diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm
index 66081658..ce0577ef 100644
--- a/code/modules/organs/organ_external.dm
+++ b/code/modules/organs/organ_external.dm
@@ -816,7 +816,7 @@ Note that amputating the affected organ does in fact remove the infection from t
return ((status & ORGAN_BROKEN) && !(status & ORGAN_SPLINTED))
/datum/organ/external/proc/is_malfunctioning()
- return ((status & ORGAN_ROBOT) && prob(brute_dam + burn_dam))
+ return ((status & ORGAN_ROBOT) && prob(brute_dam + burn_dam - 11))
//for arms and hands
/datum/organ/external/proc/process_grasp(var/obj/item/c_hand, var/hand_name)
diff --git a/code/modules/projectiles/guns/energy/erifles.dm b/code/modules/projectiles/guns/energy/erifles.dm
index 96eadadf..4d12c857 100644
--- a/code/modules/projectiles/guns/energy/erifles.dm
+++ b/code/modules/projectiles/guns/energy/erifles.dm
@@ -52,7 +52,7 @@
///////////LASER RIFLE//////////////
/obj/item/weapon/gun/energy/rifle/laser
name = "laser rifle"
- desc = "a basic weapon designed kill with concentrated energy bolts"
+ desc = "a basic weapon designed to kill with concentrated energy bolts"
icon_state = "laser"
item_state = "laser"
fire_sound = 'sound/weapons/Laser.ogg'
diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm
index a9b5b86c..e912275a 100644
--- a/code/modules/projectiles/guns/energy/laser.dm
+++ b/code/modules/projectiles/guns/energy/laser.dm
@@ -1,6 +1,6 @@
/obj/item/weapon/gun/energy/laser
name = "laser rifle"
- desc = "a basic weapon designed kill with concentrated energy bolts"
+ desc = "a basic weapon designed to kill with concentrated energy bolts"
icon_state = "laser"
item_state = "laser"
fire_sound = 'sound/weapons/Laser.ogg'
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index 2ce69211..7172382e 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -38,12 +38,14 @@
loaded -= AC //Remove casing from loaded list.
if(isnull(AC) || !istype(AC))
return 0
- AC.loc = get_turf(src) //Eject casing onto ground.
+ if(ejectshell == 1)
+ AC.loc = get_turf(src) //Eject casing onto ground. If 0, casings stay in the gun. Totally a good idea trust me okay.
if(AC.BB)
AC.desc += " This one is spent." //descriptions are magic - only when there's a projectile in the casing
in_chamber = AC.BB //Load projectile into chamber.
AC.BB.loc = src //Set projectile loc to gun.
return 1
+
return 0
diff --git a/code/modules/projectiles/guns/projectile/reloadlaser.dm b/code/modules/projectiles/guns/projectile/reloadlaser.dm
new file mode 100644
index 00000000..39da20cd
--- /dev/null
+++ b/code/modules/projectiles/guns/projectile/reloadlaser.dm
@@ -0,0 +1,179 @@
+/obj/item/weapon/gun/projectile/laser //butts
+ desc = "a basic weapon designed to kill with concentrated energy bolts."
+ name = "laser rifle"
+ caliber = "laser"
+ w_class = 3.0
+ recoil = 0
+ ammo_type = "/obj/item/ammo_casing/laser"
+ max_shells = 100
+ load_method = 2 //0 = Single shells or quick loader, 1 = box, 2 = magazine
+ fire_delay = 6
+ ejectshell = 0
+ slot_flags = SLOT_BACK
+ var/modded = 0
+ var/obj/item/weapon/reloadlasermodkit/mod
+
+ //placeholders//
+ icon_state = "laser"
+ item_state = "laser"
+ fire_sound = 'sound/weapons/Laser.ogg'
+ //placeholders// Well, okay, not the sound.
+
+ New()
+ for(var/i = 1, i <= 30, i++)
+ loaded += new ammo_type(src)
+ update_icon()
+
+ empty_mag = new /obj/item/ammo_magazine/laser/empty(src)
+ update_icon()
+ return
+
+
+
+
+/obj/item/ammo_magazine/laser/empty
+ max_ammo = 0
+
+/obj/item/ammo_magazine/laser
+ name = "charge cell (laser)"
+ desc = "A standard 30-shot cell."
+ icon_state = "12mm"
+ origin_tech = "combat=2"
+ ammo_type = "/obj/item/ammo_casing/laser"
+ max_ammo = 30
+// multiple_sprites = 1
+
+/obj/item/ammo_magazine/laser/pulse
+ name = "charge cell (pulse)"
+ desc = "A heavy-duty 15-shot pulse cell."
+ ammo_type = "/obj/item/ammo_casing/laser/pulse"
+ max_ammo = 15
+
+/obj/item/ammo_magazine/laser/heavy
+ name = "charge cell (heavy)"
+ desc = "A 15-shot cell designed to overload your projectiles with an extremely heavy charge."
+ ammo_type = "/obj/item/ammo_casing/laser/heavy"
+ max_ammo = 15
+
+/obj/item/ammo_magazine/laser/practice
+ name = "charge cell (practice)"
+ desc = "A hundred-shot cell keyed in to a harmless wavelength for practice shooting."
+ ammo_type = "/obj/item/ammo_casing/laser/practice"
+ max_ammo = 100
+
+/obj/item/ammo_magazine/laser/light
+ name = "charge cell (light)"
+ desc = "A 60-shot cell designed with capacity in mind. The lasers are weaker, though."
+ ammo_type = "/obj/item/ammo_casing/laser/light"
+ max_ammo = 60
+
+/obj/item/ammo_magazine/laser/stun
+ name = "charge cell (stun)"
+ desc = "A 20-shot cell that fires lethal incapacitating bolts. Not standard issue."
+ ammo_type = "/obj/item/ammo_casing/laser/stun"
+ max_ammo = 20
+
+////////////////////////////
+//Shells for the magazines//
+////////////////////////////
+
+//don't spawn these you butts//
+
+/obj/item/ammo_casing/laser
+ desc = "A LASER SHELL. You shouldn't be seeing this."
+ caliber = "laser"
+ projectile_type = "/obj/item/projectile/beam"
+
+/obj/item/ammo_casing/laser/pulse
+ desc = "A PULSE SHELL. You shouldn't be seeing this."
+ caliber = "laser"
+ projectile_type = "/obj/item/projectile/beam/pulse"
+
+/obj/item/ammo_casing/laser/heavy
+ desc = "A LASER CANNON SHELL. You shouldn't be seeing this."
+ caliber = "laser"
+ projectile_type = "/obj/item/projectile/beam/heavylaser"
+
+/obj/item/ammo_casing/laser/practice
+ desc = "A PRACTICE BLANK FAKE LASER SHELL. You shouldn't be seeing this."
+ caliber = "laser"
+ projectile_type = "/obj/item/projectile/beam/practice"
+
+/obj/item/ammo_casing/laser/light
+ desc = "A LIGHT LASER XRAY SHELL. You shouldn't be seeing this."
+ caliber = "laser"
+ projectile_type = "/obj/item/projectile/beam/xray/burst"
+
+/obj/item/ammo_casing/laser/stun
+ desc = "A STUN LASER SHELL. You shouldn't be seeing this."
+ caliber = "laser"
+ projectile_type = "/obj/item/projectile/beam/stun"
+
+
+////////////////////////////////
+//////////////mods//////////////
+////////////////////////////////
+
+/obj/item/weapon/reloadlasermodkit
+ desc = "A cheap, disposable modkit designed to rapidly and permanently augment NT-standard laser rifles."
+ name = "rifle nanokit"
+ var/modtype = 0
+ var/uses = 1
+ var/emagged
+ icon = 'icons/obj/assemblies.dmi'
+ icon_state = "posibrain" //the placeholders are real
+
+/* Not sure about this yet.
+/obj/item/device/megaphone/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/weapon/card/emag) && !emagged)
+ user << "\red You sneakily unlock the highly illegal military-grade burstfire augment."
+ emagged = 1
+ return
+ return
+*/
+/obj/item/weapon/reloadlasermodkit/attack_self(var/mob/user as mob)
+
+ if (!emagged)
+ if (modtype == 0)
+ user << "Size modification selected."
+ modtype = 1
+ else if (modtype == 1)
+ user << "Rapid-fire modification selected."
+ modtype = 2
+ else if (modtype == 2)
+ user << "Silencer modification selected."
+ modtype = 0
+ else if (emagged) //We'll see. Burst is ridiculous, especially on a full-power laser.
+ user << "Burstfire modification selected."
+ modtype = 3
+
+/obj/item/weapon/gun/projectile/laser/attackby(obj/item/I as obj, mob/user as mob)
+ if(istype(I, /obj/item/weapon/reloadlasermodkit))
+ if(user.l_hand != src && user.r_hand != src) //if we're not in his hands
+ user << "You'll need [src] in your hands to do that."
+ return
+ if(src.modded == 1)
+ user << "The frame can only handle one mod."
+ return
+ user.drop_item()
+ user << "You activate the modkit and watch the nanites swarm over [src]."
+ I.loc = src.mod
+ src.mod = I
+ src.modded = 1
+ if (mod.modtype == 0)
+ user << "[src]'s firerate has been increased."
+ src.fire_delay = 4
+ else if (mod.modtype == 1)
+ user << "[src]'s shape changes rapidly, becoming smaller and more economical."
+ src.w_class = 3
+ else if (mod.modtype == 2)
+ user << "[src] sprouts wave-cancelling emitters. Its shots are now silenced."
+ src.silenced = 1
+ else if (mod.modtype == 3)
+ user << "[src] rapidly reshapes its firing mechanism. It now fires in bursts."
+ src.fire_delay = 0
+ src.projectiles_per_shot = 3
+ src.fire_cooldown = 1
+ fire_sound = 'sound/weapons/Gunshot_smg.ogg'
+ return
+ ..()
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index e57d13e6..439bce57 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -87,7 +87,7 @@
return 0// nope.avi
var/distance = get_dist(starting,loc)
- var/miss_modifier = -30
+ var/miss_modifier = -60
if (istype(shot_from,/obj/item/weapon/gun)) //If you aim at someone beforehead, it'll hit more often.
var/obj/item/weapon/gun/daddy = shot_from //Kinda balanced by fact you need like 2 seconds to aim
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index 236517f3..063cbc7b 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -99,12 +99,13 @@ var/list/beam_master = list()
name = "xray beam"
icon_state = "xray"
damage = 30
+// forcedodge = -1
/obj/item/projectile/beam/xray/burst
name = "xray beam"
icon_state = "xray"
// damage = 15 this makes rapidlasers kill almost exactly as fast as the rifle, but since they do a tripleburst, armor is much more effective. plus. rng miss.
- damage = 20 //hence 20 damage. slight advantage over regular lasers. half-capacity for damage. use for coolness. use laser cannons for powergame.
+ damage = 25 //hence 25 damage. slight advantage over regular lasers. half-capacity for damage. use for coolness. use laser cannons for powergame.
/obj/item/projectile/beam/pulse
name = "pulse"
@@ -122,10 +123,10 @@ var/list/beam_master = list()
icon_state = "emitter"
damage = 30
-/obj/item/projectile/beam/stunrevolver
+/obj/item/projectile/beam/stun
name = "stun beam"
icon_state = "stun"
- damage = 10
+ damage = 20
agony = 45
/obj/item/projectile/beam/lastertag/blue
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index a9175887..d30d0217 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -88,3 +88,30 @@
*/
agony = 70
damage_type = HALLOSS
+
+
+/obj/item/projectile/energy/mining //not in the game. i'll play with it later probably.
+ name = "electrode"
+ icon_state = "spark"
+ damage = 5
+ kill_count = 3
+ var/life = 5
+
+ Bump(atom/A)
+ A.bullet_act(src, def_zone)
+ src.life -= 1
+ if(life <= 0)
+ del(src)
+ return
+
+/turf/simulated/mineral/bullet_act(var/obj/item/projectile/Proj)
+ if(istype(Proj ,/obj/item/projectile/energy/mining))
+ src.GetDrilled()
+ ..()
+ return 0
+
+/obj/structure/boulder/bullet_act(var/obj/item/projectile/Proj)
+ if(istype(Proj ,/obj/item/projectile/energy/mining))
+ del(src)
+ ..()
+ return 0
\ No newline at end of file
diff --git a/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm b/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm
index 05e6d02d..48ac8785 100644
--- a/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm
+++ b/code/modules/research/xenoarchaeology/tools/anomaly_suit.dm
@@ -20,7 +20,7 @@
icon_state = "cespace_suit"
item_state = "cespace_suit"
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 100, rad = 100)
- allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank)
+ allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank, /obj/item/device/suit_cooling_unit)
/obj/item/clothing/head/helmet/space/anomaly
name = "Excavation hood"
diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm
new file mode 100644
index 00000000..cc416aa3
--- /dev/null
+++ b/code/modules/vehicles/cargo_train.dm
@@ -0,0 +1,303 @@
+/obj/vehicle/train/cargo/engine
+ name = "cargo train tug"
+ desc = "A ridable electric car designed for pulling cargo trolleys."
+ icon = 'icons/obj/vehicles.dmi'
+ icon_state = "cargo_engine"
+ on = 0
+ powered = 1
+ locked = 0
+
+ load_item_visible = 1
+ load_offset_x = 0
+ mob_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/cargo_train/key
+
+/obj/item/weapon/key/cargo_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 = "train_keys"
+ w_class = 1
+
+/obj/vehicle/train/cargo/trolley
+ name = "cargo train trolley"
+ icon = 'icons/obj/vehicles.dmi'
+ icon_state = "cargo_trailer"
+ anchored = 0
+ passenger_allowed = 0
+ locked = 0
+
+ load_item_visible = 1
+ load_offset_x = 0
+ load_offset_y = 4
+ mob_offset_y = 8
+
+//-------------------------------------------
+// Standard procs
+//-------------------------------------------
+/obj/vehicle/train/cargo/engine/New()
+ ..()
+ cell = new /obj/item/weapon/cell/high
+ verbs -= /atom/movable/verb/pull
+ key = new()
+ var/image/I = new(icon = 'icons/obj/vehicles.dmi', icon_state = "cargo_engine_overlay", layer = src.layer + 0.2) //over mobs
+ overlays += I
+ turn_off() //so engine verbs are correctly set
+
+/obj/vehicle/train/cargo/engine/Move()
+ if(on && cell.charge < charge_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
+
+ 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/engine/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/weapon/key/cargo_train))
+ if(!key)
+ user.drop_item()
+ W.forceMove(src)
+ key = W
+ verbs += /obj/vehicle/train/cargo/engine/verb/remove_key
+ return
+ ..()
+
+/obj/vehicle/train/cargo/update_icon()
+ if(open)
+ icon_state = initial(icon_state) + "_open"
+ else
+ icon_state = initial(icon_state)
+
+/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 respects access rights
+
+ ..()
+
+/obj/vehicle/train/cargo/trolley/Bump(atom/Obstacle)
+ if(!lead)
+ return //so people can't knock others over by pushing a trolley around
+ ..()
+
+//-------------------------------------------
+// Train procs
+//-------------------------------------------
+/obj/vehicle/train/cargo/engine/turn_on()
+ if(!key)
+ return
+ else
+ ..()
+ update_stats()
+
+ verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine
+ verbs -= /obj/vehicle/train/cargo/engine/verb/start_engine
+
+ if(on)
+ verbs += /obj/vehicle/train/cargo/engine/verb/stop_engine
+ else
+ verbs += /obj/vehicle/train/cargo/engine/verb/start_engine
+
+/obj/vehicle/train/cargo/engine/turn_off()
+ ..()
+
+ verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine
+ verbs -= /obj/vehicle/train/cargo/engine/verb/start_engine
+
+ if(!on)
+ verbs += /obj/vehicle/train/cargo/engine/verb/start_engine
+ else
+ verbs += /obj/vehicle/train/cargo/engine/verb/stop_engine
+
+/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(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/cargo/engine/relaymove(mob/user, direction)
+ if(user != load)
+ return 0
+
+ if(is_train_head())
+ if(direction == reverse_direction(dir) && tow)
+ return 0
+ if(Move(get_step(src, direction)))
+ return 1
+ return 0
+ else
+ return ..()
+
+/obj/vehicle/train/cargo/engine/examine()
+ ..()
+
+ 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."
+ usr << "The charge meter reads [cell? round(cell.percent(), 0.01) : 0]%"
+
+/obj/vehicle/train/cargo/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 < charge_use)
+ usr << "[src] is out of power."
+ else
+ usr << "[src]'s engine won't start."
+
+/obj/vehicle/train/cargo/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/cargo/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/cargo/engine/verb/remove_key
+
+//-------------------------------------------
+// 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) && !istype(C, /mob/living/carbon/human))
+ return 0
+
+ ..()
+
+ if(load)
+ return 1
+
+/obj/vehicle/train/cargo/engine/load(var/atom/movable/C)
+ if(!istype(C, /mob/living/carbon/human))
+ 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_car(var/train_length, var/active_engines)
+ src.train_length = train_length
+ src.active_engines = active_engines
+
+ //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.1 //makes cargo trains 10% slower than running when not overweight
+
+/obj/vehicle/train/cargo/trolley/update_car(var/train_length, var/active_engines)
+ src.train_length = train_length
+ src.active_engines = active_engines
+
+ 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
diff --git a/code/modules/vehicles/train.dm b/code/modules/vehicles/train.dm
new file mode 100644
index 00000000..c5ca6329
--- /dev/null
+++ b/code/modules/vehicles/train.dm
@@ -0,0 +1,229 @@
+/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
+ if(lead)
+ unattach()
+ return 0
+
+/obj/vehicle/train/Bump(atom/Obstacle)
+ if(!istype(Obstacle, /atom/movable))
+ return
+ var/atom/movable/A = Obstacle
+
+ if(!A.anchored)
+ var/turf/T = get_step(A, dir)
+ if(isturf(T))
+ A.Move(T) //bump things away when hit
+
+ if(emagged)
+ if(istype(A, /mob/living))
+ var/mob/living/M = A
+ visible_message("\red [src] knocks over [M]!")
+ M.apply_effects(5, 5) //knock people down if you hit them
+ M.apply_damages(22 / move_delay) // and do damage according to how fast the train is going
+ if(istype(load, /mob/living/carbon/human))
+ var/mob/living/D = load
+ D << "\red You hit [M]!"
+ msg_admin_attack("[D.name] ([D.ckey]) hit [M.name] ([M.ckey]) with [src]. (JMP)")
+
+
+//-------------------------------------------
+// Vehicle procs
+//-------------------------------------------
+/obj/vehicle/train/explode()
+ if (tow)
+ tow.unattach()
+ unattach()
+ ..()
+
+
+//-------------------------------------------
+// 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 - this shouldn't happen - but just in case it does
+ user.forceMove(T)
+ 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(user.buckled || user.stat || user.restrained() || !Adjacent(user) || !user.Adjacent(C) || !istype(C) || (user == C && !user.canmove))
+ return
+ if(istype(C,/obj/vehicle/train))
+ latch(C, user)
+ else
+ if(!load(C))
+ user << "\red You were unable to load [C] on [src]."
+
+/obj/vehicle/train/attack_hand(mob/user as mob)
+ if(user.stat || user.restrained() || !Adjacent(user))
+ return 0
+
+ if(user != load && (user in src))
+ user.forceMove(loc) //for handling players stuck in src
+ else if(load)
+ unload(user) //unload if loaded
+ else if(!load && !user.buckled)
+ load(user) //else try climbing on board
+ else
+ return 0
+
+/obj/vehicle/train/verb/unlatch_v()
+ set name = "Unlatch"
+ set desc = "Unhitches this train from the one in front of it."
+ set category = "Object"
+ set src in view(1)
+
+ if(!istype(usr, /mob/living/carbon/human))
+ return
+
+ if(!usr.canmove || usr.stat || usr.restrained() || !Adjacent(usr))
+ return
+
+ unattach(usr)
+
+
+//-------------------------------------------
+// Latching/unlatching procs
+//-------------------------------------------
+
+//attempts to attach src as a follower of the train T
+/obj/vehicle/train/proc/attach_to(obj/vehicle/train/T, mob/user)
+ if (get_dist(src, T) > 1)
+ user << "\red [src] is too far away from [T] to hitch them together."
+ return
+
+ if (lead)
+ user << "\red [src] is already hitched to something."
+ return
+
+ if (T.tow)
+ user << "\red [T] is already towing something."
+ return
+
+ //check for cycles.
+ var/obj/vehicle/train/next_car = T
+ while (next_car)
+ if (next_car == src)
+ user << "\red That seems very silly."
+ return
+ next_car = next_car.lead
+
+ //latch with src as the follower
+ lead = T
+ T.tow = src
+ dir = lead.dir
+
+ if(user)
+ user << "\blue You hitch [src] to [T]."
+
+ update_stats()
+
+
+//detaches the train from whatever is towing it
+/obj/vehicle/train/proc/unattach(mob/user)
+ if (!lead)
+ user << "\red [src] is not hitched to anything."
+ return
+
+ lead.tow = null
+ lead.update_stats()
+
+ user << "\blue You unhitch [src] from [lead]."
+ lead = null
+
+ update_stats()
+
+/obj/vehicle/train/proc/latch(obj/vehicle/train/T, mob/user)
+ if(!istype(T) || !Adjacent(T))
+ return 0
+
+ var/T_dir = get_dir(src, T) //figure out where T is wrt src
+
+ if(dir == T_dir) //if car is ahead
+ src.attach_to(T, user)
+ else if(reverse_direction(dir) == T_dir) //else if car is behind
+ T.attach_to(src, user)
+
+//returns 1 if this is the lead car of the train
+/obj/vehicle/train/proc/is_train_head()
+ if (lead)
+ return 0
+ 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()
+ //first, seek to the end of the train
+ var/obj/vehicle/train/T = src
+ while(T.tow)
+ //check for cyclic train.
+ if (T.tow == src)
+ lead.tow = null
+ lead.update_stats()
+
+ lead = null
+ update_stats()
+ return
+ T = T.tow
+
+ //now walk back to the front.
+ var/active_engines = 0
+ var/train_length = 0
+ while(T)
+ train_length++
+ if (powered && on)
+ active_engines++
+ T.update_car(train_length, active_engines)
+ T = T.lead
+
+/obj/vehicle/train/proc/update_car(var/train_length, var/active_engines)
+ return
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
new file mode 100644
index 00000000..76fd7d89
--- /dev/null
+++ b/code/modules/vehicles/vehicle.dm
@@ -0,0 +1,358 @@
+/obj/vehicle
+ name = "vehicle"
+ icon = 'icons/obj/vehicles.dmi'
+ layer = MOB_LAYER + 0.1 //so it sits above objects including mobs
+ 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/movable = 1
+
+ var/obj/item/weapon/cell/cell
+ var/charge_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
+ var/mob_offset_y = 0 //pixel_y offset for mob overlay
+
+//-------------------------------------------
+// Standard procs
+//-------------------------------------------
+/obj/vehicle/New()
+ ..()
+ //spawn the cell you want in each vehicle
+
+/obj/vehicle/Move()
+ if(world.time > l_move_time + move_delay)
+ if(on && powered && cell.charge < charge_use)
+ turn_off()
+
+ var/init_anc = anchored
+ anchored = 0
+ if(!..())
+ anchored = init_anc
+ return 0
+
+ anchored = init_anc
+
+ if(on && powered)
+ cell.use(charge_use)
+
+ if(load)
+ load.forceMove(loc)// = loc
+ load.dir = dir
+
+ return 1
+ else
+ return 0
+
+/obj/vehicle/attackby(obj/item/weapon/W as obj, mob/user as mob)
+ if(istype(W, /obj/item/weapon/hand_labeler))
+ return
+ 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
+
+/obj/vehicle/proc/handle_rotation()
+ return
+
+//-------------------------------------------
+// Vehicle procs
+//-------------------------------------------
+/obj/vehicle/proc/turn_on()
+ if(stat)
+ return 0
+ if(powered && cell.charge < charge_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/stack/cable_coil/cut(Tsec) THIS DOESN'T WORK SO I'M GETTING RID OF IT.
+
+ if(cell)
+ cell.forceMove(Tsec)
+ cell.update_icon()
+ cell = null
+
+ //stuns people who are thrown off a train that has been blown up
+ if(istype(load, /mob/living))
+ var/mob/living/M = load
+ M.apply_effects(5, 5)
+
+ 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 < charge_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)
+ C.forceMove(src)
+ cell = C
+ 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.forceMove(get_turf(H))
+ H.put_in_hands(cell)
+ 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.forceMove(loc)
+ C.dir = dir
+ C.anchored = 1
+
+ load = C
+
+ if(load_item_visible)
+ C.pixel_x += load_offset_x
+ if(ismob(C))
+ C.pixel_y += mob_offset_y
+ else
+ C.pixel_y += load_offset_y
+ C.layer = layer + 0.1 //so it sits above the vehicle
+
+ if(ismob(C))
+ var/mob/M = C
+ M.buckled = src
+ M.update_canmove()
+
+ return 1
+
+
+/obj/vehicle/proc/unload(var/mob/user, var/direction)
+ if(!load)
+ return
+
+ 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 && load.Adjacent(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
+
+ load.forceMove(dest)
+ load.dir = get_dir(loc, dest)
+ load.anchored = initial(load.anchored)
+ 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
+ M.buckled = null
+ M.anchored = initial(M.anchored)
+ M.update_canmove()
+
+ load = null
+
+ return 1
+
+
+//-------------------------------------------------------
+// Stat update procs
+//-------------------------------------------------------
+/obj/vehicle/proc/update_stats()
+ return
\ No newline at end of file
diff --git a/data/investigate/gravity.html b/data/investigate/gravity.html
index 4864ca62..df50bfda 100644
--- a/data/investigate/gravity.html
+++ b/data/investigate/gravity.html
@@ -1,2 +1,6 @@
-00:14 [0x20077d3] (92,152,1) || the gravitational generator has regained power.
-00:14 [0x20077d3] (92,152,1) || the gravitational generator is now charging.
+00:42 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+00:42 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+00:43 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+00:43 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
+00:43 [0x20078ca] (92,152,1) || the gravitational generator has regained power.
+00:43 [0x20078ca] (92,152,1) || the gravitational generator is now charging.
diff --git a/icons/obj/vehicles.dmi b/icons/obj/vehicles.dmi
index fd6daee8..e7027559 100644
Binary files a/icons/obj/vehicles.dmi and b/icons/obj/vehicles.dmi differ