diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm
index 04e5a8fbf0d..2458519c4e6 100644
--- a/code/__DEFINES/combat.dm
+++ b/code/__DEFINES/combat.dm
@@ -39,11 +39,10 @@
//Grab levels
-#define GRAB_PASSIVE 1
-#define GRAB_AGGRESSIVE 2
-#define GRAB_NECK 3
-#define GRAB_UPGRADING 4
-#define GRAB_KILL 5
+#define GRAB_PASSIVE 0
+#define GRAB_AGGRESSIVE 1
+#define GRAB_NECK 2
+#define GRAB_KILL 3
//Hostile Mob AI Status
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 9b9bc263e6d..0f46088543b 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -150,8 +150,9 @@
#define CLICK_CD_RANGE 4
#define CLICK_CD_BREAKOUT 100
#define CLICK_CD_HANDCUFFED 10
-#define CLICK_CD_TKSTRANGLE 10
#define CLICK_CD_RESIST 20
+#define CLICK_CD_GRABBING 10
+
//click cooldowns, in tenths of a second
@@ -423,3 +424,7 @@ var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
// Shuttle return values
#define SHUTTLE_ALREADY_DOCKED 7
+
+// Diagonal movement
+#define FIRST_DIAG_STEP 1
+#define SECOND_DIAG_STEP 2
\ No newline at end of file
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 826a61fb9ab..756a6a73834 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -77,7 +77,7 @@
CtrlClickOn(A)
return
- if(stat || paralysis || stunned || weakened || sleeping)
+ if(incapacitated(ignore_restraints = 1))
return
face_atom(A)
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 72e5ae3c0f9..4cd7f81ecce 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -159,20 +159,6 @@
/obj/screen/drop/Click()
usr.drop_item_v()
-/obj/screen/grab
- name = "grab"
-
-/obj/screen/grab/Click()
- var/obj/item/weapon/grab/G = master
- G.s_click(src)
- return 1
-
-/obj/screen/grab/attack_hand()
- return
-
-/obj/screen/grab/attackby()
- return
-
/obj/screen/act_intent
name = "intent"
icon_state = "help"
diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index 0eedaa98f70..f3054dcaeb3 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -45,10 +45,6 @@
if(affected_mob.notransform)
return
affected_mob.notransform = 1
- affected_mob.canmove = 0
- affected_mob.icon = null
- affected_mob.overlays.Cut()
- affected_mob.invisibility = INVISIBILITY_ABSTRACT
for(var/obj/item/W in affected_mob)
if(istype(W, /obj/item/weapon/implant))
qdel(W)
diff --git a/code/datums/martial.dm b/code/datums/martial.dm
index 46e18dde7d7..226da8d5e57 100644
--- a/code/datums/martial.dm
+++ b/code/datums/martial.dm
@@ -323,10 +323,16 @@
add_to_streak("G",D)
if(check_streak(A,D))
return 1
- D.grabbedby(A,1)
- var/obj/item/weapon/grab/G = A.get_active_hand()
- if(G)
- G.state = GRAB_AGGRESSIVE //Instant aggressive grab
+ if(A.grab_state > GRAB_AGGRESSIVE)
+ D.grabbedby(A, 1)
+ else
+ A.start_pulling(D, 1)
+ if(A.pulling)
+ D.drop_r_hand()
+ D.drop_l_hand()
+ D.stop_pulling()
+ A.grab_state = GRAB_AGGRESSIVE //Instant aggressive grab
+ return 1
/datum/martial_art/the_sleeping_carp/harm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
add_to_streak("H",D)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 63c03c9c2dd..8952ff9b962 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -13,10 +13,12 @@
var/verb_yell = "yells"
var/inertia_dir = 0
var/pass_flags = 0
+ var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move
glide_size = 8
appearance_flags = TILE_BOUND
+
/atom/movable/Move(atom/newloc, direct = 0)
if(!loc || !newloc) return 0
var/atom/oldloc = loc
@@ -25,28 +27,38 @@
if (!(direct & (direct - 1))) //Cardinal move
. = ..()
else //Diagonal move, split it into cardinal moves
+ moving_diagonally = FIRST_DIAG_STEP
if (direct & 1)
if (direct & 4)
if (step(src, NORTH))
+ moving_diagonally = SECOND_DIAG_STEP
. = step(src, EAST)
else if (step(src, EAST))
+ moving_diagonally = SECOND_DIAG_STEP
. = step(src, NORTH)
else if (direct & 8)
if (step(src, NORTH))
+ moving_diagonally = SECOND_DIAG_STEP
. = step(src, WEST)
else if (step(src, WEST))
+ moving_diagonally = SECOND_DIAG_STEP
. = step(src, NORTH)
else if (direct & 2)
if (direct & 4)
if (step(src, SOUTH))
+ moving_diagonally = SECOND_DIAG_STEP
. = step(src, EAST)
else if (step(src, EAST))
+ moving_diagonally = SECOND_DIAG_STEP
. = step(src, SOUTH)
else if (direct & 8)
if (step(src, SOUTH))
+ moving_diagonally = SECOND_DIAG_STEP
. = step(src, WEST)
else if (step(src, WEST))
+ moving_diagonally = SECOND_DIAG_STEP
. = step(src, SOUTH)
+ moving_diagonally = 0
if(!loc || (loc == oldloc && oldloc != newloc))
last_move = 0
@@ -80,10 +92,8 @@
qdel(AM)
loc = null
invisibility = INVISIBILITY_ABSTRACT
- if (pulledby)
- if (pulledby.pulling == src)
- pulledby.pulling = null
- pulledby = null
+ if(pulledby)
+ pulledby.stop_pulling()
// Previously known as HasEntered()
@@ -104,6 +114,8 @@
/atom/movable/proc/forceMove(atom/destination)
if(destination)
+ if(pulledby)
+ pulledby.stop_pulling()
var/atom/oldloc = loc
if(oldloc)
oldloc.Exited(src, destination)
@@ -123,8 +135,6 @@
/mob/living/forceMove(atom/destination)
stop_pulling()
- if(pulledby)
- pulledby.stop_pulling()
if(buckled)
buckled.unbuckle_mob(src,force=1)
if(buckled_mobs.len)
@@ -199,6 +209,9 @@
return 0
//use a modified version of Bresenham's algorithm to get from the atom's current position to that of the target
+ if(pulledby)
+ pulledby.stop_pulling()
+
throwing = 1
if(spin) //if we don't want the /atom/movable to spin.
SpinAnimation(5, 1)
diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm
index da36d8f6d96..57f0c27dab5 100644
--- a/code/game/gamemodes/changeling/powers/absorb.dm
+++ b/code/game/gamemodes/changeling/powers/absorb.dm
@@ -15,23 +15,21 @@
user << "We are already absorbing!"
return
- var/obj/item/weapon/grab/G = user.get_active_hand()
- if(!istype(G))
- user << "We must be grabbing a creature in our active hand to absorb them!"
+ if(!user.pulling || !iscarbon(user.pulling))
+ user << "We must be grabbing a creature to absorb them!"
return
- if(G.state <= GRAB_NECK)
+ if(user.grab_state <= GRAB_NECK)
user << "We must have a tighter grip to absorb this creature!"
return
- var/mob/living/carbon/target = G.affecting
+ var/mob/living/carbon/target = user.pulling
return changeling.can_absorb_dna(user,target)
/obj/effect/proc_holder/changeling/absorbDNA/sting_action(mob/user)
var/datum/changeling/changeling = user.mind.changeling
- var/obj/item/weapon/grab/G = user.get_active_hand()
- var/mob/living/carbon/human/target = G.affecting
+ var/mob/living/carbon/human/target = user.pulling
changeling.isabsorbing = 1
for(var/stage = 1, stage<=3, stage++)
switch(stage)
@@ -122,11 +120,10 @@
/obj/effect/proc_holder/changeling/swap_form/can_sting(mob/living/carbon/user)
if(!..())
return
- var/obj/item/weapon/grab/G = user.get_active_hand()
- if(!istype(G) || (G.state < GRAB_AGGRESSIVE))
- user << "We must have an aggressive grab on creature in our active hand to do this!"
+ if(!user.pulling || !iscarbon(user.pulling) || user.grab_state < GRAB_AGGRESSIVE)
+ user << "We must have an aggressive grab on creature to do this!"
return
- var/mob/living/carbon/target = G.affecting
+ var/mob/living/carbon/target = user.pulling
if((target.disabilities & NOCLONE) || (target.disabilities & HUSK))
user << "DNA of [target] is ruined beyond usability!"
return
@@ -137,8 +134,7 @@
/obj/effect/proc_holder/changeling/swap_form/sting_action(mob/living/carbon/user)
- var/obj/item/weapon/grab/G = user.get_active_hand()
- var/mob/living/carbon/target = G.affecting
+ var/mob/living/carbon/target = user.pulling
var/datum/changeling/changeling = user.mind.changeling
user << "We tighen our grip. We must hold still...."
diff --git a/code/game/gamemodes/sandbox/h_sandbox.dm b/code/game/gamemodes/sandbox/h_sandbox.dm
index 748b9f8a3e7..9f61521660c 100644
--- a/code/game/gamemodes/sandbox/h_sandbox.dm
+++ b/code/game/gamemodes/sandbox/h_sandbox.dm
@@ -27,7 +27,7 @@ var/hsboxspawn = 1
var/hsbinfo = null
//items that shouldn't spawn on the floor because they would bug or act weird
var/global/list/spawn_forbidden = list(
- /obj/item/weapon/grab, /obj/item/tk_grab, /obj/item/weapon/implant, // not implanter, the actual thing that is inside you
+ /obj/item/tk_grab, /obj/item/weapon/implant, // not implanter, the actual thing that is inside you
/obj/item/assembly,/obj/item/device/onetankbomb, /obj/item/radio, /obj/item/device/pda/ai,
/obj/item/device/uplink, /obj/item/smallDelivery, /obj/item/missile,/obj/item/projectile,
/obj/item/borg/sight,/obj/item/borg/stun,/obj/item/weapon/robot_module)
diff --git a/code/game/machinery/dna_scanner.dm b/code/game/machinery/dna_scanner.dm
index 45f7b995486..3fee54bb4e0 100644
--- a/code/game/machinery/dna_scanner.dm
+++ b/code/game/machinery/dna_scanner.dm
@@ -152,19 +152,6 @@
if(default_deconstruction_crowbar(I))
return
- if(istype(I, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = I
- if(!ismob(G.affecting))
- return
-
- if(!state_open)
- user << "Open the scanner first."
- return
-
- var/mob/M = G.affecting
- M.forceMove(loc)
- qdel(G)
- return
return ..()
/obj/machinery/dna_scannernew/attack_hand(mob/user)
diff --git a/code/game/machinery/washing_machine.dm b/code/game/machinery/washing_machine.dm
index eb062334719..f43d5b07698 100644
--- a/code/game/machinery/washing_machine.dm
+++ b/code/game/machinery/washing_machine.dm
@@ -192,14 +192,6 @@
if(default_deconstruction_screwdriver(user, null, null, W))
update_icon()
return
- else if(istype(W,/obj/item/weapon/grab))
- if(state_open)
- var/obj/item/weapon/grab/G = W
- if(iscorgi(G.affecting))
- has_corgi = 1
- G.affecting.loc = src
- qdel(G)
- update_icon()
else if(user.a_intent != "harm")
@@ -232,6 +224,17 @@
user << "[src] is busy."
return
+ if(user.pulling && user.a_intent == "grab" && isliving(user.pulling))
+ var/mob/living/L = user.pulling
+ if(L.buckled || L.buckled_mobs.len)
+ return
+ if(state_open)
+ if(iscorgi(L))
+ has_corgi = 1
+ L.forceMove(src)
+ update_icon()
+ return
+
if(!state_open)
open_machine()
else
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 7c61b5d152f..2839bb1250b 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -409,7 +409,7 @@ obj/item/proc/item_action_slot_check(slot, mob/user)
set category = "Object"
set name = "Pick up"
- if(usr.stat || usr.restrained() || !Adjacent(usr) || usr.stunned || usr.weakened || usr.lying)
+ if(usr.incapacitated() || !Adjacent(usr) || usr.lying)
return
if(usr.get_active_hand() == null) // Let me know if this has any problems -Yota
diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm
index 29c3e7af930..fd681c0138e 100644
--- a/code/game/objects/items/weapons/implants/implantchair.dm
+++ b/code/game/objects/items/weapons/implants/implantchair.dm
@@ -69,24 +69,7 @@
add_implants()
ready = 1
- src.updateUsrDialog()
- return
-
-
-/obj/machinery/implantchair/attackby(obj/item/weapon/W, mob/user, params)
- if(istype(W, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = W
- if(!ismob(G.affecting))
- return
- var/mob/M = G.affecting
- if(M.buckled_mobs.len)
- user << "[M] will not fit into [src] because they have a creature on them!"
- return
- if(put_mob(M))
- qdel(G)
- updateUsrDialog()
- else
- return ..()
+ updateUsrDialog()
/obj/machinery/implantchair/go_out(mob/M)
diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm
index d855441b3ec..adc80abdcc5 100644
--- a/code/game/objects/items/weapons/storage/backpack.dm
+++ b/code/game/objects/items/weapons/storage/backpack.dm
@@ -85,7 +85,7 @@
qdel(src)
singulo.process()
return
- ..()
+ . = ..()
/obj/item/weapon/storage/backpack/holding/proc/failcheck(mob/user)
if (prob(src.reliability)) return 1 //No failure
diff --git a/code/game/objects/items/weapons/storage/bags.dm b/code/game/objects/items/weapons/storage/bags.dm
index 876a2816209..af415d016c8 100644
--- a/code/game/objects/items/weapons/storage/bags.dm
+++ b/code/game/objects/items/weapons/storage/bags.dm
@@ -198,6 +198,8 @@
if(!S.amount)
qdel(S)
else
+ if(S.pulledby)
+ S.pulledby.stop_pulling()
S.loc = src
orient2hud(usr)
@@ -342,7 +344,7 @@
/obj/item/weapon/storage/bag/tray/handle_item_insertion(obj/item/I, prevent_warning = 0)
overlays += image("icon" = I.icon, "icon_state" = I.icon_state, "layer" = -1)
- ..()
+ . = ..()
/*
diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm
index 88b479e8591..e09e732ddcf 100644
--- a/code/game/objects/items/weapons/storage/storage.dm
+++ b/code/game/objects/items/weapons/storage/storage.dm
@@ -301,6 +301,8 @@
return 0
if(silent)
prevent_warning = 1
+ if(W.pulledby)
+ W.pulledby.stop_pulling()
W.loc = src
W.on_enter_storage(src)
if(usr)
diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm
index d3b45dcf87b..cc861ffaeb6 100644
--- a/code/game/objects/items/weapons/storage/wallets.dm
+++ b/code/game/objects/items/weapons/storage/wallets.dm
@@ -51,7 +51,7 @@
combined_access |= I.access
/obj/item/weapon/storage/wallet/handle_item_insertion(obj/item/W, prevent_warning = 0)
- . = ..(W, prevent_warning)
+ . = ..()
if(.)
if(istype(W, /obj/item/weapon/card/id))
refreshID()
diff --git a/code/game/objects/structures/kitchen_spike.dm b/code/game/objects/structures/kitchen_spike.dm
index fb32d2d03ba..998a6820328 100644
--- a/code/game/objects/structures/kitchen_spike.dm
+++ b/code/game/objects/structures/kitchen_spike.dm
@@ -50,38 +50,37 @@
qdel(src)
else
user << "You can't do that while something's on the spike!"
-
- else if(istype(I, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = I
- if(istype(G.affecting, /mob/living/))
- if(!buckled_mobs.len)
- if(do_mob(user, src, 120))
- if(buckled_mobs.len) //to prevent spam/queing up attacks
- return
- if(G.affecting.buckled)
- return
- var/mob/living/H = G.affecting
- playsound(src.loc, "sound/effects/splat.ogg", 25, 1)
- H.visible_message("[user] slams [G.affecting] onto the meat spike!", "[user] slams you onto the meat spike!", "You hear a squishy wet noise.")
- H.loc = src.loc
- H.emote("scream")
- if(istype(H, /mob/living/carbon/human)) //So you don't get human blood when you spike a giant spidere
- var/turf/pos = get_turf(H)
- pos.add_blood_floor(H)
- H.adjustBruteLoss(30)
- H.buckled = src
- H.dir = 2
- buckle_mob(H, force=1)
- var/matrix/m180 = matrix(H.transform)
- m180.Turn(180)
- animate(H, transform = m180, time = 3)
- H.pixel_y = H.get_standard_pixel_y_offset(180)
- qdel(G)
- return
- user << "You can't use that on the spike!"
else
return ..()
+/obj/structure/kitchenspike/attack_hand(mob/user)
+ if(user.pulling && isliving(user.pulling) && user.a_intent == "grab" && !buckled_mobs.len)
+ var/mob/living/L = user.pulling
+ if(do_mob(user, src, 120))
+ if(buckled_mobs.len) //to prevent spam/queing up attacks
+ return
+ if(L.buckled)
+ return
+ playsound(src.loc, "sound/effects/splat.ogg", 25, 1)
+ L.visible_message("[user] slams [L] onto the meat spike!", "[user] slams you onto the meat spike!", "You hear a squishy wet noise.")
+ L.loc = src.loc
+ L.emote("scream")
+ if(ishuman(L)) //So you don't get human blood when you spike a giant spider
+ var/turf/pos = get_turf(L)
+ pos.add_blood_floor(L)
+ L.adjustBruteLoss(30)
+ L.buckled = src
+ L.dir = 2
+ buckle_mob(L, force=1)
+ var/matrix/m180 = matrix(L.transform)
+ m180.Turn(180)
+ animate(L, transform = m180, time = 3)
+ L.pixel_y = L.get_standard_pixel_y_offset(180)
+ else
+ ..()
+
+
+
/obj/structure/kitchenspike/user_buckle_mob(mob/living/M, mob/living/user) //Don't want them getting put on the rack other than by spiking
return
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index 199c3ddae49..e3f6df6107c 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -97,6 +97,19 @@
take_damage(rand(180,280), BRUTE, 0)
return 1
+/obj/structure/table/attack_hand(mob/living/user)
+ if(user.a_intent == "grab" && user.pulling && isliving(user.pulling))
+ var/mob/living/pushed_mob = user.pulling
+ if(pushed_mob.buckled)
+ user << "[pushed_mob] is buckled to [pushed_mob.buckled]!"
+ return
+ if(user.grab_state < GRAB_AGGRESSIVE)
+ user << "You need a better grip to do that!"
+ return
+ tablepush(user, pushed_mob)
+ user.stop_pulling()
+ else
+ ..()
/obj/structure/table/attack_tk() // no telehulk sorry
return
@@ -123,39 +136,15 @@
var/atom/movable/mover = caller
. = . || mover.checkpass(PASSTABLE)
-/obj/structure/table/proc/tablepush(obj/item/I, mob/user)
- if(get_dist(src, user) < 2)
- var/obj/item/weapon/grab/G = I
- if(G.affecting.buckled)
- user << "[G.affecting] is buckled to [G.affecting.buckled]!"
- return 0
- if(G.state < GRAB_AGGRESSIVE)
- user << "You need a better grip to do that!"
- return 0
- if(!G.confirm())
- return 0
- G.affecting.loc = src.loc
- if(istype(src, /obj/structure/table/optable))
- var/obj/structure/table/optable/OT = src
- G.affecting.resting = 1
- G.affecting.update_canmove()
- visible_message("[G.assailant] has laid [G.affecting] on [src].")
- OT.patient = G.affecting
- OT.check_patient()
- qdel(I)
- return 1
- G.affecting.Weaken(2)
- G.affecting.visible_message("[G.assailant] pushes [G.affecting] onto [src].", \
- "[G.assailant] pushes [G.affecting] onto [src].")
- add_logs(G.assailant, G.affecting, "pushed")
- qdel(I)
- return 1
- qdel(I)
+/obj/structure/table/proc/tablepush(mob/living/user, mob/living/pushed_mob)
+ pushed_mob.loc = src.loc
+ pushed_mob.Weaken(2)
+ pushed_mob.visible_message("[user] pushes [pushed_mob] onto [src].", \
+ "[user] pushes [pushed_mob] onto [src].")
+ add_logs(user, pushed_mob, "pushed")
+
/obj/structure/table/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/weapon/grab))
- tablepush(I, user)
- return
if(!(flags & NODECONSTRUCT))
if(istype(I, /obj/item/weapon/screwdriver) && deconstruction_ready)
table_deconstruct(user, 1)
@@ -375,6 +364,13 @@
computer.table = src
break
+/obj/structure/table/optable/tablepush(mob/living/user, mob/living/pushed_mob)
+ pushed_mob.loc = src.loc
+ pushed_mob.resting = 1
+ pushed_mob.update_canmove()
+ visible_message("[user] has laid [pushed_mob] on [src].")
+ check_patient()
+
/obj/structure/table/optable/proc/check_patient()
var/mob/M = locate(/mob/living/carbon/human, loc)
if(M)
diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm
index e4bbee8dcf7..0f4e8e3f431 100644
--- a/code/game/objects/structures/transit_tubes/station.dm
+++ b/code/game/objects/structures/transit_tubes/station.dm
@@ -60,41 +60,44 @@
/obj/structure/transit_tube/station/attack_hand(mob/user)
if(!pod_moving)
- for(var/obj/structure/transit_tube_pod/pod in loc)
- if(!pod.moving && pod.dir in directions())
- if(icon_state == "closed")
- open_animation()
+ if(user.pulling && user.a_intent == "grab" && isliving(user.pulling))
+ if(icon_state == "open")
+ var/mob/living/GM = user.pulling
+ if(user.grab_state >= GRAB_AGGRESSIVE)
+ if(GM.buckled || GM.buckled_mobs.len)
+ user << "[GM] is attached to something!"
+ return
+ for(var/obj/structure/transit_tube_pod/pod in loc)
+ pod.visible_message("[user] starts putting [GM] into the [pod]!")
+ if(do_after(user, 15, target = src))
+ if(GM && user.grab_state >= GRAB_AGGRESSIVE && user.pulling == GM && !GM.buckled && !GM.buckled_mobs.len)
+ GM.Weaken(5)
+ src.Bumped(GM)
+ break
+ else
+ for(var/obj/structure/transit_tube_pod/pod in loc)
+ if(!pod.moving && pod.dir in directions())
+ if(icon_state == "closed")
+ open_animation()
- else if(icon_state == "open")
- if(pod.contents.len && user.loc != pod)
- user.visible_message("[user] starts emptying [pod]'s contents onto the floor.", "You start emptying [pod]'s contents onto the floor...")
- if(do_after(user, 10, target = src)) //So it doesn't default to close_animation() on fail
- if(pod.loc == loc)
- for(var/atom/movable/AM in pod)
- AM.loc = get_turf(user)
- if(ismob(AM))
- var/mob/M = AM
- M.Weaken(5)
+ else if(icon_state == "open")
+ if(pod.contents.len && user.loc != pod)
+ user.visible_message("[user] starts emptying [pod]'s contents onto the floor.", "You start emptying [pod]'s contents onto the floor...")
+ if(do_after(user, 10, target = src)) //So it doesn't default to close_animation() on fail
+ if(pod.loc == loc)
+ for(var/atom/movable/AM in pod)
+ AM.loc = get_turf(user)
+ if(ismob(AM))
+ var/mob/M = AM
+ M.Weaken(5)
- else
- close_animation()
- break
+ else
+ close_animation()
+ break
/obj/structure/transit_tube/station/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/weapon/grab))
- if(icon_state == "open")
- var/obj/item/weapon/grab/G = W
- if(ismob(G.affecting) && G.state >= GRAB_AGGRESSIVE)
- var/mob/GM = G.affecting
- for(var/obj/structure/transit_tube_pod/pod in loc)
- pod.visible_message("[user] starts putting [GM] into the [pod]!")
- if(do_after(user, 15, target = src) && GM && G && G.affecting == GM)
- GM.Weaken(5)
- src.Bumped(GM)
- qdel(G)
- break
- else if(istype(W, /obj/item/weapon/crowbar))
+ if(istype(W, /obj/item/weapon/crowbar))
for(var/obj/structure/transit_tube_pod/pod in loc)
if(pod.contents)
user << "Empty the pod first!"
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 509263147b8..6b58d058251 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -22,12 +22,37 @@
playsound(src.loc, "swing_hit", 25, 1)
swirlie.visible_message("[user] slams the toilet seat onto [swirlie]'s head!", "[user] slams the toilet seat onto your head!", "You hear reverberating porcelain.")
swirlie.adjustBruteLoss(5)
- return
- if(cistern && !open)
+ else if(user.pulling && user.a_intent == "grab" && isliving(user.pulling))
+ user.changeNext_move(CLICK_CD_MELEE)
+ var/mob/living/GM = user.pulling
+ if(user.grab_state >= GRAB_AGGRESSIVE)
+ if(GM.loc != get_turf(src))
+ user << "[GM] needs to be on [src]!"
+ return
+ if(!swirlie)
+ if(open)
+ GM.visible_message("[user] starts to give [GM] a swirlie!", "[user] starts to give you a swirlie...")
+ swirlie = GM
+ if(do_after(user, 30, 0, target = src))
+ GM.visible_message("[user] gives [GM] a swirlie!", "[user] gives you a swirlie!", "You hear a toilet flushing.")
+ if(iscarbon(GM))
+ var/mob/living/carbon/C = GM
+ if(!C.internal)
+ C.adjustOxyLoss(5)
+ else
+ GM.adjustOxyLoss(5)
+ swirlie = null
+ else
+ playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
+ GM.visible_message("[user] slams [GM.name] into [src]!", "[user] slams you into [src]!")
+ GM.adjustBruteLoss(5)
+ else
+ user << "You need a tighter grip!"
+
+ else if(cistern && !open)
if(!contents.len)
user << "The cistern is empty."
- return
else
var/obj/item/I = pick(contents)
if(ishuman(user))
@@ -36,10 +61,9 @@
I.loc = get_turf(src)
user << "You find [I] in the cistern."
w_items -= I.w_class
- return
-
- open = !open
- update_icon()
+ else
+ open = !open
+ update_icon()
/obj/structure/toilet/update_icon()
@@ -54,7 +78,6 @@
user.visible_message("[user] [cistern ? "replaces the lid on the cistern" : "lifts the lid off the cistern"]!", "You [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]!", "You hear grinding porcelain.")
cistern = !cistern
update_icon()
- return
else if(cistern)
if(user.a_intent != "harm")
@@ -70,7 +93,6 @@
I.loc = src
w_items += I.w_class
user << "You carefully place [I] into the cistern."
- return
else if(istype(I, /obj/item/weapon/reagent_containers))
if (!open)
@@ -78,39 +100,6 @@
var/obj/item/weapon/reagent_containers/RG = I
RG.reagents.add_reagent("water", min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
user << "You fill [RG] from [src]. Gross."
- return
-
- else if(istype(I, /obj/item/weapon/grab))
- user.changeNext_move(CLICK_CD_MELEE)
- var/obj/item/weapon/grab/G = I
- if(!G.confirm())
- return
- if(isliving(G.affecting))
- var/mob/living/GM = G.affecting
- if(G.state >= GRAB_AGGRESSIVE)
- if(GM.loc != get_turf(src))
- user << "[GM] needs to be on [src]!"
- return
- if(!swirlie)
- if(open)
- GM.visible_message("[user] starts to give [GM] a swirlie!", "[user] starts to give you a swirlie...")
- swirlie = GM
- if(do_after(user, 30, 0, target = src))
- GM.visible_message("[user] gives [GM] a swirlie!", "[user] gives you a swirlie!", "You hear a toilet flushing.")
- if(iscarbon(GM))
- var/mob/living/carbon/C = GM
- if(!C.internal)
- C.adjustOxyLoss(5)
- else
- GM.adjustOxyLoss(5)
- swirlie = null
- else
- playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
- GM.visible_message("[user] slams [GM.name] into [src]!", "[user] slams you into [src]!")
- GM.adjustBruteLoss(5)
- else
- user << "You need a tighter grip!"
-
else
return ..()
@@ -125,24 +114,20 @@
anchored = 1
-/obj/structure/urinal/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = I
- if(!G.confirm())
- return
- if(isliving(G.affecting))
- var/mob/living/GM = G.affecting
- if(G.state >= GRAB_AGGRESSIVE)
- if(GM.loc != get_turf(src))
- user << "[GM.name] needs to be on [src]."
- return
- user.changeNext_move(CLICK_CD_MELEE)
- user.visible_message("[user] slams [GM] into [src]!", "You slam [GM] into [src]!")
- GM.adjustBruteLoss(8)
- else
- user << "You need a tighter grip!"
+/obj/structure/urinal/attack_hand(mob/user)
+ if(user.pulling && user.a_intent == "grab" && isliving(user.pulling))
+ var/mob/living/GM = user.pulling
+ if(user.grab_state >= GRAB_AGGRESSIVE)
+ if(GM.loc != get_turf(src))
+ user << "[GM.name] needs to be on [src]."
+ return
+ user.changeNext_move(CLICK_CD_MELEE)
+ user.visible_message("[user] slams [GM] into [src]!", "You slam [GM] into [src]!")
+ GM.adjustBruteLoss(8)
+ else
+ user << "You need a tighter grip!"
else
- return ..()
+ ..()
/obj/machinery/shower
name = "shower"
diff --git a/code/modules/food&drinks/kitchen machinery/gibber.dm b/code/modules/food&drinks/kitchen machinery/gibber.dm
index 93e3d1799fd..a0e234b94d7 100644
--- a/code/modules/food&drinks/kitchen machinery/gibber.dm
+++ b/code/modules/food&drinks/kitchen machinery/gibber.dm
@@ -95,16 +95,13 @@
if(operating)
user << "It's locked and running."
return
- else
- src.startgibbing(user)
-/obj/machinery/gibber/attackby(obj/item/P, mob/user, params)
- if(istype(P, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = P
- if(!iscarbon(G.affecting))
+ if(user.pulling && user.a_intent == "grab" && isliving(user.pulling))
+ var/mob/living/L = user.pulling
+ if(!iscarbon(L))
user << "This item is not suitable for the gibber!"
return
- var/mob/living/carbon/C = G.affecting
+ var/mob/living/carbon/C = L
if(C.buckled ||C.buckled_mobs.len)
user << "[C] is attached to something!"
return
@@ -112,17 +109,19 @@
user << "Subject may not have abiotic items on."
return
- user.visible_message("[user] starts to put [G.affecting] into the gibber!")
+ user.visible_message("[user] starts to put [C] into the gibber!")
src.add_fingerprint(user)
- if(do_after(user, gibtime, target = src) && G && G.affecting && G.affecting == C && !C.buckled && !C.buckled_mobs.len && !occupant)
- user.visible_message("[user] stuffs [G.affecting] into the gibber!")
- C.reset_perspective(src)
- C.loc = src
- occupant = C
- qdel(G)
- update_icon()
+ if(do_after(user, gibtime, target = src))
+ if(C && user.pulling == C && !C.buckled && !C.buckled_mobs.len && !occupant)
+ user.visible_message("[user] stuffs [C] into the gibber!")
+ C.forceMove(src)
+ occupant = C
+ update_icon()
+ else
+ startgibbing(user)
- else if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", P))
+/obj/machinery/gibber/attackby(obj/item/P, mob/user, params)
+ if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", P))
return
else if(exchange_parts(user, P))
diff --git a/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm b/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm
index a446c16d444..a464c31d2cc 100644
--- a/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm
+++ b/code/modules/food&drinks/kitchen machinery/monkeyrecycler.dm
@@ -57,18 +57,6 @@
if(stat) //NOPOWER etc
return
- if(istype(O, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = O
- if(!user.Adjacent(G.affecting))
- return
- var/grabbed = G.affecting
- if(ismonkey(grabbed))
- var/mob/living/carbon/monkey/target = grabbed
- stuff_monkey_in(target, user)
- user.drop_item()
- return
- else
- user << "The machine only accepts monkeys!"
else
return ..()
diff --git a/code/modules/food&drinks/kitchen machinery/processor.dm b/code/modules/food&drinks/kitchen machinery/processor.dm
index f0c41e5f082..797baa35247 100644
--- a/code/modules/food&drinks/kitchen machinery/processor.dm
+++ b/code/modules/food&drinks/kitchen machinery/processor.dm
@@ -182,22 +182,12 @@
if(default_deconstruction_crowbar(O))
return
- var/atom/movable/what = O
- if(istype(O, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = O
- if(!user.Adjacent(G.affecting))
- return
- if(G.affecting.buckled || G.affecting.buckled_mobs.len)
- user << "[G.affecting] is attached to somthing!"
- return
- what = G.affecting
-
- var/datum/food_processor_process/P = select_recipe(what)
+ var/datum/food_processor_process/P = select_recipe(O)
if(P)
- user.visible_message("[user] put [what] into [src].", \
- "You put the [what] into [src].")
+ user.visible_message("[user] put [O] into [src].", \
+ "You put the [O] into [src].")
user.drop_item()
- what.loc = src
+ O.loc = src
return 1
else
if(user.a_intent != "harm")
diff --git a/code/modules/holiday/easter.dm b/code/modules/holiday/easter.dm
index d233ea1362c..baf31192aa7 100644
--- a/code/modules/holiday/easter.dm
+++ b/code/modules/holiday/easter.dm
@@ -81,7 +81,7 @@
countEggs()
/obj/item/weapon/storage/bag/easterbasket/handle_item_insertion(obj/item/I, prevent_warning = 0)
- ..()
+ . = ..()
countEggs()
//Bunny Suit
diff --git a/code/modules/holodeck/items.dm b/code/modules/holodeck/items.dm
index dc710200724..18e378d9e5a 100644
--- a/code/modules/holodeck/items.dm
+++ b/code/modules/holodeck/items.dm
@@ -82,7 +82,7 @@
M.apply_damage(10, STAMINA)
if(prob(5))
M.Weaken(3)
- visible_message("[M] is knocked right off \his feet!", 3)
+ visible_message("[M] is knocked right off \his feet!")
//
// Structures
@@ -97,20 +97,22 @@
density = 1
/obj/structure/holohoop/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
- if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2)
- var/obj/item/weapon/grab/G = W
- if(G.state < GRAB_AGGRESSIVE)
+ if(get_dist(src,user)<2)
+ if(user.drop_item(src))
+ visible_message(" [user] dunks [W] into \the [src]!")
+
+/obj/structure/holohoop/attack_hand(mob/user)
+ if(user.pulling && user.a_intent == "grab" && isliving(user.pulling))
+ var/mob/living/L = user.pulling
+ if(user.grab_state < GRAB_AGGRESSIVE)
user << "You need a better grip to do that!"
return
- G.affecting.loc = src.loc
- G.affecting.Weaken(5)
- visible_message("[G.assailant] dunks [G.affecting] into \the [src]!", 3)
- qdel(W)
- return
- else if (istype(W, /obj/item) && get_dist(src,user)<2)
- user.drop_item(src)
- visible_message(" [user] dunks [W] into \the [src]!", 3)
- return
+ L.loc = src.loc
+ L.Weaken(5)
+ visible_message("[user] dunks [L] into \the [src]!")
+ user.stop_pulling()
+ else
+ ..()
/obj/structure/holohoop/CanPass(atom/movable/mover, turf/target, height=0)
if (istype(mover,/obj/item) && mover.throwing)
@@ -119,12 +121,12 @@
return
if(prob(50))
I.loc = src.loc
- visible_message(" Swish! \the [I] lands in \the [src].", 3)
+ visible_message(" Swish! \the [I] lands in \the [src].")
else
- visible_message(" \the [I] bounces off of \the [src]'s rim!", 3)
+ visible_message(" \the [I] bounces off of \the [src]'s rim!")
return 0
else
- return ..(mover, target, height)
+ return ..()
diff --git a/code/modules/mob/interactive.dm b/code/modules/mob/interactive.dm
index 6301af936fa..8c1c8ea5149 100644
--- a/code/modules/mob/interactive.dm
+++ b/code/modules/mob/interactive.dm
@@ -581,12 +581,11 @@
update_icons()
update_hands = 0
- if(grabbed_by.len > 0)
- for(var/obj/item/weapon/grab/G in grabbed_by)
- if(Adjacent(G))
- a_intent = "disarm"
- G.assailant.attack_hand(src)
- inactivity_period = 10
+ if(pulledby)
+ if(Adjacent(pulledby))
+ a_intent = "disarm"
+ pulledby.attack_hand(src)
+ inactivity_period = 10
if(buckled)
resist()
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 3a8e0dcaaa6..690124ac2e3 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -31,8 +31,8 @@
l_hand = W
W.layer = 20 //TODO: move to equipped?
W.equipped(src,slot_l_hand)
- if(pulling == W)
- stop_pulling()
+ if(W.pulledby)
+ W.pulledby.stop_pulling()
update_inv_l_hand()
W.pixel_x = initial(W.pixel_x)
W.pixel_y = initial(W.pixel_y)
@@ -49,8 +49,8 @@
r_hand = W
W.layer = 20
W.equipped(src,slot_r_hand)
- if(pulling == W)
- stop_pulling()
+ if(W.pulledby)
+ W.pulledby.stop_pulling()
update_inv_r_hand()
W.pixel_x = initial(W.pixel_x)
W.pixel_y = initial(W.pixel_y)
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index 6dd329ceeb8..f2521cecaaf 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -83,10 +83,8 @@
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("[M] has attempted to disarm [src]!")
-/mob/living/carbon/alien/humanoid/restrained()
- if (handcuffed)
- return 1
- return 0
+/mob/living/carbon/alien/humanoid/restrained(ignore_grab)
+ . = handcuffed
/mob/living/carbon/alien/humanoid/show_inv(mob/user)
@@ -127,6 +125,12 @@
playsound(src, 'sound/voice/hiss5.ogg', 40, 1, 1) //Alien roars when starting to break free
..(I, cuff_break = 1)
+/mob/living/carbon/alien/humanoid/resist_grab(moving_resist)
+ if(pulledby.grab_state)
+ visible_message("[src] has broken free of [pulledby]'s grip!")
+ pulledby.stop_pulling()
+ . = 0
+
/mob/living/carbon/alien/humanoid/get_standard_pixel_y_offset(lying = 0)
if(leaping)
return -32
@@ -172,4 +176,10 @@ proc/alien_type_present(var/alienpath)
/mob/living/carbon/alien/humanoid/check_breath(datum/gas_mixture/breath)
if(breath && breath.total_moles() > 0 && !sneaking)
playsound(get_turf(src), pick('sound/voice/lowHiss2.ogg', 'sound/voice/lowHiss3.ogg', 'sound/voice/lowHiss4.ogg'), 50, 0, -5)
- ..()
\ No newline at end of file
+ ..()
+
+/mob/living/carbon/alien/humanoid/grabbedby(mob/living/carbon/user, supress_message = 0)
+ if(user == src && pulling && grab_state >= GRAB_AGGRESSIVE && !pulling.anchored && iscarbon(pulling))
+ devour_mob(pulling, devour_time = 60)
+ else
+ ..()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm
index be000619379..46d5bab8fc3 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva.dm
@@ -70,8 +70,8 @@
return
-/mob/living/carbon/alien/larva/restrained()
- return 0
+/mob/living/carbon/alien/larva/restrained(ignore_grab)
+ . = 0
// new damage icon system
// now constructs damage icon for each organ from mask * damage field
diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm
index 1cfbae231cc..aca51f6cb36 100644
--- a/code/modules/mob/living/carbon/alien/life.dm
+++ b/code/modules/mob/living/carbon/alien/life.dm
@@ -8,6 +8,7 @@
return 0
var/toxins_used = 0
+ var/tox_detect_threshold = 0.02
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
var/list/breath_gases = breath.gases
@@ -16,7 +17,7 @@
//Partial pressure of the toxins in our breath
var/Toxins_pp = (breath_gases["plasma"][MOLES]/breath.total_moles())*breath_pressure
- if(Toxins_pp) // Detect toxins in air
+ if(Toxins_pp > tox_detect_threshold) // Detect toxins in air
adjustPlasma(breath_gases["plasma"][MOLES]*250)
throw_alert("alien_tox", /obj/screen/alert/alien_tox)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index e81fec5df86..cbd45ab3bea 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -208,47 +208,38 @@
throw_mode_off()
if(!target || !isturf(loc))
return
- if(istype(target, /obj/screen)) return
-
- var/atom/movable/item = src.get_active_hand()
-
- if(!item || (item.flags & (NODROP|ABSTRACT)))
+ if(istype(target, /obj/screen))
return
- if(istype(item, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = item
- item = G.get_mob_if_throwable() //throw the person instead of the grab
- qdel(G) //We delete the grab, as it needs to stay around until it's returned.
- if(ismob(item))
- var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
- var/turf/end_T = get_turf(target)
- if(start_T && end_T)
- var/mob/M = item
- var/start_T_descriptor = "tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]"
- var/end_T_descriptor = "tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]"
+ var/atom/movable/thrown_thing
+ var/obj/item/I = src.get_active_hand()
- add_logs(src, M, "thrown", addition="from [start_T_descriptor] with the target [end_T_descriptor]")
+ if(!I)
+ if(pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE)
+ var/mob/living/throwable_mob = pulling
+ if(!throwable_mob.buckled)
+ thrown_thing = throwable_mob
+ stop_pulling()
+ var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors
+ var/turf/end_T = get_turf(target)
+ if(start_T && end_T)
+ var/start_T_descriptor = "tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]"
+ var/end_T_descriptor = "tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]"
+ add_logs(src, throwable_mob, "thrown", addition="from [start_T_descriptor] with the target [end_T_descriptor]")
- if(!item) return //Grab processing has a chance of returning null
-
- if(!ismob(item)) //Honk mobs don't have a dropped() proc honk
- unEquip(item)
- if(src.client)
- src.client.screen -= item
-
- //actually throw it!
- if(item)
- item.layer = initial(item.layer)
- src.visible_message("[src] has thrown [item].")
+ else if(!(I.flags & (NODROP|ABSTRACT)))
+ thrown_thing = I
+ unEquip(I)
+ 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)
- item.throw_at(target, item.throw_range, item.throw_speed, src)
-/mob/living/carbon/restrained()
- if (handcuffed)
- return 1
- return
+/mob/living/carbon/restrained(ignore_grab)
+ . = (handcuffed || (!ignore_grab && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE))
+
/mob/living/carbon/proc/canBeHandcuffed()
return 0
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index bde5baef416..56d75b56517 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -94,3 +94,15 @@
adjustFireLoss(M.powerlevel * rand(6,10))
updatehealth()
return 1
+
+/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130)
+ C.visible_message("[src] is attempting to devour [C]!", \
+ "[src] is attempting to devour you!")
+ if(!do_mob(src, C, devour_time))
+ return
+ if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == "grab")
+ C.visible_message("[src] devours [C]!", \
+ "[src] devours you!")
+ C.forceMove(src)
+ stomach_contents.Add(C)
+ add_logs(src, C, "devoured")
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm
index 2e77a20baa8..5fdfa802698 100644
--- a/code/modules/mob/living/carbon/carbon_movement.dm
+++ b/code/modules/mob/living/carbon/carbon_movement.dm
@@ -1,5 +1,6 @@
/mob/living/carbon/movement_delay()
. = ..()
+ . += grab_state * 3
if(legcuffed)
. += legcuffed.slowdown
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 21f8bdb6cb4..6842d856b03 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -46,6 +46,9 @@
if(fire_stacks < 0)
msg += "It's soaked in water.\n"
+ if(pulledby && pulledby.grab_state)
+ msg += "It's restrained by [pulledby]'s grip.\n"
+
if(stat == UNCONSCIOUS)
msg += "It isn't responding to anything around it; it seems to be asleep.\n"
msg += ""
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index df0e5344f19..80e5574df34 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -236,6 +236,9 @@
msg += "[t_He] looks a little soaked.\n"
+ if(pulledby && pulledby.grab_state)
+ msg += "[t_He] [t_is] restrained by [pulledby]'s grip.\n"
+
if(nutrition < NUTRITION_LEVEL_STARVING - 50)
msg += "[t_He] [t_is] severely malnourished.\n"
else if(nutrition >= NUTRITION_LEVEL_FAT)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 7eab6c1d4f0..84381f3d17b 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -264,11 +264,6 @@
I.acid_act(acidpwr, acid_volume_left)
acid_volume_left = max(acid_volume_left - acid_decay, 0)
-/mob/living/carbon/human/grabbedby(mob/living/user)
- if(w_uniform)
- w_uniform.add_fingerprint(user)
- ..()
-
/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
if(..())
@@ -369,3 +364,14 @@
skipcatch = 1 //can't catch the now embedded item
return ..()
+
+/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
+ if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (disabilities & FAT) && ismonkey(pulling))
+ devour_mob(pulling)
+ else
+ ..()
+
+/mob/living/carbon/human/grippedby(mob/living/user)
+ if(w_uniform)
+ w_uniform.add_fingerprint(user)
+ ..()
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 642f86d9903..6631cdaadb7 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -1,10 +1,7 @@
-/mob/living/carbon/human/restrained()
- if (handcuffed)
- return 1
- if (wear_suit && wear_suit.breakouttime)
- return 1
- return 0
+/mob/living/carbon/human/restrained(ignore_grab)
+ . = ((wear_suit && wear_suit.breakouttime) || ..())
+
/mob/living/carbon/human/canBeHandcuffed()
return 1
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index 3e0ad9b5b3c..870f2cf032c 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -89,6 +89,7 @@
if(I.flags_inv & HIDEJUMPSUIT)
update_inv_w_uniform()
if(wear_suit.breakouttime) //when equipping a straightjacket
+ stop_pulling() //can't pull if restrained
update_action_buttons_icon() //certain action buttons will no longer be usable.
update_inv_wear_suit()
if(slot_w_uniform)
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index ec8ae177cfa..10a3a861a7c 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -974,22 +974,6 @@
H.visible_message("[M] has broken [H]'s grip on [H.pulling]!")
talked = 1
H.stop_pulling()
-
- //BubbleWrap: Disarming also breaks a grab - this will also stop someone being choked, won't it?
- if(istype(H.l_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/lgrab = H.l_hand
- if(lgrab.affecting)
- H.visible_message("[M] has broken [H]'s grip on [lgrab.affecting]!")
- talked = 1
- spawn(1)
- qdel(lgrab)
- if(istype(H.r_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/rgrab = H.r_hand
- if(rgrab.affecting)
- H.visible_message("[M] has broken [H]'s grip on [rgrab.affecting]!")
- talked = 1
- spawn(1)
- qdel(rgrab)
//End BubbleWrap
if(!talked) //BubbleWrap
diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm
index 00efe469b81..8ac3bfc3d66 100644
--- a/code/modules/mob/living/carbon/inventory.dm
+++ b/code/modules/mob/living/carbon/inventory.dm
@@ -29,6 +29,9 @@
else if(I == r_hand)
r_hand = null
+ if(I.pulledby)
+ I.pulledby.stop_pulling()
+
I.screen_loc = null // will get moved if inventory is visible
I.loc = src
I.equipped(src, slot)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 4084b11b26e..587977a4715 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -17,14 +17,6 @@
for(var/obj/item/organ/O in internal_organs)
O.on_life()
- //grab processing
- if(istype(l_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = l_hand
- G.process()
- if(istype(r_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = r_hand
- G.process()
-
//Updates the number of stored chemicals for powers
handle_changeling()
@@ -54,7 +46,7 @@
var/datum/gas_mixture/breath
- if(health <= config.health_threshold_crit)
+ if(health <= config.health_threshold_crit || (pulledby && pulledby.grab_state >= GRAB_KILL))
losebreath++
//Suffocate
diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm
index cdc9b8350c5..f3e208b6e95 100644
--- a/code/modules/mob/living/carbon/monkey/life.dm
+++ b/code/modules/mob/living/carbon/monkey/life.dm
@@ -13,7 +13,7 @@
..()
if(!client && stat == CONSCIOUS)
- if(prob(33) && canmove && isturf(loc) && !pulledby && !grabbed_by.len)
+ if(prob(33) && canmove && isturf(loc) && !pulledby)
step(src, pick(cardinal))
if(prob(1))
emote(pick("scratch","jump","roll","tail"))
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index a04bb808579..be0c8d59bc5 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -105,7 +105,7 @@ Sorry Giacom. Please don't be mad :(
//Should stop you pushing a restrained person out of the way
if(isliving(M))
var/mob/living/L = M
- if((L.pulledby && L.restrained()) || L.grabbed_by.len)
+ if(L.pulledby && L.pulledby != src && L.restrained())
if(!(world.time % 5))
src << "[L] is restrained, you cannot push past."
return 1
@@ -118,32 +118,42 @@ Sorry Giacom. Please don't be mad :(
src << "[L] is restraining [P], you cannot push past."
return 1
- //switch our position with M
- //BubbleWrap: people in handcuffs are always switched around as if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
- if((M.a_intent == "help" || M.restrained()) && (a_intent == "help" || restrained()) && M.canmove && canmove && !M.buckled && !M.buckled_mobs.len) // mutual brohugs all around!
- if(loc && !loc.Adjacent(M.loc))
- return 1
- now_pushing = 1
- var/oldloc = loc
- var/oldMloc = M.loc
-
-
- var/M_passmob = (M.pass_flags & PASSMOB) // we give PASSMOB to both mobs to avoid bumping other mobs during swap.
- var/src_passmob = (pass_flags & PASSMOB)
- M.pass_flags |= PASSMOB
- pass_flags |= PASSMOB
-
- M.Move(oldloc)
- Move(oldMloc)
-
- if(!src_passmob)
- pass_flags &= ~PASSMOB
- if(!M_passmob)
- M.pass_flags &= ~PASSMOB
-
- now_pushing = 0
+ if(moving_diagonally)//no mob swap during diagonal moves.
return 1
+ if(!M.buckled && !M.buckled_mobs.len)
+ var/mob_swap
+ //the puller can always swap with its victim if on grab intent
+ if(M.pulledby == src && a_intent == "grab")
+ mob_swap = 1
+ //restrained people act if they were on 'help' intent to prevent a person being pulled from being seperated from their puller
+ else if((M.restrained() || M.a_intent == "help") && (restrained() || a_intent == "help"))
+ mob_swap = 1
+ if(mob_swap)
+ //switch our position with M
+ if(loc && !loc.Adjacent(M.loc))
+ return 1
+ now_pushing = 1
+ var/oldloc = loc
+ var/oldMloc = M.loc
+
+
+ var/M_passmob = (M.pass_flags & PASSMOB) // we give PASSMOB to both mobs to avoid bumping other mobs during swap.
+ var/src_passmob = (pass_flags & PASSMOB)
+ M.pass_flags |= PASSMOB
+ pass_flags |= PASSMOB
+
+ M.Move(oldloc)
+ Move(oldMloc)
+
+ if(!src_passmob)
+ pass_flags &= ~PASSMOB
+ if(!M_passmob)
+ M.pass_flags &= ~PASSMOB
+
+ now_pushing = 0
+ return 1
+
//okay, so we didn't switch. but should we push?
//not if he's not CANPUSH of course
if(!(M.status_flags & CANPUSH))
@@ -162,6 +172,8 @@ Sorry Giacom. Please don't be mad :(
/mob/living/proc/PushAM(atom/movable/AM)
if(now_pushing)
return 1
+ if(moving_diagonally)// no pushing during diagonal moves.
+ return 1
if(!client && (mob_size < MOB_SIZE_SMALL))
return
if(!AM.anchored)
@@ -191,7 +203,7 @@ Sorry Giacom. Please don't be mad :(
//same as above
/mob/living/pointed(atom/A as mob|obj|turf in view())
- if(src.stat || !src.canmove || src.restrained())
+ if(incapacitated())
return 0
if(src.status_flags & FAKEDEATH)
return 0
@@ -546,67 +558,29 @@ Sorry Giacom. Please don't be mad :(
else
return 0
- if (restrained())
+ var/atom/movable/pullee = pulling
+ if(pullee && get_dist(src, pullee) > 1)
stop_pulling()
-
-
- var/cuff_dragged = 0
- if (restrained())
- for(var/mob/living/M in range(1, src))
- if (M.pulling == src && !M.incapacitated())
- cuff_dragged = 1
- if (!cuff_dragged && pulling && !throwing && (get_dist(src, pulling) <= 1 || pulling.loc == loc))
- var/turf/T = loc
- . = ..()
-
- if (pulling && pulling.loc)
- if(!isturf(pulling.loc))
- stop_pulling()
- return
- else
- if(Debug)
- diary <<"pulling disappeared? at [__LINE__] in mob.dm - pulling = [pulling]"
- diary <<"REPORT THIS"
-
- /////
- if(pulling && pulling.anchored)
+ var/turf/T = loc
+ . = ..()
+ if(. && pulling && pulling == pullee) //we were pulling a thing and didn't lose it during our move.
+ if(pulling.anchored)
stop_pulling()
return
- if (!restrained())
- var/diag = get_dir(src, pulling)
- if ((diag - 1) & diag)
- else
- diag = null
- if ((get_dist(src, pulling) > 1 || diag))
- if (isliving(pulling))
- var/mob/living/M = pulling
- var/pull_ok = 1
- if (M.grabbed_by.len)
- if (prob(75))
- var/obj/item/weapon/grab/G = pick(M.grabbed_by)
- visible_message("[src] has pulled [G.affecting] from [G.assailant]'s grip.")
- qdel(G)
- else
- pull_ok = 0
- if (M.grabbed_by.len)
- pull_ok = 0
- if (pull_ok)
- var/atom/movable/t = M.pulling
- M.stop_pulling()
+ var/pull_dir = get_dir(src, pulling)
+ if(get_dist(src, pulling) > 1 || ((pull_dir - 1) & pull_dir)) //puller and pullee more than one tile away or in diagonal position
+ if(isliving(pulling))
+ var/mob/living/M = pulling
+ if(M.lying && !M.buckled && (prob(M.getBruteLoss() / 2)))
+ makeTrail(T, M)
+ pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position
+ if(pulling && get_dist(src, pulling) > 1) //the pullee couldn't keep up
+ stop_pulling()
+
+ if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1)//separated from our puller and not in the middle of a diagonal move.
+ pulledby.stop_pulling()
- //this is the gay blood on floor shit -- Added back -- Skie
- if(M.lying && !M.buckled && (prob(M.getBruteLoss() / 2)))
- makeTrail(T, M)
- pulling.Move(T, get_dir(pulling, T))
- if(M)
- M.start_pulling(t)
- else
- if (pulling)
- pulling.Move(T, get_dir(pulling, T))
- else
- stop_pulling()
- . = ..()
if (s_active && !(s_active in contents) && !(s_active.loc in contents))
// It's ugly. But everything related to inventory/storage is. -- c0
s_active.close(src)
@@ -662,34 +636,15 @@ Sorry Giacom. Please don't be mad :(
set name = "Resist"
set category = "IC"
- if(!isliving(src) || next_move > world.time || stat || weakened || stunned || paralysis)
+ if(!isliving(src) || next_move > world.time || incapacitated(ignore_restraints = 1))
return
changeNext_move(CLICK_CD_RESIST)
//resisting grabs (as if it helps anyone...)
- if(!restrained())
- var/resisting = 0
- for(var/obj/O in requests)
- qdel(O)
- resisting++
- for(var/X in grabbed_by)
- var/obj/item/weapon/grab/G = X
- resisting++
- if(G.state == GRAB_PASSIVE)
- qdel(G)
- else
- if(G.state == GRAB_AGGRESSIVE)
- if(prob(25))
- visible_message("[src] has broken free of [G.assailant]'s grip!")
- qdel(G)
- else
- if(G.state == GRAB_NECK)
- if(prob(5))
- visible_message("[src] has broken free of [G.assailant]'s headlock!")
- qdel(G)
- if(resisting)
- visible_message("[src] resists!")
- return
+ if(!restrained(ignore_grab = 1) && pulledby)
+ visible_message("[src] resists against [pulledby]'s grip!")
+ resist_grab()
+ return
//unbuckling yourself
if(buckled && last_special <= world.time)
@@ -707,6 +662,22 @@ Sorry Giacom. Please don't be mad :(
resist_restraints() //trying to remove cuffs.
+/mob/proc/resist_grab(moving_resist)
+ return 1 //returning 0 means we successfully broke free
+
+/mob/living/resist_grab(moving_resist)
+ . = 1
+ if(pulledby.grab_state)
+ if(prob(30/pulledby.grab_state))
+ visible_message("[src] has broken free of [pulledby]'s grip!")
+ pulledby.stop_pulling()
+ return 0
+ if(moving_resist && client) //we resisted by trying to move
+ client.move_delay = world.time + 20
+ else
+ pulledby.stop_pulling()
+ return 0
+
/mob/living/proc/resist_buckle()
buckled.user_unbuckle_mob(src,src)
@@ -1024,3 +995,7 @@ Sorry Giacom. Please don't be mad :(
for(var/datum/objective/sintouched/acedia/A in src.mind.objectives)
return 1
return 0
+
+/mob/living/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0)
+ stop_pulling()
+ . = ..()
\ No newline at end of file
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 773931c8d7d..616609b01a9 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -174,28 +174,51 @@
/mob/living/acid_act(acidpwr, toxpwr, acid_volume)
take_organ_damage(min(10*toxpwr, acid_volume * toxpwr))
-/mob/living/proc/grabbedby(mob/living/carbon/user,supress_message = 0)
+/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src || anchored)
return 0
+ if(!user.pulling || user.pulling != src)
+ user.start_pulling(src, supress_message)
+ return
+
if(!(status_flags & CANPUSH))
+ user << "[src] can't be grabbed more aggressively!"
return 0
+ grippedby(user)
- add_logs(user, src, "grabbed", addition="passively")
-
- if(anchored || !Adjacent(user))
- return 0
- if(buckled)
- user << "You cannot grab [src], \he is buckled in!"
- return 0
- var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(user, src)
- if(!user.put_in_active_hand(G)) //if we can't put the grab in our hand for some reason, we delete it.
- qdel(G)
- G.synch()
- LAssailant = user
-
- playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- if(!supress_message)
- visible_message("[user] has grabbed [src] passively!")
+//proc to upgrade a simple pull into a more aggressive grab.
+/mob/living/proc/grippedby(mob/living/carbon/user)
+ if(user.grab_state < GRAB_KILL)
+ user.changeNext_move(CLICK_CD_GRABBING)
+ playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ var/old_grab_state = user.grab_state
+ var/grab_upgrade_time = 40
+ visible_message("[user] starts to tighten \his grip on [src]!", \
+ "[user] starts to tighten \his grip on you!")
+ if(do_mob(user, src, grab_upgrade_time))
+ if(user.pulling && user.pulling == src && user.grab_state == old_grab_state && user.a_intent == "grab")
+ user.grab_state++
+ switch(user.grab_state)
+ if(GRAB_AGGRESSIVE)
+ add_logs(user, src, "grabbed", addition="aggressively")
+ visible_message("[user] has grabbed [src] aggressively!", \
+ "[user] has grabbed [src] aggressively!")
+ drop_r_hand()
+ drop_l_hand()
+ stop_pulling()
+ if(GRAB_NECK)
+ visible_message("[user] has grabbed [src] by the neck!",\
+ "[user] has grabbed you by the neck!")
+ update_canmove() //we fall down
+ if(!buckled && !density)
+ Move(user.loc)
+ if(GRAB_KILL)
+ visible_message("[user] is strangling [src]!", \
+ "[user] is strangling you!")
+ update_canmove() //we fall down
+ if(!buckled && !density)
+ Move(user.loc)
+ return 1
/mob/living/attack_slime(mob/living/simple_animal/slime/M)
@@ -295,8 +318,8 @@
M.do_attack_animation(src)
return 1
-/mob/living/incapacitated()
- if(stat || paralysis || stunned || weakened || restrained())
+/mob/living/incapacitated(ignore_restraints, ignore_grab)
+ if(stat || paralysis || stunned || weakened || (!ignore_restraints && restrained(ignore_grab)))
return 1
//Looking for irradiate()? It's been moved to radiation.dm under the rad_act() for mobs.
diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm
index dab7e893b8a..8e03705663e 100644
--- a/code/modules/mob/living/living_defines.dm
+++ b/code/modules/mob/living/living_defines.dm
@@ -60,4 +60,4 @@
var/list/butcher_results = null
var/hellbound = 0 //People who've signed infernal contracts are unrevivable.
-
+
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 58d25079b3e..30de1ef4dd9 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -357,8 +357,8 @@ var/list/ai_list = list()
return 1
return 0
-/mob/living/silicon/ai/restrained()
- return 0
+/mob/living/silicon/ai/restrained(ignore_grab)
+ . = 0
/mob/living/silicon/ai/emp_act(severity)
if (prob(30))
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index ec801c34740..11849bdb578 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -95,8 +95,8 @@
/mob/living/silicon/pai/blob_act(obj/effect/blob/B)
return 0
-/mob/living/silicon/pai/restrained()
- return 0
+/mob/living/silicon/pai/restrained(ignore_grab)
+ . = 0
/mob/living/silicon/pai/emp_act(severity)
// 20% chance to kill
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 3d1ebfaa7cd..3197f34bbd2 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -378,8 +378,8 @@
if(connected_ai)
stat("Master AI:", connected_ai.name)
-/mob/living/silicon/robot/restrained()
- return 0
+/mob/living/silicon/robot/restrained(ignore_grab)
+ . = 0
/mob/living/silicon/robot/ex_act(severity, target)
switch(severity)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 208bd2da166..b5b4f308444 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -467,7 +467,7 @@
if (aicamera)
return aicamera.selectpicture(aicamera)
-/mob/living/silicon/grabbedby(mob/living/user)
+/mob/living/silicon/grippedby(mob/living/user)
return
/mob/living/silicon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/noise)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index c6b108c951a..0fcb8b953e8 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -81,10 +81,9 @@
drop_r_hand()
var/obj/item/clothing/head/drone_holder/DH = new /obj/item/clothing/head/drone_holder(src)
DH.updateVisualAppearence(src)
- DH.contents += src
DH.drone = src
user.put_in_hands(DH)
- src.loc = DH
+ forceMove(DH)
return
..()
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm
index cc56e9382a9..ed54a1e50b8 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm
@@ -91,6 +91,9 @@
r_hand = null
update_inv_hands()
+ if(I.pulledby)
+ I.pulledby.stop_pulling()
+
I.screen_loc = null // will get moved if inventory is visible
I.loc = src
I.equipped(src, slot)
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index 51e6e5f0fa1..3918348a595 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -32,7 +32,7 @@
environment_smash = 0
mouse_opacity = 2
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
- mob_size = MOB_SIZE_SMALL
+ mob_size = MOB_SIZE_TINY
flying = 1
gold_core_spawnable = 1
search_objects = 1 //have to find those plant trays!
diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm
index cd450b1ba34..739a332d653 100644
--- a/code/modules/mob/living/simple_animal/hostile/statue.dm
+++ b/code/modules/mob/living/simple_animal/hostile/statue.dm
@@ -228,7 +228,7 @@
/mob/living/simple_animal/hostile/statue/sentience_act()
faction -= "neutral"
-/mob/living/simple_animal/hostile/statue/restrained()
+/mob/living/simple_animal/hostile/statue/restrained(ignore_grab)
. = ..()
if(can_be_seen(loc))
return 1
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 40457e167aa..78c877ba366 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -172,6 +172,9 @@
/mob/living/simple_animal/handle_environment(datum/gas_mixture/environment)
var/atmos_suitable = 1
+ if(pulledby && pulledby.grab_state >= GRAB_KILL && atmos_requirements["min_oxy"])
+ atmos_suitable = 0 //getting choked
+
var/atom/A = src.loc
if(isturf(A))
var/turf/T = A
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 5b0ed1aaa8d..74b3e20a378 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -389,7 +389,7 @@
sleep(3)
if(user)
step_away(src,user,15)
- canmove = 1
+ update_canmove()
/mob/living/simple_animal/slime/pet
docile = 1
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index e4de12e8ac3..c549cd73a18 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -179,44 +179,10 @@ var/next_mob_id = 0
return r_hand
return null
-/mob/proc/ret_grab(obj/effect/list_container/mobl/L, flag)
- if ((!( istype(l_hand, /obj/item/weapon/grab) ) && !( istype(r_hand, /obj/item/weapon/grab) )))
- if (!( L ))
- return null
- else
- return L.container
- else
- if (!( L ))
- L = new /obj/effect/list_container/mobl( null )
- L.container += src
- L.master = src
- if (istype(l_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = l_hand
- if (!( L.container.Find(G.affecting) ))
- L.container += G.affecting
- if (G.affecting)
- G.affecting.ret_grab(L, 1)
- if (istype(r_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = r_hand
- if (!( L.container.Find(G.affecting) ))
- L.container += G.affecting
- if (G.affecting)
- G.affecting.ret_grab(L, 1)
- if (!( flag ))
- if (L.master == src)
- var/list/temp = list( )
- temp += L.container
- //L = null
- qdel(L)
- return temp
- else
- return L.container
+/mob/proc/restrained(ignore_grab)
return
-/mob/proc/restrained()
- return
-
-/mob/proc/incapacitated()
+/mob/proc/incapacitated(ignore_restraints, ignore_grab)
return
//This proc is called whenever someone clicks an inventory ui slot.
@@ -333,12 +299,14 @@ var/next_mob_id = 0
return 1
//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, supress_message = 0)
if(!AM || !src)
return
if(AM == src || !isturf(AM.loc))
return
- if(AM.anchored)
+ if(AM.anchored || AM.throwing)
+ return
+ if(throwing || incapacitated())
return
AM.add_fingerprint(src)
@@ -350,13 +318,21 @@ var/next_mob_id = 0
return
stop_pulling()
+ changeNext_move(CLICK_CD_GRABBING)
+
+ if(AM.pulledby)
+ visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.")
+ AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once.
+
pulling = AM
AM.pulledby = src
-
+ playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
update_pull_hud_icon()
if(ismob(AM))
var/mob/M = AM
+ if(!supress_message)
+ visible_message("[src] has grabbed [M] passively!")
if(!iscarbon(src))
M.LAssailant = null
else
@@ -368,11 +344,15 @@ var/next_mob_id = 0
if(pulling)
pulling.pulledby = null
+ if(ismob(pulling))
+ var/mob/M = pulling
+ M.update_canmove()// mob gets up if it was lyng down in a chokehold
pulling = null
+ grab_state = 0
update_pull_hud_icon()
/mob/proc/update_pull_hud_icon()
- if(client && hud_used)
+ if(hud_used)
if(hud_used.pull_icon)
hud_used.pull_icon.update_icon(src)
@@ -677,10 +657,11 @@ var/next_mob_id = 0
//Robots, animals and brains have their own version so don't worry about them
/mob/proc/update_canmove()
var/ko = weakened || paralysis || stat || (status_flags & FAKEDEATH)
+ var/chokehold = pulledby && pulledby.grab_state >= GRAB_NECK
var/buckle_lying = !(buckled && !buckled.buckle_lying)
var/has_legs = get_num_legs()
var/has_arms = get_num_arms()
- if(ko || resting || stunned)
+ if(ko || resting || stunned || chokehold)
drop_r_hand()
drop_l_hand()
unset_machine()
@@ -691,10 +672,12 @@ var/next_mob_id = 0
if(buckled)
lying = 90*buckle_lying
- else
- if((ko || resting || !has_legs) && !lying)
- fall(ko)
- canmove = !(ko || resting || stunned || buckled || (!has_legs && !has_arms))
+ else if(!lying)
+ if(resting)
+ fall()
+ else if(ko || !has_legs || chokehold)
+ fall(forced = 1)
+ canmove = !(ko || resting || stunned || chokehold || buckled || (!has_legs && !has_arms))
density = !lying
if(lying)
if(layer == initial(layer)) //to avoid special cases like hiding larvas.
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 2d8684ded9d..00e480cbcc2 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -32,7 +32,10 @@
var/other_mobs = null
var/memory = ""
var/disabilities = 0 //Carbon
+
var/atom/movable/pulling = null
+ var/grab_state = 0
+
var/next_move = null
var/notransform = null //Carbon
var/hand = null
@@ -86,9 +89,6 @@
var/research_scanner = 0 //For research scanner equipped mobs. Enable to show research data when examining.
- var/list/grabbed_by = list( )
- var/list/requests = list( )
-
var/list/mapobjs = list()
var/in_throw_mode = 0
diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm
deleted file mode 100644
index c89cf9ac1a8..00000000000
--- a/code/modules/mob/mob_grab.dm
+++ /dev/null
@@ -1,223 +0,0 @@
-#define UPGRADE_COOLDOWN 40
-#define UPGRADE_KILL_TIMER 100
-
-/obj/item/weapon/grab
- name = "grab"
- flags = NOBLUDGEON | ABSTRACT
- var/obj/screen/grab/hud = null
- var/mob/affecting = null
- var/mob/assailant = null
- var/state = GRAB_PASSIVE
-
- var/allow_upgrade = 1
- var/last_upgrade = 0
-
- layer = 21
- item_state = "nothing"
- w_class = 5
-
-
-/obj/item/weapon/grab/New(mob/user, mob/victim)
- ..()
- assailant = user
- affecting = victim
-
- hud = new /obj/screen/grab(src)
- hud.icon_state = "reinforce"
- hud.name = "reinforce grab"
- hud.master = src
-
- affecting.grabbed_by += src
-
-
-/obj/item/weapon/grab/Destroy()
- if(affecting)
- affecting.grabbed_by -= src
- affecting = null
- if(assailant)
- if(assailant.client)
- assailant.client.screen -= hud
- assailant = null
- qdel(hud)
- return ..()
-
-//Used by throw code to hand over the mob, instead of throwing the grab. The grab is then deleted by the throw code.
-/obj/item/weapon/grab/proc/get_mob_if_throwable()
- if(affecting)
- if(affecting.buckled)
- return null
- if(state >= GRAB_AGGRESSIVE)
- return affecting
- return null
-
-
-//This makes sure that the grab screen object is displayed in the correct hand.
-/obj/item/weapon/grab/proc/synch()
- if(affecting)
- if(assailant.r_hand == src)
- hud.screen_loc = ui_rhand
- else
- hud.screen_loc = ui_lhand
-
-
-/obj/item/weapon/grab/process()
- if(!confirm())
- return 0
-
- if(assailant.client)
- assailant.client.screen -= hud
- assailant.client.screen += hud
-
- if(assailant.pulling == affecting)
- assailant.stop_pulling()
-
- if(state <= GRAB_AGGRESSIVE)
- allow_upgrade = 1
- if((assailant.l_hand && assailant.l_hand != src && istype(assailant.l_hand, /obj/item/weapon/grab)))
- var/obj/item/weapon/grab/G = assailant.l_hand
- if(G.affecting != affecting)
- allow_upgrade = 0
- if((assailant.r_hand && assailant.r_hand != src && istype(assailant.r_hand, /obj/item/weapon/grab)))
- var/obj/item/weapon/grab/G = assailant.r_hand
- if(G.affecting != affecting)
- allow_upgrade = 0
- if(state == GRAB_AGGRESSIVE)
- var/h = affecting.hand
- affecting.hand = 0
- affecting.drop_item()
- affecting.hand = 1
- affecting.drop_item()
- affecting.hand = h
- for(var/X in affecting.grabbed_by)
- var/obj/item/weapon/grab/G = X
- if(G == src) continue
- if(G.state == GRAB_AGGRESSIVE)
- allow_upgrade = 0
- if(allow_upgrade)
- hud.icon_state = "reinforce"
- else
- hud.icon_state = "!reinforce"
- else
- if(!affecting.buckled)
- affecting.loc = assailant.loc
-
- var/breathing_tube = affecting.getorganslot("breathing_tube")
-
- if(state >= GRAB_NECK)
- affecting.Stun(5) //It will hamper your voice, being choked and all.
- if(isliving(affecting) && !breathing_tube)
- var/mob/living/L = affecting
- L.adjustOxyLoss(1)
-
- if(state >= GRAB_KILL)
- affecting.Weaken(5) //Should keep you down unless you get help.
- if(!breathing_tube)
- affecting.losebreath = min(affecting.losebreath + 2, 3)
-
-/obj/item/weapon/grab/attack_self(mob/user)
- s_click(hud)
-
-/obj/item/weapon/grab/proc/s_click(obj/screen/S)
- if(!affecting)
- return
- if(state == GRAB_UPGRADING)
- return
- if(world.time < (last_upgrade + UPGRADE_COOLDOWN))
- return
- if(!assailant.canmove || assailant.lying)
- qdel(src)
- return
-
- last_upgrade = world.time
-
- if(state < GRAB_AGGRESSIVE)
- if(!allow_upgrade)
- return
- assailant.visible_message("[assailant] grabs [affecting] aggressively!")
- state = GRAB_AGGRESSIVE
- icon_state = "grabbed1"
- else
- if(state < GRAB_NECK)
- if(isslime(affecting))
- assailant << "You squeeze [affecting], but nothing interesting happens!"
- return
-
- assailant.visible_message("[assailant] moves \his grip to [affecting]'s neck!")
- state = GRAB_NECK
- icon_state = "grabbed+1"
- if(!affecting.buckled)
- affecting.loc = assailant.loc
- add_logs(assailant, affecting, "neck-grabbed")
- hud.icon_state = "disarm/kill"
- hud.name = "disarm/kill"
- else
- if(state < GRAB_UPGRADING)
- assailant.visible_message("[assailant] starts to tighten \his grip on [affecting]'s neck!")
- hud.icon_state = "disarm/kill1"
- state = GRAB_UPGRADING
- if(do_after(assailant, UPGRADE_KILL_TIMER, target = affecting))
- if(state == GRAB_KILL)
- return
- if(!affecting)
- qdel(src)
- return
- if(!assailant.canmove || assailant.lying)
- qdel(src)
- return
- state = GRAB_KILL
- assailant.visible_message("[assailant] tightens \his grip on [affecting]'s neck!")
- add_logs(assailant, affecting, "strangled")
-
- assailant.changeNext_move(CLICK_CD_TKSTRANGLE)
- if(!affecting.getorganslot("breathing_tube"))
- affecting.losebreath += 1
- else
- if(assailant)
- assailant.visible_message("[assailant] is unable to tighten \his grip on [affecting]'s neck!")
- hud.icon_state = "disarm/kill"
- state = GRAB_NECK
-
-
-//This is used to make sure the victim hasn't managed to yackety sax away before using the grab.
-/obj/item/weapon/grab/proc/confirm()
- if(!assailant || !affecting)
- qdel(src)
- return 0
-
- if(affecting)
- if(!isturf(assailant.loc) || ( !isturf(affecting.loc) || assailant.loc != affecting.loc && get_dist(assailant, affecting) > 1) )
- qdel(src)
- return 0
-
- return 1
-
-
-/obj/item/weapon/grab/attack(mob/M, mob/user)
- if(!affecting)
- return
-
- if(M == affecting)
- s_click(hud)
- return
-
- if(M == assailant && state >= GRAB_AGGRESSIVE)
- if( (ishuman(user) && (user.disabilities & FAT) && ismonkey(affecting) ) || ( isalien(user) && iscarbon(affecting) ) )
- var/mob/living/carbon/attacker = user
- user.visible_message("[user] is attempting to devour [affecting]!")
- if(istype(user, /mob/living/carbon/alien/humanoid/hunter))
- if(!do_mob(user, affecting, 60)) return
- else
- if(!do_mob(user, affecting, 130)) return
- user.visible_message("[user] devours [affecting]!")
- affecting.loc = user
- attacker.stomach_contents.Add(affecting)
- qdel(src)
-
- add_logs(user, affecting, "attempted to put", src, "into [M]")
-
-/obj/item/weapon/grab/dropped()
- ..()
- qdel(src)
-
-#undef UPGRADE_COOLDOWN
-#undef UPGRADE_KILL_TIMER
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index bb213d051d4..cfba67193ce 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -8,9 +8,6 @@
if(buckled == mover)
return 1
if(ismob(mover))
- var/mob/moving_mob = mover
- if ((other_mobs && moving_mob.other_mobs))
- return 1
if (mover in buckled_mobs)
return 1
return (!mover.density || !density || lying)
@@ -114,7 +111,7 @@
Process_Incorpmove(direct)
return 0
- if(Process_Grab())
+ if(Process_Grab()) //are we restrained by someone's grip?
return
if(mob.buckled) //if we're buckled to something, tell it we moved.
@@ -136,54 +133,10 @@
if(!mob.Process_Spacemove(direct))
return 0
- if(mob.restrained()) //Why being pulled while cuffed prevents you from moving
- for(var/mob/M in orange(1, mob))
- if(M.pulling == mob)
- if(!M.incapacitated() && mob.Adjacent(M))
- src << "You're restrained! You can't move!"
- move_delay = world.time + 10
- return 0
- else
- M.stop_pulling()
-
-
//We are now going to move
moving = 1
move_delay = mob.movement_delay() + world.time
- //Something with pulling things
- if(locate(/obj/item/weapon/grab, mob))
- move_delay = max(move_delay, world.time + 7)
- var/list/L = mob.ret_grab()
- if(istype(L, /list))
- if(L.len == 2)
- L -= mob
- var/mob/M = L[1]
- if(M)
- if ((get_dist(mob, M) <= 1 || M.loc == mob.loc))
- . = ..()
- if(M)//Mob may get deleted during parent call
- if (isturf(M.loc))
- var/diag = get_dir(mob, M)
- if ((diag - 1) & diag)
- else
- diag = null
- if ((get_dist(mob, M) > 1 || diag))
- step(M, get_dir(M.loc, mob.loc))
- else
- for(var/mob/M in L)
- M.other_mobs = 1
- if(mob != M)
- M.animate_movement = 3
- for(var/mob/M in L)
- spawn( 0 )
- step(M, direct)
- return
- spawn( 1 )
- M.other_mobs = null
- M.animate_movement = 2
- return
-
if(mob.confused)
if(mob.confused > 40)
step(mob, pick(cardinal))
@@ -207,39 +160,14 @@
///Called by client/Move()
///Checks to see if you are being grabbed and if so attemps to break it
/client/proc/Process_Grab()
- if(mob.grabbed_by.len)
- var/list/grabbing = list()
+ if(mob.pulledby)
+ if(mob.restrained(ignore_grab = 1))
+ move_delay = world.time + 10
+ src << "You're restrained! You can't move!"
+ return 1
+ else
+ return mob.resist_grab(1)
- if(istype(mob.l_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = mob.l_hand
- grabbing += G.affecting
-
- if(istype(mob.r_hand, /obj/item/weapon/grab))
- var/obj/item/weapon/grab/G = mob.r_hand
- grabbing += G.affecting
-
- for(var/X in mob.grabbed_by)
- var/obj/item/weapon/grab/G = X
- switch(G.state)
-
- if(GRAB_PASSIVE)
- if(!grabbing.Find(G.assailant)) //moving always breaks a passive grab unless we are also grabbing our grabber.
- qdel(G)
-
- if(GRAB_AGGRESSIVE)
- move_delay = world.time + 10
- if(!prob(25))
- return 1
- mob.visible_message("[mob] has broken free of [G.assailant]'s grip!")
- qdel(G)
-
- if(GRAB_NECK)
- move_delay = world.time + 10
- if(!prob(5))
- return 1
- mob.visible_message("[mob] has broken free of [G.assailant]'s headlock!")
- qdel(G)
- return 0
///Process_Incorpmove
///Called by client/Move()
@@ -352,27 +280,19 @@
/mob/proc/mob_negates_gravity()
return 0
+//moves the mob/object we're pulling
/mob/proc/Move_Pulled(atom/A)
- if (!canmove || restrained() || !pulling)
+ if (!pulling)
return
- if (pulling.anchored)
- return
- if (!pulling.Adjacent(src))
+ if (pulling.anchored || !pulling.Adjacent(src))
+ stop_pulling()
return
if (A == loc && pulling.density)
return
if (!Process_Spacemove(get_dir(pulling.loc, A)))
return
- if (ismob(pulling))
- var/mob/M = pulling
- var/atom/movable/t = M.pulling
- M.stop_pulling()
- step(pulling, get_dir(pulling.loc, A))
- if(M)
- M.start_pulling(t)
- else
- step(pulling, get_dir(pulling.loc, A))
- return
+ step(pulling, get_dir(pulling.loc, A))
+
/mob/proc/slip(s_amount, w_amount, obj/O, lube)
return
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
index 2b9890ee8c7..e1539301204 100644
--- a/code/modules/vehicles/vehicle.dm
+++ b/code/modules/vehicles/vehicle.dm
@@ -109,7 +109,7 @@
/obj/vehicle/Move(NewLoc,Dir=0,step_x=0,step_y=0)
- ..()
+ . = ..()
handle_vehicle_layer()
handle_vehicle_offsets()
diff --git a/tgstation.dme b/tgstation.dme
index d2affc0e6c8..b36bbfe8d60 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1229,7 +1229,6 @@
#include "code\modules\mob\mob.dm"
#include "code\modules\mob\mob_cleanup.dm"
#include "code\modules\mob\mob_defines.dm"
-#include "code\modules\mob\mob_grab.dm"
#include "code\modules\mob\mob_helpers.dm"
#include "code\modules\mob\mob_movement.dm"
#include "code\modules\mob\mob_transformation_simple.dm"