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.
This commit is contained in:
phil235
2016-05-24 01:28:04 +02:00
parent 910d1e1ffe
commit 11ca987acb
62 changed files with 518 additions and 893 deletions
+28 -29
View File
@@ -50,38 +50,37 @@
qdel(src)
else
user << "<span class='notice'>You can't do that while something's on the spike!</span>"
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("<span class='danger'>[user] slams [G.affecting] onto the meat spike!</span>", "<span class='userdanger'>[user] slams you onto the meat spike!</span>", "<span class='italics'>You hear a squishy wet noise.</span>")
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 << "<span class='danger'>You can't use that on the spike!</span>"
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("<span class='danger'>[user] slams [L] onto the meat spike!</span>", "<span class='userdanger'>[user] slams you onto the meat spike!</span>", "<span class='italics'>You hear a squishy wet noise.</span>")
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
+27 -31
View File
@@ -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 << "<span class='warning'>[pushed_mob] is buckled to [pushed_mob.buckled]!</span>"
return
if(user.grab_state < GRAB_AGGRESSIVE)
user << "<span class='warning'>You need a better grip to do that!</span>"
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 << "<span class='warning'>[G.affecting] is buckled to [G.affecting.buckled]!</span>"
return 0
if(G.state < GRAB_AGGRESSIVE)
user << "<span class='warning'>You need a better grip to do that!</span>"
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("<span class='notice'>[G.assailant] has laid [G.affecting] on [src].</span>")
OT.patient = G.affecting
OT.check_patient()
qdel(I)
return 1
G.affecting.Weaken(2)
G.affecting.visible_message("<span class='danger'>[G.assailant] pushes [G.affecting] onto [src].</span>", \
"<span class='userdanger'>[G.assailant] pushes [G.affecting] onto [src].</span>")
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("<span class='danger'>[user] pushes [pushed_mob] onto [src].</span>", \
"<span class='userdanger'>[user] pushes [pushed_mob] onto [src].</span>")
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("<span class='notice'>[user] has laid [pushed_mob] on [src].</span>")
check_patient()
/obj/structure/table/optable/proc/check_patient()
var/mob/M = locate(/mob/living/carbon/human, loc)
if(M)
@@ -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 << "<span class='warning'>[GM] is attached to something!</span>"
return
for(var/obj/structure/transit_tube_pod/pod in loc)
pod.visible_message("<span class='warning'>[user] starts putting [GM] into the [pod]!</span>")
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.", "<span class='notice'>You start emptying [pod]'s contents onto the floor...</span>")
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.", "<span class='notice'>You start emptying [pod]'s contents onto the floor...</span>")
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("<span class='warning'>[user] starts putting [GM] into the [pod]!</span>")
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 << "<span class='warning'>Empty the pod first!</span>"
+44 -59
View File
@@ -22,12 +22,37 @@
playsound(src.loc, "swing_hit", 25, 1)
swirlie.visible_message("<span class='danger'>[user] slams the toilet seat onto [swirlie]'s head!</span>", "<span class='userdanger'>[user] slams the toilet seat onto your head!</span>", "<span class='italics'>You hear reverberating porcelain.</span>")
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 << "<span class='warning'>[GM] needs to be on [src]!</span>"
return
if(!swirlie)
if(open)
GM.visible_message("<span class='danger'>[user] starts to give [GM] a swirlie!</span>", "<span class='userdanger'>[user] starts to give you a swirlie...</span>")
swirlie = GM
if(do_after(user, 30, 0, target = src))
GM.visible_message("<span class='danger'>[user] gives [GM] a swirlie!</span>", "<span class='userdanger'>[user] gives you a swirlie!</span>", "<span class='italics'>You hear a toilet flushing.</span>")
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("<span class='danger'>[user] slams [GM.name] into [src]!</span>", "<span class='userdanger'>[user] slams you into [src]!</span>")
GM.adjustBruteLoss(5)
else
user << "<span class='warning'>You need a tighter grip!</span>"
else if(cistern && !open)
if(!contents.len)
user << "<span class='notice'>The cistern is empty.</span>"
return
else
var/obj/item/I = pick(contents)
if(ishuman(user))
@@ -36,10 +61,9 @@
I.loc = get_turf(src)
user << "<span class='notice'>You find [I] in the cistern.</span>"
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"]!", "<span class='notice'>You [cistern ? "replace the lid on the cistern" : "lift the lid off the cistern"]!</span>", "<span class='italics'>You hear grinding porcelain.</span>")
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 << "<span class='notice'>You carefully place [I] into the cistern.</span>"
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 << "<span class='notice'>You fill [RG] from [src]. Gross.</span>"
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 << "<span class='warning'>[GM] needs to be on [src]!</span>"
return
if(!swirlie)
if(open)
GM.visible_message("<span class='danger'>[user] starts to give [GM] a swirlie!</span>", "<span class='userdanger'>[user] starts to give you a swirlie...</span>")
swirlie = GM
if(do_after(user, 30, 0, target = src))
GM.visible_message("<span class='danger'>[user] gives [GM] a swirlie!</span>", "<span class='userdanger'>[user] gives you a swirlie!</span>", "<span class='italics'>You hear a toilet flushing.</span>")
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("<span class='danger'>[user] slams [GM.name] into [src]!</span>", "<span class='userdanger'>[user] slams you into [src]!</span>")
GM.adjustBruteLoss(5)
else
user << "<span class='warning'>You need a tighter grip!</span>"
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 << "<span class='notice'>[GM.name] needs to be on [src].</span>"
return
user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("<span class='danger'>[user] slams [GM] into [src]!</span>", "<span class='danger'>You slam [GM] into [src]!</span>")
GM.adjustBruteLoss(8)
else
user << "<span class='warning'>You need a tighter grip!</span>"
/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 << "<span class='notice'>[GM.name] needs to be on [src].</span>"
return
user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("<span class='danger'>[user] slams [GM] into [src]!</span>", "<span class='danger'>You slam [GM] into [src]!</span>")
GM.adjustBruteLoss(8)
else
user << "<span class='warning'>You need a tighter grip!</span>"
else
return ..()
..()
/obj/machinery/shower
name = "shower"