mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-18 11:36:24 +01:00
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:
@@ -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
|
||||
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user