diff --git a/code/__DEFINES/move_force.dm b/code/__DEFINES/move_force.dm
new file mode 100644
index 00000000000..750821bd898
--- /dev/null
+++ b/code/__DEFINES/move_force.dm
@@ -0,0 +1,19 @@
+//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)
\ No newline at end of file
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 6ce486bdc05..44522f89e8e 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1495,7 +1495,7 @@ var/mob/dview/dview_mob = new
invisibility = 101
density = 0
- anchored = 1
+ move_resist = INFINITY
simulated = 0
see_in_dark = 1e6
diff --git a/code/controllers/subsystem/throwing.dm b/code/controllers/subsystem/throwing.dm
index b74e3a1a6c9..fb32991b42b 100644
--- a/code/controllers/subsystem/throwing.dm
+++ b/code/controllers/subsystem/throwing.dm
@@ -53,6 +53,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
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 5ca34ceb57e..2bfcd762793 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -85,7 +85,7 @@
if(opacity && isturf(loc))
var/turf/T = loc
T.has_opaque_atom = TRUE // No need to recalculate it in this case, it's guranteed to be on afterwards anyways.
-
+
if(loc)
loc.InitializedOn(src) // Used for poolcontroller / pool to improve performance greatly. However it also open up path to other usage of observer pattern on turfs.
@@ -321,7 +321,7 @@
// Atoms that return TRUE prevent RPDs placing any kind of pipes on their turf.
return FALSE
-/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 36d3ce81ea2..7c1f02d049d 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -3,6 +3,9 @@
appearance_flags = TILE_BOUND
var/last_move = null
var/anchored = 0
+ var/move_resist = MOVE_RESIST_DEFAULT
+ var/move_force = MOVE_FORCE_DEFAULT
+ var/pull_force = PULL_FORCE_DEFAULT
// var/elevation = 2 - not used anywhere
var/move_speed = 10
var/l_move_time = 1
@@ -55,6 +58,14 @@
pulledby = null
return ..()
+/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
// Used in shuttle movement and AI eye stuff.
// Primarily used to notify objects being moved by a shuttle/bluespace fuckup.
/atom/movable/proc/setLoc(var/T, var/teleported=0)
@@ -216,12 +227,12 @@
if(!QDELETED(hit_atom))
return hit_atom.hitby(src)
-/atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked)
- if(!anchored && hitpush)
+/atom/movable/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked, datum/thrownthing/throwingdatum)
+ if(!anchored && hitpush && (!throwingdatum || (throwingdatum.force >= (move_resist * MOVE_FORCE_PUSH_RATIO))))
step(src, AM.dir)
..()
-/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, var/datum/callback/callback)
+/atom/movable/proc/throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, /datum/callback/callback, force = INFINITY)
if(!target || (flags & NODROP) || speed <= 0)
return 0
@@ -328,6 +339,19 @@
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, height=1.5)
if(buckled_mob == mover)
return 1
diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
index 9a8ead8b289..52c321017b5 100644
--- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
+++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm
@@ -311,7 +311,7 @@
to_chat(S, "Destroying this machine while it is occupied would result in biological and sentient resources to be harmed. Aborting.")
return
..()
-
+
/mob/living/swarmer_act(mob/living/simple_animal/hostile/swarmer/S)
S.DisperseTarget(src)
@@ -421,7 +421,6 @@
icon = 'icons/mob/swarmer.dmi'
icon_state = "ui_light"
layer = MOB_LAYER
- anchored = 1
unacidable = 1
light_range = 1
mouse_opacity = MOUSE_OPACITY_ICON
diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm
index fe7d02488d6..708a11901ab 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant.dm
@@ -32,7 +32,7 @@
wander = 0
density = 0
flying = 1
- anchored = 1
+ move_resist = MOVE_FORCE_OVERPOWERING
mob_size = MOB_SIZE_TINY
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
speed = 1
@@ -130,7 +130,7 @@
else
message_admins("Revenant was created but has no mind. Put a ghost inside, or a poll will be made in one minute.")
addtimer(CALLBACK(src, .proc/setupOrDelete), 1 MINUTES)
-
+
/mob/living/simple_animal/revenant/proc/setupOrDelete()
if(mind)
giveObjectivesandGoals()
diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm
index 7ede1d7586d..c6e6c578f4c 100644
--- a/code/game/machinery/atmo_control.dm
+++ b/code/game/machinery/atmo_control.dm
@@ -5,6 +5,7 @@
req_one_access_txt = "24;10"
anchored = 1
+ move_resist = INFINITY
var/state = 0
var/bolts = 1
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 8d9b17ef7c2..7ffadc338bc 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -43,6 +43,7 @@ var/list/airlock_overlays = list()
name = "airlock"
icon = 'icons/obj/doors/airlocks/station/public.dmi'
icon_state = "closed"
+ move_resist = MOVE_FORCE_VERY_STRONG
max_integrity = 300
integrity_failure = 70
damage_deflection = AIRLOCK_DAMAGE_DEFLECTION_N
diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm
index b655635ba1a..ebb70a03e45 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 = 1
+ move_resist = INFINITY
opacity = FALSE
anchored = 1
unacidable = 1
@@ -154,6 +155,7 @@
active = 1
update_icon()
+ move_resist = INFINITY
for(var/turf/target_tile in range(2, src))
if(istype(target_tile,/turf/space) && !(locate(/obj/machinery/shield) in target_tile))
@@ -166,6 +168,7 @@
active = 0
update_icon()
+ move_resist = initial(move_resist)
for(var/obj/machinery/shield/shield_tile in deployed_shields)
qdel(shield_tile)
diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm
index 5836136401e..f1276828bdd 100644
--- a/code/game/objects/effects/effects.dm
+++ b/code/game/objects/effects/effects.dm
@@ -6,6 +6,7 @@
icon = 'icons/effects/effects.dmi'
burn_state = LAVA_PROOF | FIRE_PROOF
resistance_flags = INDESTRUCTIBLE
+ move_resist = INFINITY
can_be_hit = FALSE
/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 9af8b04580a..dcb4bbc2be4 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -503,10 +503,10 @@ var/global/image/fire_overlay = image("icon" = 'icons/goonstation/effects/fire.d
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)
if(callback) //call the original callback
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 572ff92c4fa..2f260559191 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -87,6 +87,15 @@
return TRUE
return FALSE
+/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/blob_act(obj/structure/blob/B)
if(isturf(loc))
var/turf/T = loc
diff --git a/code/modules/mob/camera/camera.dm b/code/modules/mob/camera/camera.dm
index 38b5e81a87b..a5bfcb02e4b 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 = 0
- anchored = 1
+ 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/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 7e583216475..99454dc5261 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -706,6 +706,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Mob spawners menu"
set desc = "See all currently available ghost spawners"
set category = "Ghost"
-
+
var/datum/spawners_menu/menu = new /datum/spawners_menu(src)
menu.ui_interact(src)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index e9b09ba1f2b..88ac1320f04 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -574,7 +574,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
if(thrown_thing)
visible_message("[src] has thrown [thrown_thing].")
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/can_use_hands()
if(handcuffed)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index bf49d5b2598..dfc3a949cac 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -50,7 +50,7 @@
if(ObjBump(A))
return
if(istype(A, /atom/movable))
- if(PushAM(A))
+ if(PushAM(A, move_force))
return
//Called when we bump into a mob
@@ -127,32 +127,42 @@
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/Stat()
. = ..()
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 92a9a6b7b47..5de5de34be0 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -73,7 +73,7 @@
return 0
//this proc handles being hit by a thrown atom
-/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked = 0)//Standardization and logging -Sieve
+/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked = 0, datum/thrownthing/throwingdatum)//Standardization and logging -Sieve
if(istype(AM, /obj/item))
var/obj/item/I = AM
var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest
@@ -229,7 +229,7 @@
// End BS12 momentum-transfer code.
-/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)
return 0
if(!(status_flags & CANPUSH))
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 8d5e60785db..1e67fd8c818 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -38,7 +38,7 @@ var/list/ai_verbs_default = list(
name = "AI"
icon = 'icons/mob/AI.dmi'//
icon_state = "ai"
- anchored = 1 // -- TLE
+ move_resist = MOVE_FORCE_VERY_STRONG
density = 1
status_flags = CANSTUN|CANPARALYSE|CANPUSH
mob_size = MOB_SIZE_LARGE
@@ -530,9 +530,14 @@ var/list/ai_verbs_default = list(
if(!isturf(loc)) // if their location isn't a turf
return // stop
- 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, "[anchored ? "You are now anchored." : "You are now unanchored."]")
+ to_chat(src, "[is_anchored ? "You are now anchored." : "You are now unanchored."]")
/mob/living/silicon/ai/update_canmove()
return FALSE
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index eeaa920c83a..e7028ea4422 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -517,12 +517,8 @@
/mob/living/silicon/pai/Bumped()
return
-/mob/living/silicon/pai/start_pulling(var/atom/movable/AM)
- if(stat || sleeping || paralysis || weakened)
- return
- if(istype(AM,/obj/item))
- to_chat(src, "You are far too small to pull anything!")
- return
+/mob/living/silicon/pai/start_pulling(atom/movable/AM, state, force = move_force, supress_message = FALSE)
+ return FALSE
/mob/living/silicon/pai/update_canmove(delay_action_updates = 0)
. = ..()
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 103e443d7e7..49a3b2718db 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -11,8 +11,8 @@
desc = "A Multiple Utility Load Effector bot."
icon_state = "mulebot0"
density = 1
- anchored = 1
- 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/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
index 6a6e44a5852..870b3bf62cc 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -38,7 +38,9 @@
var/elimination = 0
var/anger_modifier = 0
var/obj/item/gps/internal_gps
- anchored = TRUE
+ move_force = MOVE_FORCE_OVERPOWERING
+ move_resist = MOVE_FORCE_OVERPOWERING
+ pull_force = MOVE_FORCE_OVERPOWERING
mob_size = MOB_SIZE_LARGE
layer = MOB_LAYER + 0.5 //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/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
index 39799d6e493..0f37482b3e2 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
@@ -136,7 +136,9 @@
throw_message = "does nothing to the rocky hide of the"
aggro_vision_range = 9
idle_vision_range = 5
- anchored = 1 //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
loot = list(/obj/item/asteroid/goliath_hide{layer = 4.1})
@@ -152,7 +154,9 @@
icon_state = "Goliath_preattack"
/mob/living/simple_animal/hostile/asteroid/goliath/revive()
- anchored = 1
+ move_force = MOVE_FORCE_VERY_STRONG
+ move_resist = MOVE_FORCE_VERY_STRONG
+ pull_force = MOVE_FORCE_VERY_STRONG
..()
/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 88326747247..b293c1de974 100644
--- a/code/modules/mob/living/simple_animal/hostile/statue.dm
+++ b/code/modules/mob/living/simple_animal/hostile/statue.dm
@@ -42,7 +42,9 @@
see_invisible = SEE_INVISIBLE_OBSERVER_NOLIGHTING
sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS
- anchored = 1
+ move_force = MOVE_FORCE_EXTREMELY_STRONG
+ move_resist = MOVE_FORCE_EXTREMELY_STRONG
+ pull_force = MOVE_FORCE_EXTREMELY_STRONG
status_flags = GODMODE // Cannot push also
var/cannot_be_seen = 1
diff --git a/code/modules/mob/living/simple_animal/spawner.dm b/code/modules/mob/living/simple_animal/spawner.dm
index 22b5fb705a9..7a17dfb202b 100644
--- a/code/modules/mob/living/simple_animal/spawner.dm
+++ b/code/modules/mob/living/simple_animal/spawner.dm
@@ -10,7 +10,7 @@
var/mob_type = /mob/living/simple_animal/hostile/carp
var/spawn_text = "emerges from"
status_flags = 0
- anchored = 1
+ move_resist = MOVE_FORCE_VERY_STRONG
AIStatus = AI_OFF
a_intent = INTENT_HARM
stop_automated_movement = 1
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 5b3fd873777..91a34e39d53 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -12,8 +12,6 @@
stat = 2
canmove = 0
- anchored = 1 // don't get pushed around
-
/mob/new_player/New()
GLOB.mob_list += src
diff --git a/code/modules/mob/pulling.dm b/code/modules/mob/pulling.dm
index f5cb9eecbe2..6fd3659303d 100644
--- a/code/modules/mob/pulling.dm
+++ b/code/modules/mob/pulling.dm
@@ -1,8 +1,10 @@
//this and stop_pulling really ought to be /mob/living procs
-/mob/proc/start_pulling(atom/movable/AM)
+/mob/proc/start_pulling(atom/movable/AM, state, force = move_force, suppress_message = FALSE)
if(src == AM) // Trying to pull yourself is a shortcut to stop pulling
stop_pulling()
return
+ if(!(AM.can_be_pulled(src, state, force)))
+ return FALSE
if(!AM || !isturf(AM.loc)) //if there's no object or the object being pulled is inside something: abort!
return
if(incapacitated())
@@ -12,6 +14,9 @@
// If we're pulling something then drop what we're currently pulling and pull this instead.
if(pulling)
+ if(state == 0)
+ stop_pulling()
+ return FALSE
// Are we trying to pull something we are already pulling? Then just stop here, no need to continue.
if(AM == pulling)
return
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index c65f7d56158..3bb26c08c75 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -22,7 +22,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
name = "gravitational generator"
desc = "A device which produces a gravaton field when set up."
icon = 'icons/obj/machines/gravity_generator.dmi'
- anchored = 1
+ move_resist = INFINITY
density = 1
use_power = NO_POWER_USE
unacidable = 1
diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm
index a0e84f8455a..ee597b7c083 100644
--- a/code/modules/power/singularity/containment_field.dm
+++ b/code/modules/power/singularity/containment_field.dm
@@ -3,7 +3,7 @@
desc = "An energy field."
icon = 'icons/obj/singularity.dmi'
icon_state = "Contain_F"
- anchored = 1
+ move_resist = INFINITY
density = 0
unacidable = 1
use_power = NO_POWER_USE
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index 40947d79368..53af3f9bf43 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -89,14 +89,14 @@ field_generator power level display
user.visible_message("[user.name] secures [name] to the floor.", \
"You secure the external reinforcing bolts to the floor.", \
"You hear ratchet.")
- anchored = 1
+ move_resist = INFINITY
if(FG_SECURED)
state = FG_UNSECURED
playsound(loc, W.usesound, 75, 1)
user.visible_message("[user.name] unsecures [name] reinforcing bolts from the floor.", \
"You undo the external reinforcing bolts.", \
"You hear ratchet.")
- anchored = 0
+ move_resist = initial(move_resist)
if(FG_WELDED)
to_chat(user, "The [name] needs to be unwelded from the floor!")
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 67238444eaa..171ef01dd6b 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -3,7 +3,7 @@
desc = "A gravitational singularity."
icon = 'icons/obj/singularity.dmi'
icon_state = "singularity_s1"
- anchored = 1
+ move_resist = INFINITY
density = 1
layer = MASSIVE_OBJ_LAYER
light_range = 6
diff --git a/paradise.dme b/paradise.dme
index 49888aaf7f2..518fa02c2fe 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -44,6 +44,7 @@
#include "code\__DEFINES\MC.dm"
#include "code\__DEFINES\misc.dm"
#include "code\__DEFINES\mobs.dm"
+#include "code\__DEFINES\move_force.dm"
#include "code\__DEFINES\pda.dm"
#include "code\__DEFINES\pipes.dm"
#include "code\__DEFINES\preferences.dm"
@@ -325,7 +326,6 @@
#include "code\datums\helper_datums\topic_input.dm"
#include "code\datums\looping_sounds\looping_sound.dm"
#include "code\datums\looping_sounds\machinery_sounds.dm"
-#include "code\datums\looping_sounds\thermal_drill.dm"
#include "code\datums\looping_sounds\weather.dm"
#include "code\datums\outfits\outfit.dm"
#include "code\datums\outfits\outfit_admin.dm"