From 11ca987acb96fbf6092ea897ed6429db79cfdf34 Mon Sep 17 00:00:00 2001 From: phil235 Date: Tue, 24 May 2016 01:28:04 +0200 Subject: [PATCH] Merges Pull and Grab into a single functionality. Pulling someone is now the same as a passive grab. You can start pulling someone with ctrlclick or by using the grab intent with empty hand. Using the grab intent again on the pulled person tries to grab them aggressively, then neck grab, then kill grab. Two mobs can no longer pull the same mob at the same time. Pulling someone break any other pull/grab from other mob on that person. The grab item is gone entirely. You can now only grab one mob at a time, instead of two (one for each hand). Being aggressively grabbed or more now counts as being restrained (like handcuffed). A neck grab or more makes you lie down and prevents you from getting up until the grab is broken. Fixes movement when moving with a grabbed person. Fixes movement when moving a pulled person around you diagonally. Fixes neckgrab moving the victim on your turf even if the turf is dense. --- code/__DEFINES/combat.dm | 9 +- code/__DEFINES/misc.dm | 7 +- code/_onclick/click.dm | 2 +- code/_onclick/hud/screen_objects.dm | 14 -- code/datums/diseases/transformation.dm | 4 - code/datums/martial.dm | 14 +- code/game/atoms_movable.dm | 25 +- .../gamemodes/changeling/powers/absorb.dm | 22 +- code/game/gamemodes/sandbox/h_sandbox.dm | 2 +- code/game/machinery/dna_scanner.dm | 13 - code/game/machinery/washing_machine.dm | 19 +- code/game/objects/items.dm | 2 +- .../items/weapons/implants/implantchair.dm | 19 +- .../objects/items/weapons/storage/backpack.dm | 2 +- .../objects/items/weapons/storage/bags.dm | 4 +- .../objects/items/weapons/storage/storage.dm | 2 + .../objects/items/weapons/storage/wallets.dm | 2 +- code/game/objects/structures/kitchen_spike.dm | 57 +++-- code/game/objects/structures/tables_racks.dm | 58 +++-- .../structures/transit_tubes/station.dm | 63 ++--- code/game/objects/structures/watercloset.dm | 103 ++++---- .../food&drinks/kitchen machinery/gibber.dm | 31 ++- .../kitchen machinery/monkeyrecycler.dm | 12 - .../kitchen machinery/processor.dm | 18 +- code/modules/holiday/easter.dm | 2 +- code/modules/holodeck/items.dm | 34 +-- code/modules/mob/interactive.dm | 11 +- code/modules/mob/inventory.dm | 8 +- .../living/carbon/alien/humanoid/humanoid.dm | 20 +- .../mob/living/carbon/alien/larva/larva.dm | 4 +- code/modules/mob/living/carbon/alien/life.dm | 3 +- code/modules/mob/living/carbon/carbon.dm | 57 ++--- .../mob/living/carbon/carbon_defense.dm | 12 + .../mob/living/carbon/carbon_movement.dm | 1 + code/modules/mob/living/carbon/examine.dm | 3 + .../mob/living/carbon/human/examine.dm | 3 + .../mob/living/carbon/human/human_defense.dm | 16 +- .../mob/living/carbon/human/human_helpers.dm | 9 +- .../mob/living/carbon/human/inventory.dm | 1 + .../mob/living/carbon/human/species.dm | 16 -- code/modules/mob/living/carbon/inventory.dm | 3 + code/modules/mob/living/carbon/life.dm | 10 +- code/modules/mob/living/carbon/monkey/life.dm | 2 +- code/modules/mob/living/living.dm | 187 +++++++-------- code/modules/mob/living/living_defense.dm | 61 +++-- code/modules/mob/living/living_defines.dm | 2 +- code/modules/mob/living/silicon/ai/ai.dm | 4 +- code/modules/mob/living/silicon/pai/pai.dm | 4 +- .../modules/mob/living/silicon/robot/robot.dm | 4 +- code/modules/mob/living/silicon/silicon.dm | 2 +- .../friendly/drone/interaction.dm | 3 +- .../simple_animal/friendly/drone/inventory.dm | 3 + .../mob/living/simple_animal/hostile/bees.dm | 2 +- .../living/simple_animal/hostile/statue.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 3 + .../mob/living/simple_animal/slime/slime.dm | 2 +- code/modules/mob/mob.dm | 73 +++--- code/modules/mob/mob_defines.dm | 6 +- code/modules/mob/mob_grab.dm | 223 ------------------ code/modules/mob/mob_movement.dm | 108 ++------- code/modules/vehicles/vehicle.dm | 2 +- tgstation.dme | 1 - 62 files changed, 518 insertions(+), 893 deletions(-) delete mode 100644 code/modules/mob/mob_grab.dm 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"