Add alternate attack procs (#56663)

Adds alternate attack procs for right-clicking. Updates the gunpoint code to use this new proc as an example (though I suspect this is being changed soon, so oops).

This makes it easier to add new behavior to right click, which we should be doing.
This commit is contained in:
Mothblocks
2021-02-05 16:23:09 -08:00
committed by GitHub
parent 1a58b33ef3
commit 33ca41c0bd
3 changed files with 82 additions and 10 deletions
+11
View File
@@ -278,3 +278,14 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
/// If a carbon is thrown at a speed faster than normal and impacts something solid, they take extra damage for every extra speed up to this number (see [/mob/living/carbon/proc/throw_impact])
#define CARBON_MAX_IMPACT_SPEED_BONUS 5
/// Alternate attack defines. Return these at the end of procs like afterattack_alt.
/// Calls the normal attack proc. For example, if returned in afterattack_alt, will call afterattack.
/// Will continue the chain depending on the return value of the non-alternate proc, like with normal attacks.
#define ALT_ATTACK_CALL_NORMAL 1
/// Cancels the attack chain entirely.
#define ALT_ATTACK_CANCEL_ATTACK_CHAIN 2
/// Proceed with the attack chain, but don't call the normal methods.
#define ALT_ATTACK_CONTINUE_CHAIN 3
+64 -1
View File
@@ -8,15 +8,41 @@
* * [/obj/item/proc/afterattack]. The return value does not matter.
*/
/obj/item/proc/melee_attack_chain(mob/user, atom/target, params)
var/is_right_clicking = params2list(params)["right"]
if(tool_behaviour && target.tool_act(user, src, tool_behaviour))
return TRUE
if(pre_attack(target, user, params))
return TRUE
if(target.attackby(src,user, params))
var/attackby_result
if (is_right_clicking)
switch (target.attackby_alt(src, user, params))
if (ALT_ATTACK_CALL_NORMAL)
attackby_result = target.attackby(src, user, params)
if (ALT_ATTACK_CANCEL_ATTACK_CHAIN)
return TRUE
if (null)
CRASH("attackby_alt must return an ALT_ATTACK_* define, please consult code/__DEFINES/combat.dm")
else
attackby_result = target.attackby(src, user, params)
if (attackby_result)
return TRUE
if(QDELETED(src) || QDELETED(target))
attack_qdeleted(target, user, TRUE, params)
return TRUE
if (is_right_clicking)
var/after_attack_alt_result = afterattack_alt(target, user, TRUE, params)
// There's no chain left to continue at this point, so CANCEL_ATTACK_CHAIN and CONTINUE_CHAIN are functionally the same.
if (after_attack_alt_result == ALT_ATTACK_CANCEL_ATTACK_CHAIN || after_attack_alt_result == ALT_ATTACK_CONTINUE_CHAIN)
return TRUE
return afterattack(target, user, TRUE, params)
/// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
@@ -55,6 +81,19 @@
return TRUE
return FALSE
/**
* Called on an object being right-clicked on by an item
*
* Arguments:
* * obj/item/weapon - The item hitting this atom
* * mob/user - The wielder of this item
* * params - click params such as alt/shift etc
*
* See: [/obj/item/proc/melee_attack_chain]
*/
/atom/proc/attackby_alt(obj/item/weapon, mob/user, params)
return ALT_ATTACK_CALL_NORMAL
/obj/attackby(obj/item/I, mob/living/user, params)
return ..() || ((obj_flags & CAN_BE_HIT) && I.attack_obj(src, user))
@@ -64,6 +103,15 @@
user.changeNext_move(CLICK_CD_MELEE)
return I.attack(src, user, params)
/mob/living/attackby_alt(obj/item/weapon, mob/living/user, params)
var/result = weapon.attack_alt(src, user, params)
// Normal attackby updates click cooldown, so we have to make up for it
if (result != ALT_ATTACK_CALL_NORMAL)
user.changeNext_move(CLICK_CD_MELEE)
return result
/**
* Called from [/mob/living/proc/attackby]
*
@@ -110,6 +158,9 @@
log_combat(user, M, "attacked", src.name, "(COMBAT MODE: [uppertext(user.combat_mode)]) (DAMTYPE: [uppertext(damtype)])")
add_fingerprint(user)
/// The equivalent of [/obj/item/proc/attack] but for alternate attacks, AKA right clicking
/obj/item/proc/attack_alt(mob/living/victim, mob/living/user, params)
return ALT_ATTACK_CALL_NORMAL
/// The equivalent of the standard version of [/obj/item/proc/attack] but for object targets.
/obj/item/proc/attack_obj(obj/O, mob/living/user)
@@ -165,6 +216,18 @@
SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK, target, user, proximity_flag, click_parameters)
SEND_SIGNAL(user, COMSIG_MOB_ITEM_AFTERATTACK, target, user, proximity_flag, click_parameters)
/**
* Called at the end of the attack chain if the user right-clicked.
*
* Arguments:
* * atom/target - The thing that was hit
* * mob/user - The mob doing the hitting
* * proximity_flag - is 1 if this afterattack was called on something adjacent, in your square, or on your person.
* * click_parameters - is the params string from byond [/atom/proc/Click] code, see that documentation.
*/
/obj/item/proc/afterattack_alt(atom/target, mob/user, proximity_flag, click_parameters)
return ALT_ATTACK_CALL_NORMAL
/// Called if the target gets deleted by our attack
/obj/item/proc/attack_qdeleted(atom/target, mob/user, proximity_flag, click_parameters)
SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_QDELETED, target, user, proximity_flag, click_parameters)
+7 -9
View File
@@ -193,15 +193,13 @@
for(var/obj/O in contents)
O.emp_act(severity)
/obj/item/gun/attack(mob/M, mob/living/user, params)
var/list/modifiers = params2list(params)
if(ismob(M) && modifiers && modifiers["right"]) //Right click to hold someone up
if(user.GetComponent(/datum/component/gunpoint))
to_chat(user, "<span class='warning'>You are already holding someone up!</span>")
return
user.AddComponent(/datum/component/gunpoint, M, src)
return TRUE
return ..()
/obj/item/gun/attack_alt(mob/living/victim, mob/living/user, params)
if (user.GetComponent(/datum/component/gunpoint))
to_chat(user, "<span class='warning'>You are already holding someone up!</span>")
return ALT_ATTACK_CANCEL_ATTACK_CHAIN
user.AddComponent(/datum/component/gunpoint, victim, src)
return ALT_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/gun/afterattack(atom/target, mob/living/user, flag, params)
. = ..()