Files
Bubberstation/code/datums/components/combo_attacks.dm
Ghom 11d82b7995 You can now interact with held mobs beside wearing them (feat: "minor" melee attack chain cleanup) (#90080)
People can now pet held mothroaches and pugs if they want to, or use
items on them, hopefully without causing many issues. After all, it only
took about a couple dozen lines of code to make...

...Oh, did the 527 files changed or the 850~ lines added/removed perhaps
catch your eye? Made you wonder if I accidentally pushed the wrong
branch? or skewed something up big time? Well, nuh uh. I just happen to
be fed up with the melee attack chain still using stringized params
instead of an array/list. It was frankly revolting to see how I'd have
had to otherwise call `list2params` for what I'm trying to accomplish
here, and make this PR another tessera to the immense stupidity of our
attack chain procs calling `params2list` over and over and over instead
of just using that one call instance from `ClickOn` as an argument. It's
2025, honey, wake up!

I also tried to replace some of those single letter vars/args but there
are just way too many of them.

Improving old code. And I want to be able to pet mobroaches while
holding them too.

🆑
qol: You can now interact with held mobs in more ways beside wearing
them.
/🆑
2025-04-29 18:22:44 -06:00

106 lines
3.9 KiB
Plaintext

/datum/component/combo_attacks
/// Length of combo we allow before resetting.
var/max_combo_length
/// Message when the item is examined.
var/examine_message
/// Balloon alert message when the combo is reset.
var/reset_message
/// ID for the reset combo timer.
var/timerid
/// How much time before the combo resets.
var/leniency_time
/// List of inputs done by user.
var/list/input_list = list()
/// Associative list of all the combo moves. Name of Attack = list(COMBO_STEPS = list(Steps made of LEFT_ATTACK and RIGHT_ATTACK), COMBO_PROC = PROC_REF(Proc Name))
var/list/combo_list = list()
/// A list of strings containing the ways to do combos, for examines.
var/list/combo_strings = list()
/// A callback to the proc that checks whether or not we can do combo attacks.
var/datum/callback/can_attack_callback
/datum/component/combo_attacks/Initialize(combos, examine_message, reset_message, max_combo_length, leniency_time = 5 SECONDS, can_attack_callback)
if(!isitem(parent))
return COMPONENT_INCOMPATIBLE
combo_list = combos
for(var/combo in combo_list)
var/list/combo_specifics = combo_list[combo]
var/step_string = english_list(combo_specifics[COMBO_STEPS])
combo_strings += span_notice("<b>[combo]</b> - [step_string]")
src.examine_message = examine_message
src.reset_message = reset_message
src.max_combo_length = max_combo_length
src.leniency_time = leniency_time
src.can_attack_callback = can_attack_callback
/datum/component/combo_attacks/Destroy(force)
can_attack_callback = null
return ..()
/datum/component/combo_attacks/RegisterWithParent()
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignal(parent, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_examine_more))
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_attack_self))
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(on_attack))
/datum/component/combo_attacks/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE, COMSIG_ATOM_EXAMINE_MORE, COMSIG_ITEM_ATTACK_SELF, COMSIG_ITEM_DROPPED, COMSIG_ITEM_ATTACK))
/datum/component/combo_attacks/proc/on_examine(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
if(!examine_message)
return
examine_list += examine_message
/datum/component/combo_attacks/proc/on_examine_more(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
examine_list += combo_strings
/datum/component/combo_attacks/proc/on_attack_self(obj/item/source, mob/user)
SIGNAL_HANDLER
reset_inputs(user, deltimer = TRUE)
/datum/component/combo_attacks/proc/on_drop(datum/source, mob/dropper)
SIGNAL_HANDLER
reset_inputs(user = null, deltimer = TRUE)
/datum/component/combo_attacks/proc/check_input(mob/living/target, mob/user)
for(var/combo in combo_list)
var/list/combo_specifics = combo_list[combo]
if(compare_list(input_list, combo_specifics[COMBO_STEPS]))
INVOKE_ASYNC(parent, combo_specifics[COMBO_PROC], target, user)
return TRUE
return FALSE
/datum/component/combo_attacks/proc/reset_inputs(mob/user, deltimer)
var/atom/atom_parent = parent
input_list.Cut()
if(user)
atom_parent.balloon_alert(user, reset_message)
if(deltimer && timerid)
deltimer(timerid)
/datum/component/combo_attacks/proc/on_attack(datum/source, mob/living/target, mob/user, list/modifiers)
SIGNAL_HANDLER
if(can_attack_callback && !can_attack_callback.Invoke(user, target))
return NONE
if(HAS_TRAIT(user, TRAIT_PACIFISM))
return NONE
if(LAZYACCESS(modifiers, RIGHT_CLICK))
input_list += RIGHT_ATTACK
if(LAZYACCESS(modifiers, LEFT_CLICK))
input_list += LEFT_ATTACK
if(length(input_list) > max_combo_length)
reset_inputs(user, deltimer = TRUE)
if(check_input(target, user))
reset_inputs(user = null, deltimer = TRUE)
return COMPONENT_SKIP_ATTACK
if(leniency_time)
timerid = addtimer(CALLBACK(src, PROC_REF(reset_inputs), user, FALSE), leniency_time, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE)
return NONE