diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 5fd925b54cf..0a1cd55d29c 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -23,30 +23,6 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
//define THIS_PROC_TYPE_WEIRD_STR "[THIS_PROC_TYPE_WEIRD]" //Included for completeness
//define THIS_PROC_TYPE_WEIRD_STR_WITH_ARGS "[THIS_PROC_TYPE_WEIRD]([args.Join(",")])" //Ditto
-#define MIDNIGHT_ROLLOVER 864000 //number of deciseconds in a day
-
-#define JANUARY 1
-#define FEBRUARY 2
-#define MARCH 3
-#define APRIL 4
-#define MAY 5
-#define JUNE 6
-#define JULY 7
-#define AUGUST 8
-#define SEPTEMBER 9
-#define OCTOBER 10
-#define NOVEMBER 11
-#define DECEMBER 12
-
-//Select holiday names -- If you test for a holiday in the code, make the holiday's name a define and test for that instead
-#define NEW_YEAR "New Year"
-#define VALENTINES "Valentine's Day"
-#define APRIL_FOOLS "April Fool's Day"
-#define EASTER "Easter"
-#define HALLOWEEN "Halloween"
-#define CHRISTMAS "Christmas"
-#define FESTIVE_SEASON "Festive Season"
-
//Human Overlays Indexes/////////
#define MUTATIONS_LAYER 26 //mutations. Tk headglows, cold resistance glow, etc
#define BODY_BEHIND_LAYER 25 //certain mutantrace features (tail when looking south) that must appear behind the body parts
diff --git a/code/__DEFINES/move_force.dm b/code/__DEFINES/move_force.dm
new file mode 100644
index 00000000000..2b8faeb60d6
--- /dev/null
+++ b/code/__DEFINES/move_force.dm
@@ -0,0 +1,20 @@
+//Defaults
+#define MOVE_FORCE_DEFAULT 1000
+#define MOVE_RESIST_DEFAULT 1000
+#define PULL_FORCE_DEFAULT 1000
+
+//Factors/modifiers
+#define MOVE_FORCE_PULL_RATIO 1 //Same move force to pull objects
+#define MOVE_FORCE_PUSH_RATIO 1 //Same move force to normally push
+#define MOVE_FORCE_FORCEPUSH_RATIO 2 //2x move force to forcefully push
+#define MOVE_FORCE_CRUSH_RATIO 3 //3x move force to do things like crush objects
+#define MOVE_FORCE_THROW_RATIO 1 //Same force throw as resist to throw objects
+
+#define MOVE_FORCE_OVERPOWERING MOVE_FORCE_DEFAULT * MOVE_FORCE_CRUSH_RATIO * 10
+#define MOVE_FORCE_EXTREMELY_STRONG MOVE_FORCE_DEFAULT * MOVE_FORCE_CRUSH_RATIO * 3
+#define MOVE_FORCE_VERY_STRONG (MOVE_FORCE_DEFAULT * MOVE_FORCE_CRUSH_RATIO) - 1
+#define MOVE_FORCE_STRONG MOVE_FORCE_DEFAULT * 2
+#define MOVE_FORCE_NORMAL MOVE_FORCE_DEFAULT
+#define MOVE_FORCE_WEAK MOVE_FORCE_DEFAULT / 2
+#define MOVE_FORCE_VERY_WEAK (MOVE_FORCE_DEFAULT / MOVE_FORCE_CRUSH_RATIO) + 1
+#define MOVE_FORCE_EXTREMELY_WEAK MOVE_FORCE_DEFAULT / (MOVE_FORCE_CRUSH_RATIO * 3)
diff --git a/code/__DEFINES/time.dm b/code/__DEFINES/time.dm
index 27f6eae8b6e..9a2993ee65b 100644
--- a/code/__DEFINES/time.dm
+++ b/code/__DEFINES/time.dm
@@ -1,3 +1,27 @@
+#define MIDNIGHT_ROLLOVER 864000 //number of deciseconds in a day
+
+#define JANUARY 1
+#define FEBRUARY 2
+#define MARCH 3
+#define APRIL 4
+#define MAY 5
+#define JUNE 6
+#define JULY 7
+#define AUGUST 8
+#define SEPTEMBER 9
+#define OCTOBER 10
+#define NOVEMBER 11
+#define DECEMBER 12
+
+//Select holiday names -- If you test for a holiday in the code, make the holiday's name a define and test for that instead
+#define NEW_YEAR "New Year"
+#define VALENTINES "Valentine's Day"
+#define APRIL_FOOLS "April Fool's Day"
+#define EASTER "Easter"
+#define HALLOWEEN "Halloween"
+#define CHRISTMAS "Christmas"
+#define FESTIVE_SEASON "Festive Season"
+
/*
Days of the week to make it easier to reference them.
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index be20918485a..f311997ca95 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1266,7 +1266,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
invisibility = 101
density = FALSE
see_in_dark = 1e6
- anchored = TRUE
+ move_resist = INFINITY
var/ready_to_die = FALSE
/mob/dview/Initialize() //Properly prevents this mob from gaining huds or joining any global lists
diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm
index de58c1a0d70..7be3f82d151 100644
--- a/code/controllers/subsystem/throwing.dm
+++ b/code/controllers/subsystem/throwing.dm
@@ -54,6 +54,7 @@ SUBSYSTEM_DEF(throwing)
var/dist_y
var/dx
var/dy
+ var/force = MOVE_FORCE_DEFAULT
var/pure_diagonal
var/diagonal_error
var/datum/callback/callback
@@ -116,7 +117,7 @@ SUBSYSTEM_DEF(throwing)
return
dist_travelled++
-
+
if (dist_travelled > MAX_THROWING_DIST)
finalize()
return
diff --git a/code/datums/martial/cqc.dm b/code/datums/martial/cqc.dm
index 55cd4a3f7aa..c2322a3c31a 100644
--- a/code/datums/martial/cqc.dm
+++ b/code/datums/martial/cqc.dm
@@ -126,7 +126,7 @@
if(A.grab_state >= GRAB_AGGRESSIVE)
D.grabbedby(A, 1)
else
- A.start_pulling(D, 1)
+ A.start_pulling(D, supress_message = TRUE)
if(A.pulling)
D.stop_pulling()
log_combat(A, D, "grabbed", addition="aggressively")
diff --git a/code/datums/martial/psychotic_brawl.dm b/code/datums/martial/psychotic_brawl.dm
index b17d52f4604..4a3000548cb 100644
--- a/code/datums/martial/psychotic_brawl.dm
+++ b/code/datums/martial/psychotic_brawl.dm
@@ -24,7 +24,7 @@
if(A.grab_state >= GRAB_AGGRESSIVE)
D.grabbedby(A, 1)
else
- A.start_pulling(D, 1)
+ A.start_pulling(D, supress_message = TRUE)
if(A.pulling)
D.drop_all_held_items()
D.stop_pulling()
diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm
index 9b41e72d344..e9fd9a94f91 100644
--- a/code/datums/martial/sleeping_carp.dm
+++ b/code/datums/martial/sleeping_carp.dm
@@ -106,7 +106,7 @@
if(A.grab_state >= GRAB_AGGRESSIVE)
D.grabbedby(A, 1)
else
- A.start_pulling(D, 1)
+ A.start_pulling(D, supress_message = TRUE)
if(A.pulling)
D.drop_all_held_items()
D.stop_pulling()
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 69332489f90..ddf8b0fa512 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -298,7 +298,7 @@
SEND_SIGNAL(src, COMSIG_ATOM_FIRE_ACT, exposed_temperature, exposed_volume)
return
-/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked)
+/atom/proc/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(density && !has_gravity(AM)) //thrown stuff bounces off dense stuff in no grav, unless the thrown stuff ends up inside what it hit(embedding, bola, etc...).
addtimer(CALLBACK(src, .proc/hitby_react, AM), 2)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index ba840d0771f..90939bb0eea 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -3,6 +3,9 @@
var/last_move = null
var/last_move_time = 0
var/anchored = FALSE
+ var/move_resist = MOVE_RESIST_DEFAULT
+ var/move_force = MOVE_FORCE_DEFAULT
+ var/pull_force = PULL_FORCE_DEFAULT
var/datum/thrownthing/throwing = null
var/throw_speed = 2 //How many tiles to move per ds when being thrown. Float values are fully supported
var/throw_range = 7
@@ -68,20 +71,20 @@
return FALSE
return ..()
-/atom/movable/proc/start_pulling(atom/movable/AM,gs)
+/atom/movable/proc/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
if(QDELETED(AM))
return FALSE
- if(!(AM.can_be_pulled(src)))
+ if(!(AM.can_be_pulled(src, state, force)))
return FALSE
// If we're pulling something then drop what we're currently pulling and pull this instead.
if(pulling)
- if(gs==0)
+ if(state == 0)
stop_pulling()
return FALSE
// Are we trying to pull something we are already pulling? Then enter grab cycle and end.
if(AM == pulling)
- grab_state = gs
+ grab_state = state
if(istype(AM,/mob/living))
var/mob/living/AMob = AM
AMob.grabbedby(src)
@@ -92,11 +95,12 @@
AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once.
pulling = AM
AM.pulledby = src
- grab_state = gs
+ grab_state = state
if(ismob(AM))
var/mob/M = AM
log_combat(src, M, "grabbed", addition="passive grab")
- visible_message("[src] has grabbed [M] passively!")
+ if(!supress_message)
+ visible_message("[src] has grabbed [M] passively!")
return TRUE
/atom/movable/proc/stop_pulling()
@@ -463,15 +467,17 @@
SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum)
return hit_atom.hitby(src)
-/atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked)
- if(!anchored && hitpush)
+/atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked, datum/thrownthing/throwingdatum)
+ if(!anchored && hitpush && (!throwingdatum || (throwingdatum.force >= (move_resist * MOVE_FORCE_PUSH_RATIO))))
step(src, AM.dir)
..()
-/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback)
- return throw_at(target, range, speed, thrower, spin, diagonals_first, callback)
+/atom/movable/proc/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = INFINITY)
+ if((force < (move_resist * MOVE_FORCE_THROW_RATIO)) || (move_resist == INFINITY))
+ return
+ return throw_at(target, range, speed, thrower, spin, diagonals_first, callback, force)
-/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback) //If this returns FALSE then callback will not be called.
+/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = INFINITY) //If this returns FALSE then callback will not be called.
. = FALSE
if (!target || speed <= 0)
return
@@ -517,6 +523,7 @@
TT.speed = speed
TT.thrower = thrower
TT.diagonals_first = diagonals_first
+ TT.force = force
TT.callback = callback
var/dist_x = abs(target.x - src.x)
@@ -565,6 +572,22 @@
return 0
return 1
+/atom/movable/proc/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
+ return FALSE
+
+/atom/movable/proc/force_push(atom/movable/AM, force = move_force, direction, silent = FALSE)
+ . = AM.force_pushed(src, force, direction)
+ if(!silent && .)
+ visible_message("[src] forcefully pushes against [AM]!", "You forcefully push against [AM]!")
+
+/atom/movable/proc/move_crush(atom/movable/AM, force = move_force, direction, silent = FALSE)
+ . = AM.move_crushed(src, force, direction)
+ if(!silent && .)
+ visible_message("[src] crushes past [AM]!", "You crush [AM]!")
+
+/atom/movable/proc/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
+ return FALSE
+
/atom/movable/CanPass(atom/movable/mover, turf/target)
if(mover in buckled_mobs)
return 1
@@ -780,14 +803,15 @@
/atom/movable/proc/get_cell()
return
-/atom/movable/proc/can_be_pulled(user)
+/atom/movable/proc/can_be_pulled(user, grab_state, force)
if(src == user || !isturf(loc))
return FALSE
if(anchored || throwing)
return FALSE
+ if(force < (move_resist * MOVE_FORCE_PULL_RATIO))
+ return FALSE
return TRUE
-
/obj/item/proc/do_pickup_animation(atom/target)
set waitfor = FALSE
if(!istype(loc, /turf))
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 222caeb5951..34c1f8516d7 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -5,6 +5,7 @@
icon_state = "door1"
opacity = 1
density = TRUE
+ move_resist = MOVE_FORCE_VERY_STRONG
layer = OPEN_DOOR_LAYER
power_channel = ENVIRON
max_integrity = 350
diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm
index e2aebd23701..6f6497a929e 100644
--- a/code/game/machinery/shieldgen.dm
+++ b/code/game/machinery/shieldgen.dm
@@ -4,6 +4,7 @@
icon = 'icons/effects/effects.dmi'
icon_state = "shield-old"
density = TRUE
+ move_resist = INFINITY
opacity = 0
anchored = TRUE
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
@@ -93,6 +94,7 @@
/obj/machinery/shieldgen/proc/shields_up()
active = TRUE
update_icon()
+ move_resist = INFINITY
for(var/turf/target_tile in range(shield_range, src))
if(isspaceturf(target_tile) && !(locate(/obj/structure/emergency_shield) in target_tile))
@@ -101,6 +103,7 @@
/obj/machinery/shieldgen/proc/shields_down()
active = FALSE
+ move_resist = initial(move_resist)
update_icon()
QDEL_LIST(deployed_shields)
diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm
index 410923fe254..ccde9c2254d 100644
--- a/code/game/objects/effects/effects.dm
+++ b/code/game/objects/effects/effects.dm
@@ -4,6 +4,7 @@
/obj/effect
icon = 'icons/effects/effects.dmi'
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
+ move_resist = INFINITY
obj_flags = 0
/obj/effect/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 2540f148504..56c270b091a 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -519,10 +519,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
itempush = 0 //too light to push anything
return A.hitby(src, 0, itempush)
-/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
+/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force)
thrownby = thrower
callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own
- . = ..(target, range, speed, thrower, spin, diagonals_first, callback)
+ . = ..(target, range, speed, thrower, spin, diagonals_first, callback, force)
/obj/item/proc/after_throw(datum/callback/callback)
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 6221416db8c..83cad936964 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -121,6 +121,17 @@
if(. && !play_soundeffect)
playsound(src, 'sound/effects/meteorimpact.ogg', 100, 1)
+/obj/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
+ return TRUE
+
+/obj/move_crushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
+ collision_damage(pusher, force, direction)
+ return TRUE
+
+/obj/proc/collision_damage(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
+ var/amt = max(0, ((force - (move_resist * MOVE_FORCE_CRUSH_RATIO)) / (move_resist * MOVE_FORCE_CRUSH_RATIO)) * 10)
+ take_damage(amt, BRUTE)
+
/obj/attack_slime(mob/living/simple_animal/slime/user)
if(!user.is_adult)
return
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index c1d381b4351..3c7a98eddf5 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -78,7 +78,7 @@
SEND_SIGNAL(src, COMSIG_OBJ_SETANCHORED, anchorvalue)
anchored = anchorvalue
-/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
+/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force)
..()
if(obj_flags & FROZEN)
visible_message("[src] shatters into a million pieces!")
diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm
index f40f74787aa..cbe90e7c10b 100644
--- a/code/game/turfs/simulated/wall/misc_walls.dm
+++ b/code/game/turfs/simulated/wall/misc_walls.dm
@@ -24,7 +24,7 @@
if(stored_pulling)
stored_pulling.setDir(get_dir(stored_pulling.loc, newloc))
stored_pulling.forceMove(src)
- H.start_pulling(stored_pulling, TRUE)
+ H.start_pulling(stored_pulling, supress_message = TRUE)
/turf/closed/wall/mineral/cult/ratvar_act()
. = ..()
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index 87794993a7e..f6f4c2a9f7c 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -43,7 +43,7 @@
wander = FALSE
density = FALSE
movement_type = FLYING
- anchored = TRUE
+ move_resist = MOVE_FORCE_OVERPOWERING
mob_size = MOB_SIZE_TINY
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
speed = 1
diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
index fd35b9c0d13..f40c2890be9 100644
--- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
+++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
@@ -254,12 +254,13 @@
/atom/movable/proc/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0)
var/const/PROBABILITY_OFFSET = 25
var/const/PROBABILITY_BASE_PRECENT = 75
+ var/max_force = sqrt(pressure_difference)*(MOVE_FORCE_DEFAULT / 5)
set waitfor = 0
var/move_prob = 100
if (pressure_resistance > 0)
move_prob = (pressure_difference/pressure_resistance*PROBABILITY_BASE_PRECENT)-PROBABILITY_OFFSET
move_prob += pressure_resistance_prob_delta
- if (move_prob > PROBABILITY_OFFSET && prob(move_prob))
+ if (move_prob > PROBABILITY_OFFSET && prob(move_prob) && (move_resist != INFINITY) && (!anchored && (max_force >= (move_resist * MOVE_FORCE_PUSH_RATIO))) || (anchored && (max_force >= (move_resist * MOVE_FORCE_FORCEPUSH_RATIO))))
step(src, direction)
last_high_pressure_movement_air_cycle = SSair.times_fired
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index 7d095869cb1..c9b5eab18e1 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -14,6 +14,7 @@ Pipelines + Other Objects -> Pipe network
/obj/machinery/atmospherics
anchored = TRUE
+ move_resist = INFINITY //Moving a connected machine without actually doing the normal (dis)connection things will probably cause a LOT of issues.
idle_power_usage = 0
active_power_usage = 0
power_channel = ENVIRON
diff --git a/code/modules/mining/fulton.dm b/code/modules/mining/fulton.dm
index f97d3612a85..af8860c02be 100644
--- a/code/modules/mining/fulton.dm
+++ b/code/modules/mining/fulton.dm
@@ -11,6 +11,7 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
var/uses_left = 3
var/can_use_indoors
var/safe_for_living_creatures = 1
+ var/max_force_fulton = MOVE_FORCE_STRONG
/obj/item/extraction_pack/examine()
. = ..()
@@ -57,7 +58,7 @@ GLOBAL_LIST_EMPTY(total_extraction_beacons)
return
if(!isturf(A.loc)) // no extracting stuff inside other stuff
return
- if(A.anchored)
+ if(A.anchored || (A.move_resist > max_force_fulton))
return
to_chat(user, "You start attaching the pack to [A]...")
if(do_after(user,50,target=A))
diff --git a/code/modules/mob/camera/camera.dm b/code/modules/mob/camera/camera.dm
index 883f5a034f1..5baab247127 100644
--- a/code/modules/mob/camera/camera.dm
+++ b/code/modules/mob/camera/camera.dm
@@ -3,7 +3,8 @@
/mob/camera
name = "camera mob"
density = FALSE
- anchored = TRUE
+ move_force = INFINITY
+ move_resist = INFINITY
status_flags = GODMODE // You can't damage it.
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
see_in_dark = 7
diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm
index 67d20923ca9..2b272a6b5e9 100644
--- a/code/modules/mob/dead/dead.dm
+++ b/code/modules/mob/dead/dead.dm
@@ -4,6 +4,7 @@ INITIALIZE_IMMEDIATE(/mob/dead)
/mob/dead
sight = SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
+ move_resist = INFINITY
throwforce = 0
/mob/dead/Initialize()
diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm
index 76c3282e9cd..5b56e91f33f 100644
--- a/code/modules/mob/dead/new_player/new_player.dm
+++ b/code/modules/mob/dead/new_player/new_player.dm
@@ -12,7 +12,6 @@
stat = DEAD
canmove = FALSE
- anchored = TRUE // don't get pushed around
var/mob/living/new_character //for instant transfer once the round is set up
/mob/dead/new_player/Initialize()
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 9f8463477fd..9f9c4c4f9e1 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -12,7 +12,6 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
stat = DEAD
density = FALSE
canmove = 0
- anchored = TRUE // don't get pushed around
see_invisible = SEE_INVISIBLE_OBSERVER
see_in_dark = 100
invisibility = INVISIBILITY_OBSERVER
diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm
index 94f3596d278..c5c8a8038a6 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva.dm
@@ -57,7 +57,7 @@
/mob/living/carbon/alien/larva/toggle_throw_mode()
return
-/mob/living/carbon/alien/larva/start_pulling()
+/mob/living/carbon/alien/larva/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
return
/mob/living/carbon/alien/larva/stripPanelUnequip(obj/item/what, mob/who)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index ae46723ce83..ae9a47cfd5e 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -153,7 +153,7 @@
return
var/atom/movable/thrown_thing
- var/obj/item/I = src.get_active_held_item()
+ var/obj/item/I = get_active_held_item()
if(!I)
if(pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE)
@@ -178,9 +178,9 @@
if(thrown_thing)
visible_message("[src] has thrown [thrown_thing].")
- src.log_message("has thrown [thrown_thing]", LOG_ATTACK)
+ log_message("has thrown [thrown_thing]", LOG_ATTACK)
newtonian_move(get_dir(target, src))
- thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src)
+ thrown_thing.safe_throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src, null, null, null, move_force)
/mob/living/carbon/restrained(ignore_grab)
. = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))
@@ -423,7 +423,7 @@
I.throw_at(target,I.throw_range,I.throw_speed,src)
if(61 to 90) //throw it down to the floor
var/turf/target = get_turf(loc)
- I.throw_at(target,I.throw_range,I.throw_speed,src)
+ I.safe_throw_at(target,I.throw_range,I.throw_speed,src, force = move_force)
/mob/living/carbon/Stat()
..()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index d011d6ad7b5..233f0bcd066 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -59,7 +59,7 @@
return
if(ismovableatom(A))
var/atom/movable/AM = A
- if(PushAM(AM))
+ if(PushAM(AM, move_force))
return
/mob/living/Bumped(atom/movable/AM)
@@ -176,36 +176,46 @@
return
//Called when we want to push an atom/movable
-/mob/living/proc/PushAM(atom/movable/AM)
+/mob/living/proc/PushAM(atom/movable/AM, force = move_force)
if(now_pushing)
- return 1
+ return TRUE
if(moving_diagonally)// no pushing during diagonal moves.
- return 1
+ return TRUE
if(!client && (mob_size < MOB_SIZE_SMALL))
return
- if(!AM.anchored)
- now_pushing = 1
- var/t = get_dir(src, AM)
- if (istype(AM, /obj/structure/window))
- var/obj/structure/window/W = AM
- if(W.fulltile)
- for(var/obj/structure/window/win in get_step(W,t))
- now_pushing = 0
- return
- if(pulling == AM)
- stop_pulling()
- var/current_dir
- if(isliving(AM))
- current_dir = AM.dir
- step(AM, t)
- if(current_dir)
- AM.setDir(current_dir)
- now_pushing = 0
+ now_pushing = TRUE
+ var/t = get_dir(src, AM)
+ var/push_anchored = FALSE
+ if((AM.move_resist * MOVE_FORCE_CRUSH_RATIO) <= force)
+ if(move_crush(AM, move_force, t))
+ push_anchored = TRUE
+ if((AM.move_resist * MOVE_FORCE_FORCEPUSH_RATIO) <= force) //trigger move_crush and/or force_push regardless of if we can push it normally
+ if(force_push(AM, move_force, t, push_anchored))
+ push_anchored = TRUE
+ if((AM.anchored && !push_anchored) || (force < (AM.move_resist * MOVE_FORCE_PUSH_RATIO)))
+ now_pushing = FALSE
+ return
+ if (istype(AM, /obj/structure/window))
+ var/obj/structure/window/W = AM
+ if(W.fulltile)
+ for(var/obj/structure/window/win in get_step(W,t))
+ now_pushing = FALSE
+ return
+ if(pulling == AM)
+ stop_pulling()
+ var/current_dir
+ if(isliving(AM))
+ current_dir = AM.dir
+ if(step(AM, t))
+ step(src, t)
+ if(current_dir)
+ AM.setDir(current_dir)
+ now_pushing = FALSE
-/mob/living/start_pulling(atom/movable/AM, supress_message = 0)
+/mob/living/start_pulling(atom/movable/AM, state, force = pull_force, supress_message = FALSE)
if(!AM || !src)
return FALSE
- if(!(AM.can_be_pulled(src)))
+ if(!(AM.can_be_pulled(src, state, force)))
return FALSE
if(throwing || incapacitated())
return FALSE
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index f5b44db70fc..8312aa2b0b8 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -61,7 +61,7 @@
else
return 0
-/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE)
+/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
if(istype(AM, /obj/item))
var/obj/item/I = AM
var/zone = ran_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest
@@ -126,11 +126,11 @@
adjust_fire_stacks(3)
IgniteMob()
-/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = 0)
+/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = FALSE)
if(user == src || anchored || !isturf(user.loc))
return FALSE
if(!user.pulling || user.pulling != src)
- user.start_pulling(src, supress_message)
+ user.start_pulling(src, supress_message = supress_message)
return
if(!(status_flags & CANPUSH) || has_trait(TRAIT_PUSHIMMUNE))
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 83a2a6df4c5..8dbea8f071a 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -16,7 +16,7 @@
name = "AI"
icon = 'icons/mob/ai.dmi'
icon_state = "ai"
- anchored = TRUE
+ move_resist = MOVE_FORCE_VERY_STRONG
density = TRUE
canmove = FALSE
status_flags = CANSTUN|CANPUSH
@@ -350,9 +350,14 @@
return // stop
if(incapacitated())
return
- anchored = !anchored // Toggles the anchor
+ var/is_anchored = FALSE
+ if(move_resist == MOVE_FORCE_VERY_STRONG)
+ move_resist = MOVE_FORCE_VERY_STRONG
+ else
+ is_anchored = TRUE
+ move_resist = MOVE_FORCE_NORMAL
- to_chat(src, "You are now [anchored ? "" : "un"]anchored.")
+ to_chat(src, "You are now [is_anchored ? "" : "un"]anchored.")
// the message in the [] will change depending whether or not the AI is anchored
/mob/living/silicon/ai/update_canmove() //If the AI dies, mobs won't go through it anymore
diff --git a/code/modules/mob/living/silicon/pai/pai_shell.dm b/code/modules/mob/living/silicon/pai/pai_shell.dm
index 99484f395ea..4344a439db4 100644
--- a/code/modules/mob/living/silicon/pai/pai_shell.dm
+++ b/code/modules/mob/living/silicon/pai/pai_shell.dm
@@ -92,7 +92,7 @@
if(loc != card)
visible_message("[src] [rest? "lays down for a moment..." : "perks up from the ground"]")
-/mob/living/silicon/pai/start_pulling(atom/movable/AM)
+/mob/living/silicon/pai/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
return FALSE
/mob/living/silicon/pai/proc/toggle_integrated_light()
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index c45d435253c..a5569734f0b 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -13,8 +13,8 @@
desc = "A Multiple Utility Load Effector bot."
icon_state = "mulebot0"
density = TRUE
- anchored = TRUE
- animate_movement=1
+ move_resist = MOVE_FORCE_STRONG
+ animate_movement = 1
health = 50
maxHealth = 50
damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index ff91ca7dc39..774bed17ec7 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -338,7 +338,7 @@
stored_pulling.forceMove(loc)
forceMove(AM)
if(stored_pulling)
- start_pulling(stored_pulling, TRUE) //drag anything we're pulling through the wall with us by magic
+ start_pulling(stored_pulling, supress_message = TRUE) //drag anything we're pulling through the wall with us by magic
/mob/living/simple_animal/hostile/construct/harvester/AttackingTarget()
if(iscarbon(target))
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm b/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm
index 1a894734d8f..8a1cfb7125f 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/seedling.dm
@@ -29,7 +29,7 @@
projectilesound = 'sound/weapons/pierce.ogg'
robust_searching = TRUE
stat_attack = UNCONSCIOUS
- anchored = TRUE
+ move_resist = MOVE_FORCE_EXTREMELY_STRONG
var/combatant_state = SEEDLING_STATE_NEUTRAL
var/obj/seedling_weakpoint/weak_point
var/mob/living/beam_debuff_target
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
index 9dc51ac9508..4a52248964b 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -21,7 +21,9 @@
maxbodytemp = INFINITY
vision_range = 5
aggro_vision_range = 18
- anchored = TRUE
+ move_force = MOVE_FORCE_OVERPOWERING
+ move_resist = MOVE_FORCE_OVERPOWERING
+ pull_force = MOVE_FORCE_OVERPOWERING
mob_size = MOB_SIZE_LARGE
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm
index 786d7a97757..c7d90f9556a 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/swarmer.dm
@@ -54,7 +54,6 @@ GLOBAL_LIST_INIT(AISwarmerCapsByType, list(/mob/living/simple_animal/hostile/swa
weather_immunities = list("lava","ash")
stop_automated_movement = TRUE
wander = FALSE
- anchored = TRUE
layer = BELOW_MOB_LAYER
AIStatus = AI_OFF
var/swarmer_spawn_cooldown = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm
index f74f9a436c1..4e1d601712e 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm
@@ -28,7 +28,9 @@
throw_message = "does nothing to the rocky hide of the"
vision_range = 5
aggro_vision_range = 9
- anchored = TRUE //Stays anchored until death as to be unpullable
+ move_force = MOVE_FORCE_VERY_STRONG
+ move_resist = MOVE_FORCE_VERY_STRONG
+ pull_force = MOVE_FORCE_VERY_STRONG
var/pre_attack = 0
var/pre_attack_icon = "Goliath_preattack"
loot = list(/obj/item/stack/sheet/animalhide/goliath_hide)
@@ -52,7 +54,9 @@
. = 1
/mob/living/simple_animal/hostile/asteroid/goliath/death(gibbed)
- anchored = FALSE
+ move_force = MOVE_FORCE_DEFAULT
+ move_resist = MOVE_RESIST_DEFAULT
+ pull_force = PULL_FORCE_DEFAULT
..(gibbed)
/mob/living/simple_animal/hostile/asteroid/goliath/OpenFire()
diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm
index 804989e71ee..f38d77cd906 100644
--- a/code/modules/mob/living/simple_animal/hostile/statue.dm
+++ b/code/modules/mob/living/simple_animal/hostile/statue.dm
@@ -43,7 +43,10 @@
search_objects = 1 // So that it can see through walls
sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS
- anchored = TRUE
+
+ move_force = MOVE_FORCE_EXTREMELY_STRONG
+ move_resist = MOVE_FORCE_EXTREMELY_STRONG
+ pull_force = MOVE_FORCE_EXTREMELY_STRONG
var/cannot_be_seen = 1
var/mob/living/creator = null
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 034ccc4c399..baea2ec84df 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -243,7 +243,7 @@
/mob/living/simple_animal/slime/doUnEquip(obj/item/W)
return
-/mob/living/simple_animal/slime/start_pulling(atom/movable/AM)
+/mob/living/simple_animal/slime/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
return
/mob/living/simple_animal/slime/attack_ui(slot)
diff --git a/code/modules/mob/living/simple_animal/spawner.dm b/code/modules/mob/living/simple_animal/spawner.dm
index 0b97a940e40..b96ff37f4a5 100644
--- a/code/modules/mob/living/simple_animal/spawner.dm
+++ b/code/modules/mob/living/simple_animal/spawner.dm
@@ -11,7 +11,7 @@
var/mob_types = list(/mob/living/simple_animal/hostile/carp)
var/spawn_text = "emerges from"
status_flags = 0
- anchored = TRUE
+ move_resist = MOVE_FORCE_VERY_STRONG
AIStatus = AI_OFF
a_intent = INTENT_HARM
stop_automated_movement = 1
@@ -22,7 +22,6 @@
layer = BELOW_MOB_LAYER
sentience_type = SENTIENCE_BOSS
-
/mob/living/simple_animal/hostile/spawner/Destroy()
for(var/mob/living/simple_animal/L in spawned_mobs)
if(L.nest == src)
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index cb532e4d5e9..6dd12b707d0 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -108,8 +108,7 @@
if((direct & (direct - 1)) && mob.loc == n) //moved diagonally successfully
add_delay *= 2
- if(mob.loc != oldloc)
- move_delay += add_delay
+ move_delay += add_delay
if(.) // If mob is null here, we deserve the runtime
if(mob.throwing)
mob.throwing.finalize(FALSE)
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index 4d8cdaa7782..6cedab99a44 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -23,6 +23,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
desc = "A device which produces a graviton field when set up."
icon = 'icons/obj/machines/gravity_generator.dmi'
density = TRUE
+ move_resist = INFINITY
use_power = NO_POWER_USE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/sprite_number = 0
diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm
index 3b0f7e7f6f8..491be4a83dc 100644
--- a/code/modules/power/singularity/containment_field.dm
+++ b/code/modules/power/singularity/containment_field.dm
@@ -6,6 +6,7 @@
icon = 'icons/obj/singularity.dmi'
icon_state = "Contain_F"
density = FALSE
+ move_resist = INFINITY
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
use_power = NO_POWER_USE
interaction_flags_atom = NONE
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index 6be89b43f4c..34346a1629b 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -245,6 +245,7 @@ field_generator power level display
if(state != FG_WELDED || !anchored)
turn_off()
return
+ move_resist = INFINITY
spawn(1)
setup_field(1)
spawn(2)
@@ -335,6 +336,8 @@ field_generator power level display
message_admins("A singulo exists and a containment field has failed at [ADMIN_VERBOSEJMP(T)].")
investigate_log("has failed whilst a singulo exists at [AREACOORD(T)].", INVESTIGATE_SINGULO)
O.last_warning = world.time
+
+ move_resist = initial(move_resist)
/obj/machinery/field/generator/shock(mob/living/user)
if(fields.len)
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index bc05e784a4e..a33d9cc91ac 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -7,6 +7,7 @@
icon_state = "singularity_s1"
anchored = TRUE
density = TRUE
+ move_resist = INFINITY
layer = MASSIVE_OBJ_LAYER
light_range = 6
appearance_flags = 0
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index 99424468688..9af37c3a389 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -131,7 +131,7 @@ All ShuttleMove procs go here
var/range = throw_force * 10
range = CEILING(rand(range-(range*0.1), range+(range*0.1)), 10)/10
var/speed = range/5
- throw_at(target, range, speed)
+ safe_throw_at(target, range, speed)
/////////////////////////////////////////////////////////////////////////////////////
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index 8da5d7c1138..66f3d4f544b 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -2,6 +2,7 @@
//Keep this sorted alphabetically
#ifdef UNIT_TESTS
+#include "anchored_mobs.dm"
#include "reagent_id_typos.dm"
#include "reagent_recipe_collisions.dm"
#include "spawn_humans.dm"
diff --git a/code/modules/unit_tests/anchored_mobs.dm b/code/modules/unit_tests/anchored_mobs.dm
new file mode 100644
index 00000000000..d68b02b5dac
--- /dev/null
+++ b/code/modules/unit_tests/anchored_mobs.dm
@@ -0,0 +1,9 @@
+/datum/unit_test/anchored_mobs/Run()
+ var/list/L = list()
+ for(var/i in typesof(/mob))
+ var/mob/M = i
+ if(initial(M.anchored))
+ L += "[i]"
+ if(!L.len)
+ return //passed!
+ Fail("The following mobs are defined as anchored. This is incompatible with the new move force/resist system and needs to be revised.: [L.Join(" ")]")
diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm
index 6d05c340b30..492bfecf4d9 100644
--- a/code/modules/unit_tests/unit_test.dm
+++ b/code/modules/unit_tests/unit_test.dm
@@ -18,7 +18,7 @@ GLOBAL_VAR(test_log)
/datum/unit_test
//Bit of metadata for the future maybe
var/list/procs_tested
-
+
//usable vars
var/turf/run_loc_bottom_left
var/turf/run_loc_top_right
diff --git a/tgstation.dme b/tgstation.dme
index 032a80c0bd1..ad74d981703 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -64,6 +64,7 @@
#include "code\__DEFINES\misc.dm"
#include "code\__DEFINES\mobs.dm"
#include "code\__DEFINES\monkeys.dm"
+#include "code\__DEFINES\move_force.dm"
#include "code\__DEFINES\movespeed_modification.dm"
#include "code\__DEFINES\nanites.dm"
#include "code\__DEFINES\networks.dm"
@@ -2670,11 +2671,11 @@
#include "code\modules\vehicles\_vehicle.dm"
#include "code\modules\vehicles\atv.dm"
#include "code\modules\vehicles\bicycle.dm"
-#include "code\modules\vehicles\sealed.dm"
#include "code\modules\vehicles\lavaboat.dm"
#include "code\modules\vehicles\pimpin_ride.dm"
#include "code\modules\vehicles\ridden.dm"
#include "code\modules\vehicles\scooter.dm"
+#include "code\modules\vehicles\sealed.dm"
#include "code\modules\vehicles\secway.dm"
#include "code\modules\vehicles\speedbike.dm"
#include "code\modules\vehicles\vehicle_actions.dm"