Files
Bubberstation/code/datums/elements/selfknockback.dm
SkyratBot e65a48e91f [MIRROR] Adds SIGNAL_HANDLER and SIGNAL_HANDLER_DOES_SLEEP to prevent signal callbacks from blocking (#430)
* Adds SIGNAL_HANDLER and SIGNAL_HANDLER_DOES_SLEEP to prevent signal callbacks from blocking (#52761)

Adds SIGNAL_HANDLER, a macro that sets SHOULD_NOT_SLEEP(TRUE). This should ideally be required on all new signal callbacks.

Adds BLOCKING_SIGNAL_HANDLER, a macro that does nothing except symbolize "this is an older signal that didn't necessitate a code rewrite". It should not be allowed for new work.

This comes from discussion around #52735, which yields by calling input, and (though it sets the return type beforehand) will not properly return the flag to prevent attack from slapping.

To fix 60% of the yielding cases, WrapAdminProcCall no longer waits for another admin's proc call to finish. I'm not an admin, so I don't know how many behinds this has saved, but if this is problematic for admins I can just make it so that it lets you do it anyway. I'm not sure what the point of this babysitting was anyway.

Requested by @optimumtact.
Changelog

cl
admin: Calling a proc while another admin is calling one will no longer wait for the first to finish. You will simply just have to call it again.
/cl

* Adds SIGNAL_HANDLER and SIGNAL_HANDLER_DOES_SLEEP to prevent signal callbacks from blocking

Co-authored-by: Jared-Fogle <35135081+Jared-Fogle@users.noreply.github.com>
2020-08-19 20:17:28 -04:00

65 lines
2.7 KiB
Plaintext

/datum/element/selfknockback
element_flags = ELEMENT_BESPOKE
id_arg_index = 2
var/override_throw_val
var/override_speed_val
/* Adds the ability to put recoil on various things, throwing the user back proportional to the force and speed set.
Important note: Force/Throw_Amount, is how far you want to throw a user. By default, it is calculated based on damage below.
Speed_Amount, is a measure of how long it will take a user to get thrown to the target. By default, it is calculated by
clamping the Knockback_Force value below. */
/datum/element/selfknockback/Attach(datum/target, throw_amount, speed_amount)
. = ..()
if(isitem(target))
RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, .proc/Item_SelfKnockback)
else if(isprojectile(target))
RegisterSignal(target, COMSIG_PROJECTILE_FIRE, .proc/Projectile_SelfKnockback)
else
return ELEMENT_INCOMPATIBLE
override_throw_val = throw_amount
override_speed_val = speed_amount
/datum/element/selfknockback/Detach(datum/source, force)
. = ..()
UnregisterSignal(source, list(COMSIG_ITEM_AFTERATTACK, COMSIG_PROJECTILE_FIRE))
/datum/element/selfknockback/proc/Get_Knockback_Force(default_force)
if(override_throw_val)
return override_throw_val
else
return default_force
/datum/element/selfknockback/proc/Get_Knockback_Speed(default_speed)
if(override_speed_val)
return override_speed_val
else
return default_speed
/datum/element/selfknockback/proc/Item_SelfKnockback(obj/item/I, atom/attacktarget, mob/usertarget, proximity_flag)
SIGNAL_HANDLER
if(isturf(attacktarget) && !attacktarget.density)
return
if(proximity_flag || (get_dist(attacktarget, usertarget) <= I.reach))
var/knockback_force = Get_Knockback_Force(clamp(CEILING((I.force / 10), 1), 1, 5))
var/knockback_speed = Get_Knockback_Speed(clamp(knockback_force, 1, 5))
var/target_angle = Get_Angle(attacktarget, usertarget)
var/move_target = get_ranged_target_turf(usertarget, angle2dir(target_angle), knockback_force)
usertarget.throw_at(move_target, knockback_force, knockback_speed)
usertarget.visible_message("<span class='warning'>[usertarget] gets thrown back by the force of \the [I] impacting \the [attacktarget]!</span>", "<span class='warning'>The force of \the [I] impacting \the [attacktarget] sends you flying!</span>")
/datum/element/selfknockback/proc/Projectile_SelfKnockback(obj/projectile/P)
SIGNAL_HANDLER
if(!P.firer)
return
var/knockback_force = Get_Knockback_Force(clamp(CEILING((P.damage / 10), 1), 1, 5))
var/knockback_speed = Get_Knockback_Speed(clamp(knockback_force, 1, 5))
var/atom/movable/knockback_target = P.firer
var/move_target = get_edge_target_turf(knockback_target, angle2dir(P.original_angle+180))
knockback_target.throw_at(move_target, knockback_force, knockback_speed)