-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MIRROR] Different pen types have unique behavior when used in foam d…
…arts. [MDB IGNORE] (#25183) (#773) * Different pen types have unique behavior when used in foam darts. (#79587) ## About The Pull Request This PR makes the following changes: - Refactors inserting items into foam darts into a component on items that can be inserted into darts - Adds the aforementioned component to pens - Provides an inspection tip for how to modify a foam dart - Gives different pen types specific behavior when used in a foam dart Pens typically give a foam dart 5 brute and 50% embed chance (affected by falloff). The following types of pens give the specified properties (usually directly derived from the pen's stats and additional functions): - Red pen (and four-color pen set to red): Slightly faster dart - Captain's fountain pen: Slightly faster dart, and 75% base embed chance - Sleepypen: Tries to inject its reagents into the hit mob, but doesn't penetrate thick clothing like syringe guns do - Energy Dagger: 35 brute, 100% base embed chance, and slightly faster dart - Survival Pen: Mines rocks on impact - Fine Tip Pen (if someone somehow manages to get one): 100 bare wound bonus and 9000 demolition modifier ## Why It's Good For The Game Expands the emergent gameplay possibilities of using pens in foam darts. While there are balance risks involved with traitors being able to buy the equivalent of reusable 45u syringe shots and 35 brute bullets, you are not likely to get your pen back once it hits its target, unless you somehow have the recall spell and have bound the pen to it. There are probably more TC-efficient ways to achieve comparable projectile weaponry, but foam dart guns have an air of subtlety to them... at least until your skin is pierced by a pointy writing implement that may also be something more deadly. If maintainers still have balance concerns, please let me know. ## Changelog :cl: add: Certain types of pens now function like you expect they would when inserted into a foam dart qol: Examining a foam dart closely will show you how to modify it, or what it is modified with /:cl: * Different pen types have unique behavior when used in foam darts. --------- Co-authored-by: SkyratBot <[email protected]> Co-authored-by: Y0SH1M4S73R <[email protected]>
- Loading branch information
1 parent
fbdd283
commit 365bf82
Showing
19 changed files
with
403 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/** | ||
* 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 | ||
|
||
/datum/component/dart_insert/Initialize(_casing_overlay_icon, _casing_overlay_icon_state, _projectile_overlay_icon, _projectile_overlay_icon_state) | ||
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 | ||
|
||
/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) | ||
LAZYINITLIST(var_modifiers) | ||
SEND_SIGNAL(parent, COMSIG_DART_INSERT_GET_VAR_MODIFIERS, var_modifiers) | ||
projectile.damage += var_modifiers["damage"] | ||
if(var_modifiers["speed"]) | ||
var_modifiers["speed"] = reciprocal_add(projectile.speed, var_modifiers["speed"]) - projectile.speed | ||
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(islist(var_modifiers["embedding"])) | ||
var/list/embed_params = var_modifiers["embedding"] | ||
for(var/embed_param in embed_params - "ignore_throwspeed_threshold") | ||
LAZYADDASSOC(projectile.embedding, embed_param, embed_params[embed_param]) | ||
projectile.updateEmbedding() | ||
|
||
/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(islist(var_modifiers["embedding"])) | ||
var/list/embed_params = var_modifiers["embedding"] | ||
for(var/embed_param in embed_params - "ignore_throwspeed_threshold") | ||
LAZYADDASSOC(projectile.embedding, embed_param, -embed_params[embed_param]) | ||
projectile.updateEmbedding() | ||
var_modifiers.Cut() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.