Files
Bubberstation/code/datums/components/combo_attacks.dm
Ghom 339616ae78 You can now interact with held mobs beside wearing them (feat: "minor" melee attack chain cleanup) (#90080)
## About The Pull Request
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.

## Why It's Good For The Game
Improving old code. And I want to be able to pet mobroaches while
holding them too.

## Changelog

🆑
qol: You can now interact with held mobs in more ways beside wearing
them.
/🆑
2025-04-23 20:18:26 +00: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