mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-05-18 20:59:56 +01:00
d5849910e5
* Begin clickcode attack_self fix Begins the work to make everything call back to parent for attack_self so that signals are sacred. * Makes MORE things call the attack_self() parent Yes, I could make special_handling a var on obj/item HOWEVER i want it to be specific so it can be tracked down later and ONLY the objects that use it can be refactored instead of sitting there literally forever and it just becoming 'a thing'. * Finishes making the rest of attack_self call parent. As mentioned, things such as 'specialty_goggles' 'special_handling' and the such are only there to help with attack_self until the attack_self is recoded for those items. * begone foul demon * some more cleanup * These * GOD this was annoying * yeh * Fix this * fLARES * Thesee too * toys! * Even more! * More fixes * Even more * rest of em * these too * Update syndie.dm * hardref clear * Update code/game/gamemodes/nuclear/pinpointer.dm * Update code/game/objects/effects/mines.dm * Update code/game/objects/items/blueprints_vr.dm * Update code/game/objects/items/blueprints_vr.dm * Update code/game/objects/items/contraband_vr.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/gunbox.dm * Update code/game/objects/items/gunbox.dm * Update code/game/objects/items/gunbox_vr.dm * Update code/game/objects/items/gunbox_vr.dm * Update code/game/objects/items/weapons/gift_wrappaper.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/crayons.dm * Update code/game/objects/items/gunbox.dm * these too * Update maintpanel_stack.dm * angry warning * Fixes packaged snacks. Fixes improper var default. * Special handling for these * proper poly types * Fixes magclaws Makes the 'features' it had just part of base magboots that can be adjusted via varswap. * Fixes jackets Fixes https://github.com/VOREStation/VOREStation/issues/18941 * Small bugfix Makes p_Theyre properly capitialize Makes examine show proper wording * Update gift_wrappaper.dm
416 lines
13 KiB
Plaintext
416 lines
13 KiB
Plaintext
#define UPGRADE_KILL_TIMER 100
|
|
|
|
///Process_Grab()
|
|
///Called by client/Move()
|
|
///Checks to see if you are grabbing or being grabbed by anything and if moving will affect your grab.
|
|
/client/proc/Process_Grab()
|
|
//if we are being grabbed
|
|
if(isliving(mob))
|
|
var/mob/living/L = mob
|
|
if(!L.canmove && L.grabbed_by.len)
|
|
L.resist() //shortcut for resisting grabs
|
|
|
|
//if we are grabbing someone
|
|
for(var/obj/item/grab/G in list(L.l_hand, L.r_hand))
|
|
G.reset_kill_state() //no wandering across the station/asteroid while choking someone
|
|
|
|
/obj/item/grab
|
|
name = "grab"
|
|
icon = 'icons/mob/screen1.dmi'
|
|
icon_state = "reinforce"
|
|
item_flags = DROPDEL | NOSTRIP
|
|
var/atom/movable/screen/grab/hud = null
|
|
var/mob/living/affecting = null
|
|
var/mob/living/carbon/human/assailant = null
|
|
var/state = GRAB_PASSIVE
|
|
|
|
var/allow_upgrade = 1
|
|
var/last_action = 0
|
|
var/last_hit_zone = 0
|
|
var/force_down //determines if the affecting mob will be pinned to the ground
|
|
var/dancing //determines if assailant and affecting keep looking at each other. Basically a wrestling position
|
|
|
|
abstract = 1
|
|
item_state = "nothing"
|
|
w_class = ITEMSIZE_HUGE
|
|
|
|
|
|
/obj/item/grab/Initialize(mapload, mob/victim)
|
|
. = ..()
|
|
assailant = loc
|
|
affecting = victim
|
|
|
|
if(!istype(assailant) || !istype(affecting) || affecting.anchored || !assailant.Adjacent(victim))
|
|
return INITIALIZE_HINT_QDEL
|
|
|
|
affecting.grabbed_by += src
|
|
affecting.reveal(span_warning("You are revealed as [assailant] grabs you."))
|
|
assailant.reveal(span_warning("You reveal yourself as you grab [affecting]."))
|
|
|
|
hud = new /atom/movable/screen/grab(src)
|
|
hud.icon_state = "reinforce"
|
|
icon_state = "grabbed"
|
|
hud.name = "reinforce grab"
|
|
hud.master = src
|
|
|
|
//check if assailant is grabbed by victim as well
|
|
if(assailant.grabbed_by)
|
|
for (var/obj/item/grab/G in assailant.grabbed_by)
|
|
if(G.assailant == affecting && G.affecting == assailant)
|
|
G.dancing = 1
|
|
G.adjust_position()
|
|
dancing = 1
|
|
|
|
//stop pulling the affected
|
|
if(assailant.pulling == affecting)
|
|
assailant.stop_pulling()
|
|
|
|
adjust_position()
|
|
|
|
|
|
//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/grab/proc/throw_held()
|
|
if(affecting)
|
|
if(affecting.buckled)
|
|
return null
|
|
if(state >= GRAB_AGGRESSIVE)
|
|
animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = initial(affecting.pixel_y), 4, 1)
|
|
return affecting
|
|
|
|
return null
|
|
|
|
|
|
//This makes sure that the grab screen object is displayed in the correct hand.
|
|
/obj/item/grab/proc/synch() //why is this needed?
|
|
if(QDELETED(src))
|
|
return
|
|
if(affecting)
|
|
if(assailant.r_hand == src)
|
|
hud.screen_loc = ui_rhand
|
|
else
|
|
hud.screen_loc = ui_lhand
|
|
|
|
/obj/item/grab/process()
|
|
if(QDELETED(src)) // GC is trying to delete us, we'll kill our processing so we can cleanly GC
|
|
return PROCESS_KILL
|
|
|
|
confirm()
|
|
if(!assailant)
|
|
qdel(src) // Same here, except we're trying to delete ourselves.
|
|
return PROCESS_KILL
|
|
|
|
if(assailant.client)
|
|
assailant.client.screen -= hud
|
|
assailant.client.screen += hud
|
|
|
|
if(state <= GRAB_AGGRESSIVE)
|
|
allow_upgrade = 1
|
|
//disallow upgrading if we're grabbing more than one person
|
|
if((assailant.l_hand && assailant.l_hand != src && istype(assailant.l_hand, /obj/item/grab)))
|
|
var/obj/item/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/grab)))
|
|
var/obj/item/grab/G = assailant.r_hand
|
|
if(G.affecting != affecting)
|
|
allow_upgrade = 0
|
|
|
|
//disallow upgrading past aggressive if we're being grabbed aggressively
|
|
for(var/obj/item/grab/G in affecting.grabbed_by)
|
|
if(G == src) continue
|
|
if(G.state >= GRAB_AGGRESSIVE)
|
|
allow_upgrade = 0
|
|
|
|
if(allow_upgrade)
|
|
if(state < GRAB_AGGRESSIVE)
|
|
hud.icon_state = "reinforce"
|
|
else
|
|
hud.icon_state = "reinforce1"
|
|
else
|
|
hud.icon_state = "!reinforce"
|
|
|
|
if(state >= GRAB_AGGRESSIVE)
|
|
affecting.drop_l_hand()
|
|
affecting.drop_r_hand()
|
|
|
|
if(iscarbon(affecting))
|
|
handle_eye_mouth_covering(affecting, assailant, assailant.zone_sel.selecting)
|
|
|
|
if(force_down)
|
|
if(affecting.loc != assailant.loc || size_difference(affecting, assailant) > 0)
|
|
force_down = 0
|
|
else
|
|
affecting.Weaken(2)
|
|
|
|
if(state >= GRAB_NECK)
|
|
affecting.Stun(3)
|
|
if(isliving(affecting))
|
|
var/mob/living/L = affecting
|
|
L.adjustOxyLoss(1)
|
|
|
|
if(state >= GRAB_KILL)
|
|
//affecting.apply_effect(STUTTER, 5) //would do this, but affecting isn't declared as mob/living for some stupid reason.
|
|
affecting.stuttering = max(affecting.stuttering, 5) //It will hamper your voice, being choked and all.
|
|
affecting.Weaken(5) //Should keep you down unless you get help.
|
|
affecting.losebreath = max(affecting.losebreath + 2, 3)
|
|
|
|
adjust_position()
|
|
|
|
/obj/item/grab/proc/handle_eye_mouth_covering(mob/living/carbon/target, mob/user, var/target_zone)
|
|
var/announce = (target_zone != last_hit_zone) //only display messages when switching between different target zones
|
|
last_hit_zone = target_zone
|
|
|
|
switch(target_zone)
|
|
if(O_MOUTH)
|
|
if(announce)
|
|
user.visible_message(span_warning("\The [user] covers [target]'s mouth!"))
|
|
if(target.silent < 3)
|
|
target.silent = 3
|
|
if(O_EYES)
|
|
if(announce)
|
|
assailant.visible_message(span_warning("[assailant] covers [affecting]'s eyes!"))
|
|
if(affecting.eye_blind < 3)
|
|
affecting.Blind(3)
|
|
//VOREStation Edit
|
|
if(BP_HEAD)
|
|
if(force_down)
|
|
if(user.a_intent == I_HELP)
|
|
if(announce)
|
|
assailant.visible_message(span_warning("[assailant] sits on [target]'s face!"))
|
|
//VOREStation Edit End
|
|
|
|
/obj/item/grab/attack_self(mob/user)
|
|
. = ..(user)
|
|
if(.)
|
|
return TRUE
|
|
return s_click(hud)
|
|
|
|
|
|
//Updating pixelshift, position and direction
|
|
//Gets called on process, when the grab gets upgraded or the assailant moves
|
|
/obj/item/grab/proc/adjust_position()
|
|
if(!affecting)
|
|
qdel(src)
|
|
return
|
|
if(affecting.buckled)
|
|
animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = initial(affecting.pixel_y), 4, 1, LINEAR_EASING)
|
|
return
|
|
if(affecting.lying && state != GRAB_KILL)
|
|
animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = initial(affecting.pixel_y), 5, 1, LINEAR_EASING)
|
|
if(force_down)
|
|
affecting.set_dir(SOUTH) //face up
|
|
return
|
|
var/shift = 0
|
|
var/adir = get_dir(assailant, affecting)
|
|
affecting.layer = MOB_LAYER
|
|
switch(state)
|
|
if(GRAB_PASSIVE)
|
|
shift = 8
|
|
if(dancing) //look at partner
|
|
shift = 10
|
|
assailant.set_dir(get_dir(assailant, affecting))
|
|
if(GRAB_AGGRESSIVE)
|
|
shift = 12
|
|
if(GRAB_NECK, GRAB_UPGRADING)
|
|
shift = -10
|
|
adir = assailant.dir
|
|
affecting.set_dir(assailant.dir)
|
|
affecting.loc = assailant.loc
|
|
if(GRAB_KILL)
|
|
shift = 0
|
|
adir = 1
|
|
affecting.set_dir(SOUTH) //face up
|
|
affecting.loc = assailant.loc
|
|
|
|
switch(adir)
|
|
if(NORTH)
|
|
animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y =-shift, 5, 1, LINEAR_EASING)
|
|
affecting.layer = BELOW_MOB_LAYER
|
|
if(SOUTH)
|
|
animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = shift, 5, 1, LINEAR_EASING)
|
|
if(WEST)
|
|
animate(affecting, pixel_x = shift, pixel_y = initial(affecting.pixel_y), 5, 1, LINEAR_EASING)
|
|
if(EAST)
|
|
animate(affecting, pixel_x =-shift, pixel_y = initial(affecting.pixel_y), 5, 1, LINEAR_EASING)
|
|
|
|
/obj/item/grab/proc/s_click(atom/movable/screen/S)
|
|
if(QDELETED(src))
|
|
return
|
|
if(!affecting)
|
|
return
|
|
if(state == GRAB_UPGRADING)
|
|
return
|
|
if(world.time < (last_action + UPGRADE_COOLDOWN))
|
|
return
|
|
if(!assailant.canmove || assailant.lying)
|
|
qdel(src)
|
|
return
|
|
|
|
last_action = world.time
|
|
|
|
if(state < GRAB_AGGRESSIVE)
|
|
if(!allow_upgrade)
|
|
return
|
|
if(!affecting.lying || size_difference(affecting, assailant) > 0)
|
|
assailant.visible_message(span_warning("[assailant] has grabbed [affecting] aggressively (now hands)!"))
|
|
else
|
|
assailant.visible_message(span_warning("[assailant] pins [affecting] down to the ground (now hands)!"))
|
|
apply_pinning(affecting, assailant)
|
|
|
|
state = GRAB_AGGRESSIVE
|
|
icon_state = "grabbed1"
|
|
hud.icon_state = "reinforce1"
|
|
add_attack_logs(assailant, affecting, "Aggressively grabbed", FALSE) // Not important enough to notify admins, but still helpful.
|
|
else if(state < GRAB_NECK)
|
|
if(isslime(affecting))
|
|
to_chat(assailant, span_notice("You squeeze [affecting], but nothing interesting happens."))
|
|
return
|
|
|
|
assailant.visible_message(span_warning("[assailant] has reinforced [assailant.p_their()] grip on [affecting] (now neck)!"))
|
|
state = GRAB_NECK
|
|
icon_state = "grabbed+1"
|
|
assailant.set_dir(get_dir(assailant, affecting))
|
|
add_attack_logs(assailant,affecting,"Neck grabbed")
|
|
hud.icon_state = "kill"
|
|
hud.name = "kill"
|
|
affecting.Stun(10) //10 ticks of ensured grab
|
|
else if(state < GRAB_UPGRADING)
|
|
assailant.visible_message(span_danger("[assailant] starts to tighten [assailant.p_their()] grip on [affecting]'s neck!"))
|
|
hud.icon_state = "kill1"
|
|
|
|
state = GRAB_KILL
|
|
assailant.visible_message(span_danger("[assailant] has tightened [assailant.p_their()] grip on [affecting]'s neck!"))
|
|
add_attack_logs(assailant,affecting,"Strangled")
|
|
affecting.setClickCooldown(10)
|
|
affecting.AdjustLosebreath(1)
|
|
affecting.set_dir(WEST)
|
|
adjust_position()
|
|
|
|
//This is used to make sure the victim hasn't managed to yackety sax away before using the grab.
|
|
/obj/item/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/grab/attack(mob/M, mob/living/user)
|
|
if(QDELETED(src))
|
|
return
|
|
if(!affecting)
|
|
return
|
|
if(world.time < (last_action + 20))
|
|
return
|
|
|
|
last_action = world.time
|
|
reset_kill_state() //using special grab moves will interrupt choking them
|
|
|
|
//clicking on the victim while grabbing them
|
|
if(M == affecting)
|
|
if(ishuman(affecting))
|
|
var/mob/living/carbon/human/H = affecting
|
|
var/hit_zone = assailant.zone_sel.selecting
|
|
flick(hud.icon_state, hud)
|
|
switch(assailant.a_intent)
|
|
if(I_HELP)
|
|
if(force_down)
|
|
to_chat(assailant, span_warning("You are no longer pinning [affecting] to the ground."))
|
|
force_down = 0
|
|
return
|
|
if(state >= GRAB_AGGRESSIVE)
|
|
H.apply_pressure(assailant, hit_zone)
|
|
else
|
|
inspect_organ(affecting, assailant, hit_zone)
|
|
|
|
if(I_GRAB)
|
|
jointlock(affecting, assailant, hit_zone)
|
|
|
|
if(I_HURT)
|
|
if(hit_zone == O_EYES)
|
|
attack_eye(affecting, assailant)
|
|
else if(hit_zone == BP_HEAD)
|
|
headbutt(affecting, assailant)
|
|
else
|
|
dislocate(affecting, assailant, hit_zone)
|
|
|
|
if(I_DISARM)
|
|
pin_down(affecting, assailant)
|
|
|
|
/obj/item/grab/proc/reset_kill_state()
|
|
if(state == GRAB_KILL)
|
|
assailant.visible_message(span_warning("[assailant] lost [assailant.p_their()] tight grip on [affecting]'s neck!"))
|
|
hud.icon_state = "kill"
|
|
state = GRAB_NECK
|
|
|
|
/obj/item/grab/proc/handle_resist()
|
|
var/grab_name
|
|
var/break_strength = 1
|
|
var/list/break_chance_table = list(100)
|
|
switch(state)
|
|
//if(GRAB_PASSIVE)
|
|
|
|
if(GRAB_AGGRESSIVE)
|
|
grab_name = "grip"
|
|
//Being knocked down makes it harder to break a grab, so it is easier to cuff someone who is down without forcing them into unconsciousness.
|
|
if(!affecting.incapacitated(INCAPACITATION_KNOCKDOWN))
|
|
break_strength++
|
|
break_chance_table = list(15, 60, 100)
|
|
|
|
if(GRAB_NECK)
|
|
grab_name = "headlock"
|
|
//If the you move when grabbing someone then it's easier for them to break free. Same if the affected mob is immune to stun.
|
|
if(world.time - assailant.l_move_time < 30 || !affecting.stunned)
|
|
break_strength++
|
|
break_chance_table = list(3, 18, 45, 100)
|
|
|
|
|
|
if(GRAB_KILL)
|
|
grab_name = "stranglehold"
|
|
break_chance_table = list(5, 20, 40, 80, 100)
|
|
|
|
//It's easier to break out of a grab by a smaller mob
|
|
break_strength += max(size_difference(affecting, assailant), 0)
|
|
var/prob_mult = 1
|
|
var/mob/living/carbon/human/grabbee = affecting
|
|
var/mob/living/carbon/human/grabber = assailant
|
|
if(istype(grabbee))
|
|
prob_mult /= grabbee.species.grab_resist_divisor_self
|
|
break_strength += grabbee.species.grab_power_self
|
|
if(istype(grabber))
|
|
prob_mult /= grabber.species.grab_resist_divisor_victims
|
|
break_strength += grabber.species.grab_power_victims
|
|
|
|
var/break_chance = CLAMP(prob_mult*break_chance_table[CLAMP(break_strength, 1, break_chance_table.len)],0,100)
|
|
if(prob(break_chance))
|
|
if(state == GRAB_KILL)
|
|
reset_kill_state()
|
|
return
|
|
else if(grab_name)
|
|
affecting.visible_message(span_warning("[affecting] has broken free of [assailant]'s [grab_name]!"))
|
|
qdel(src)
|
|
|
|
//returns the number of size categories between affecting and assailant, rounded. Positive means A is larger than B
|
|
/obj/item/grab/proc/size_difference(mob/A, mob/B)
|
|
return mob_size_difference(A.mob_size, B.mob_size)
|
|
|
|
/obj/item/grab/Destroy()
|
|
animate(affecting, pixel_x = initial(affecting.pixel_x), pixel_y = initial(affecting.pixel_y), 4, 1, LINEAR_EASING)
|
|
affecting.reset_plane_and_layer()
|
|
if(affecting)
|
|
affecting.grabbed_by -= src
|
|
affecting = null
|
|
if(assailant)
|
|
if(assailant.client)
|
|
assailant.client.screen -= hud
|
|
assailant = null
|
|
qdel(hud)
|
|
hud = null
|
|
return ..()
|
|
|
|
#undef UPGRADE_KILL_TIMER
|