mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-11 18:22:14 +00:00
## About The Pull Request This PR implements multiple new features: Foam darts now can stick to people as long as their cap isn't removed. Riot foam darts have a chance to jostle when you move with one stuck inside of you, dealing a bit of stamina damage from the weight stuck to your limbs. Syringe guns received a second "low power" mode, toggleable with in-hand right click. In this mode, syringes fired will embed into their target and slowly leak their reagents instead of instantly delivering them. Thankfully, they can be plucked out pretty quickly. You can also insert syringes into uncapped (screwdriver-ed) foam darts (similarly to pens) to achieve the same result, allowing you to get a bootleg low-efficiency syringe gun. Additionally, I fixed/cleaned up some embedding issues/code which I found while coding this. ## Why It's Good For The Game This allows players to explore new funny interactions between items and chems, as we don't have a reliable slow release mechanism aside from IV drips currently. And foam darts embedding it just (mostly) harmless fluff, if someone figures out a way to cause havoc with it then I'll be very proud of them (someone totally will). ## Changelog 🆑 add: Foam darts now stick to people when they have their cap on, riot foam darts also can passively deal a bit of stamina damage when you move with one. add: Syringes can be inserted into foam darts, making them embed and slowly leak their reagents into their victim. add: Syringe guns can be toggled (with right click) between high power and low power modes, former being their normal functionality and latter making syringes embed and slowly leak their contents. fix: Fixed projectiles sometimes not embedding when they should've code: Cleaned embedding code up /🆑
158 lines
7.5 KiB
Plaintext
158 lines
7.5 KiB
Plaintext
/**
|
|
* Component for allowing items to be inserted into foam darts.
|
|
* The parent can register signal handlers for `COMSIG_DART_INSERT_ADDED`,
|
|
* `COMSIG_DART_INSERT_REMOVED` to define custom behavior for when the item
|
|
* is added to/removed from a dart, and `COMSIG_DART_INSERT_GET_VAR_MODIFIERS`
|
|
* to define the modifications the item makes to the vars of the fired projectile.
|
|
*/
|
|
/datum/component/dart_insert
|
|
/// List for tracking the modifications this component has made to the vars of the containing projectile
|
|
var/list/var_modifiers
|
|
/// A reference to the ammo casing this component's parent was inserted into
|
|
var/obj/item/ammo_casing/holder_casing
|
|
/// A reference to the projectile this component's parent was inserted into
|
|
var/obj/projectile/holder_projectile
|
|
/// The icon file used for the overlay applied over the containing ammo casing
|
|
var/casing_overlay_icon
|
|
/// The icon state used for the overlay applied over the containing ammo casing
|
|
var/casing_overlay_icon_state
|
|
/// The icon file used for the overlay applied over the containing projectile
|
|
var/projectile_overlay_icon
|
|
/// The icon state used for the overlay applied over the containing projectile
|
|
var/projectile_overlay_icon_state
|
|
/// Optional callback to invoke when acquiring projectile var modifiers
|
|
var/datum/callback/modifier_getter
|
|
|
|
/datum/component/dart_insert/Initialize(_casing_overlay_icon, _casing_overlay_icon_state, _projectile_overlay_icon, _projectile_overlay_icon_state, datum/callback/_modifier_getter)
|
|
if(!isitem(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
casing_overlay_icon = _casing_overlay_icon
|
|
casing_overlay_icon_state = _casing_overlay_icon_state
|
|
projectile_overlay_icon = _projectile_overlay_icon
|
|
projectile_overlay_icon_state = _projectile_overlay_icon_state
|
|
modifier_getter = _modifier_getter
|
|
|
|
/datum/component/dart_insert/RegisterWithParent()
|
|
. = ..()
|
|
RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(on_preattack))
|
|
RegisterSignal(parent, COMSIG_OBJ_RESKIN, PROC_REF(on_reskin))
|
|
|
|
/datum/component/dart_insert/UnregisterFromParent()
|
|
. = ..()
|
|
var/obj/item/parent_item = parent
|
|
var/parent_loc = parent_item.loc
|
|
if(parent_loc && (parent_loc == holder_casing || parent_loc == holder_projectile))
|
|
parent_item.forceMove(get_turf(parent_item))
|
|
remove_from_dart(holder_casing, holder_projectile)
|
|
UnregisterSignal(parent, COMSIG_ITEM_PRE_ATTACK)
|
|
|
|
/datum/component/dart_insert/proc/on_preattack(datum/source, atom/target, mob/user, params)
|
|
SIGNAL_HANDLER
|
|
var/obj/item/ammo_casing/foam_dart/dart = target
|
|
if(!istype(dart))
|
|
return
|
|
if(!dart.modified)
|
|
to_chat(user, span_warning("The safety cap prevents you from inserting [parent] into [dart]."))
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
if(HAS_TRAIT(dart, TRAIT_DART_HAS_INSERT))
|
|
to_chat(user, span_warning("There's already something in [dart]."))
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
add_to_dart(dart, user)
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
/datum/component/dart_insert/proc/on_reskin(datum/source, mob/user, skin)
|
|
SIGNAL_HANDLER
|
|
SEND_SIGNAL(parent, COMSIG_DART_INSERT_PARENT_RESKINNED)
|
|
|
|
/datum/component/dart_insert/proc/add_to_dart(obj/item/ammo_casing/dart, mob/user)
|
|
var/obj/projectile/dart_projectile = dart.loaded_projectile
|
|
var/obj/item/parent_item = parent
|
|
if(user)
|
|
if(!user.transferItemToLoc(parent_item, dart_projectile))
|
|
return
|
|
to_chat(user, span_notice("You insert [parent_item] into [dart]."))
|
|
else
|
|
parent_item.forceMove(dart_projectile)
|
|
ADD_TRAIT(dart, TRAIT_DART_HAS_INSERT, REF(src))
|
|
RegisterSignal(dart, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_dart_attack_self))
|
|
RegisterSignal(dart, COMSIG_ATOM_EXAMINE_MORE, PROC_REF(on_dart_examine_more))
|
|
RegisterSignals(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED), PROC_REF(on_leave_dart))
|
|
RegisterSignal(dart, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_casing_update_overlays))
|
|
RegisterSignal(dart_projectile, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_projectile_update_overlays))
|
|
RegisterSignals(dart_projectile, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED), PROC_REF(on_spawn_drop))
|
|
apply_var_modifiers(dart_projectile)
|
|
dart.harmful = dart_projectile.damage > 0 || dart_projectile.wound_bonus > 0 || dart_projectile.bare_wound_bonus > 0
|
|
SEND_SIGNAL(parent, COMSIG_DART_INSERT_ADDED, dart)
|
|
dart.update_appearance()
|
|
dart_projectile.update_appearance()
|
|
holder_casing = dart
|
|
holder_projectile = dart_projectile
|
|
|
|
/datum/component/dart_insert/proc/remove_from_dart(obj/item/ammo_casing/dart, obj/projectile/projectile, mob/user)
|
|
holder_casing = null
|
|
holder_projectile = null
|
|
if(istype(dart))
|
|
UnregisterSignal(dart, list(COMSIG_ITEM_ATTACK_SELF, COMSIG_ATOM_EXAMINE_MORE, COMSIG_ATOM_UPDATE_OVERLAYS))
|
|
REMOVE_TRAIT(dart, TRAIT_DART_HAS_INSERT, REF(src))
|
|
dart.update_appearance()
|
|
if(istype(projectile))
|
|
remove_var_modifiers(projectile)
|
|
UnregisterSignal(projectile, list(COMSIG_PROJECTILE_ON_SPAWN_DROP, COMSIG_PROJECTILE_ON_SPAWN_EMBEDDED, COMSIG_ATOM_UPDATE_OVERLAYS))
|
|
if(dart?.loaded_projectile == projectile)
|
|
dart.harmful = projectile.damage > 0 || projectile.wound_bonus > 0 || projectile.bare_wound_bonus > 0
|
|
projectile.update_appearance()
|
|
SEND_SIGNAL(parent, COMSIG_DART_INSERT_REMOVED, dart, projectile, user)
|
|
UnregisterSignal(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED))
|
|
if(user)
|
|
INVOKE_ASYNC(user, TYPE_PROC_REF(/mob, put_in_hands), parent)
|
|
to_chat(user, span_notice("You remove [parent] from [dart]."))
|
|
|
|
/datum/component/dart_insert/proc/on_dart_attack_self(datum/source, mob/user)
|
|
SIGNAL_HANDLER
|
|
remove_from_dart(holder_casing, holder_projectile, user)
|
|
|
|
/datum/component/dart_insert/proc/on_dart_examine_more(datum/source, mob/user, list/examine_list)
|
|
var/obj/item/parent_item = parent
|
|
examine_list += span_notice("You can see a [parent_item.name] inserted into it.")
|
|
|
|
/datum/component/dart_insert/proc/on_leave_dart()
|
|
SIGNAL_HANDLER
|
|
remove_from_dart(holder_casing, holder_projectile)
|
|
|
|
/datum/component/dart_insert/proc/on_spawn_drop(datum/source, obj/item/ammo_casing/new_casing)
|
|
SIGNAL_HANDLER
|
|
UnregisterSignal(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED))
|
|
add_to_dart(new_casing)
|
|
|
|
/datum/component/dart_insert/proc/on_casing_update_overlays(datum/source, list/new_overlays)
|
|
SIGNAL_HANDLER
|
|
new_overlays += mutable_appearance(casing_overlay_icon, casing_overlay_icon_state)
|
|
|
|
/datum/component/dart_insert/proc/on_projectile_update_overlays(datum/source, list/new_overlays)
|
|
SIGNAL_HANDLER
|
|
new_overlays += mutable_appearance(projectile_overlay_icon, projectile_overlay_icon_state)
|
|
|
|
/datum/component/dart_insert/proc/apply_var_modifiers(obj/projectile/projectile)
|
|
if (!modifier_getter)
|
|
return
|
|
var_modifiers = modifier_getter.Invoke(projectile)
|
|
projectile.damage += var_modifiers["damage"]
|
|
projectile.speed += var_modifiers["speed"]
|
|
projectile.armour_penetration += var_modifiers["armour_penetration"]
|
|
projectile.wound_bonus += var_modifiers["wound_bonus"]
|
|
projectile.bare_wound_bonus += var_modifiers["bare_wound_bonus"]
|
|
projectile.demolition_mod += var_modifiers["demolition_mod"]
|
|
if(var_modifiers["embedding"])
|
|
projectile.set_embed(var_modifiers["embedding"])
|
|
|
|
/datum/component/dart_insert/proc/remove_var_modifiers(obj/projectile/projectile)
|
|
projectile.damage -= var_modifiers["damage"]
|
|
projectile.speed -= var_modifiers["speed"]
|
|
projectile.armour_penetration -= var_modifiers["armour_penetration"]
|
|
projectile.wound_bonus -= var_modifiers["wound_bonus"]
|
|
projectile.bare_wound_bonus -= var_modifiers["bare_wound_bonus"]
|
|
projectile.demolition_mod -= var_modifiers["demolition_mod"]
|
|
if(var_modifiers["embedding"])
|
|
projectile.set_embed(initial(projectile.embed_type))
|
|
var_modifiers.Cut()
|