Files
Bubberstation/code/datums/components/ranged_attacks.dm
DATA e4682c04a4 Adds a new smite: Retcon, also refactors the temporary_atom component into an atom level proc (#90016)
## About The Pull Request

Adds a new Retcon smite, it makes the person fade out into nothingness
with a configurable timer, deletes their records and reopens their job
slot, as if they were never there at all.

I was also annoyed that to play around with temporary_atom I had to
slowy add a component, and it doesn't really have much of a reason to BE
a component, so I refactored it into an atom level proc called
fade_into_nothing

## Why It's Good For The Game

The smite is useful for when you wanna get rid of someone who had to
leave roundstart and whatnot, on top of just being funny. the refactor
is also good because i can now put that proc on build mode and go to
town.

## Changelog

🆑
add: Added new mechanics or gameplay changes
add: Added more things
del: Removed old things
qol: made something easier to use
balance: rebalanced something
fix: fixed a few things
sound: added/modified/removed audio or sound effects
image: added/modified/removed some icons or images
map: added/modified/removed map content
spellcheck: fixed a few typos
code: changed some code
refactor: refactored some code
config: changed some config setting
admin: messed with admin stuff
server: something server ops should know
/🆑

---------

Co-authored-by: Jacquerel <hnevard@gmail.com>
2025-03-12 22:26:06 -04:00

96 lines
3.5 KiB
Plaintext

/**
* Configurable ranged attack for basic mobs.
*/
/datum/component/ranged_attacks
/// What kind of casing do we use to fire?
var/casing_type
/// What kind of projectile to we fire? Use only one of this or casing_type
var/projectile_type
/// Sound to play when we fire our projectile
var/projectile_sound
/// how many shots we will fire
var/burst_shots
/// intervals between shots
var/burst_intervals
/// Time to wait between shots
var/cooldown_time
/// Tracks time between shots
COOLDOWN_DECLARE(fire_cooldown)
/datum/component/ranged_attacks/Initialize(
casing_type,
projectile_type,
projectile_sound = 'sound/items/weapons/gun/pistol/shot.ogg',
burst_shots,
burst_intervals = 0.2 SECONDS,
cooldown_time = 3 SECONDS,
)
. = ..()
if(!isbasicmob(parent))
return COMPONENT_INCOMPATIBLE
src.casing_type = casing_type
src.projectile_sound = projectile_sound
src.projectile_type = projectile_type
src.cooldown_time = cooldown_time
if (casing_type && projectile_type)
CRASH("Set both casing type and projectile type in [parent]'s ranged attacks component! uhoh! stinky!")
if (!casing_type && !projectile_type)
CRASH("Set neither casing type nor projectile type in [parent]'s ranged attacks component! What are they supposed to be attacking with, air?")
if(burst_shots <= 1)
return
src.burst_shots = burst_shots
src.burst_intervals = burst_intervals
/datum/component/ranged_attacks/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_MOB_ATTACK_RANGED, PROC_REF(fire_ranged_attack))
ADD_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type)
RegisterSignal(parent, COMSIG_MOB_TROPHY_ACTIVATED(TROPHY_WATCHER), PROC_REF(disable_attack))
/datum/component/ranged_attacks/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, COMSIG_MOB_ATTACK_RANGED)
REMOVE_TRAIT(parent, TRAIT_SUBTREE_REQUIRED_OPERATIONAL_DATUM, type)
/datum/component/ranged_attacks/proc/fire_ranged_attack(mob/living/basic/firer, atom/target, modifiers)
SIGNAL_HANDLER
if(!COOLDOWN_FINISHED(src, fire_cooldown))
return
if(SEND_SIGNAL(firer, COMSIG_BASICMOB_PRE_ATTACK_RANGED, target, modifiers) & COMPONENT_CANCEL_RANGED_ATTACK)
return
COOLDOWN_START(src, fire_cooldown, cooldown_time)
INVOKE_ASYNC(src, PROC_REF(async_fire_ranged_attack), firer, target, modifiers)
if(isnull(burst_shots))
return
for(var/i in 1 to (burst_shots - 1))
addtimer(CALLBACK(src, PROC_REF(async_fire_ranged_attack), firer, target, modifiers), i * burst_intervals)
/// Actually fire the damn thing
/datum/component/ranged_attacks/proc/async_fire_ranged_attack(mob/living/basic/firer, atom/target, modifiers)
firer.face_atom(target)
if(projectile_type)
firer.fire_projectile(projectile_type, target, projectile_sound)
SEND_SIGNAL(parent, COMSIG_BASICMOB_POST_ATTACK_RANGED, target, modifiers)
return
playsound(firer, projectile_sound, 100, TRUE)
var/turf/startloc = get_turf(firer)
var/obj/item/ammo_casing/casing = new casing_type(startloc)
var/target_zone
if(ismob(target))
var/mob/target_mob = target
target_zone = target_mob.get_random_valid_zone()
else
target_zone = ran_zone()
casing.fire_casing(target, firer, null, null, null, target_zone, 0, firer)
casing.update_appearance()
casing.fade_into_nothing(30 SECONDS)
SEND_SIGNAL(parent, COMSIG_BASICMOB_POST_ATTACK_RANGED, target, modifiers)
return
/datum/component/ranged_attacks/proc/disable_attack(obj/item/crusher_trophy/used_trophy, mob/living/user)
SIGNAL_HANDLER
var/stun_duration = (used_trophy.bonus_value * 0.1) SECONDS
COOLDOWN_INCREMENT(src, fire_cooldown, stun_duration)