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"