Fixes xenos being able to pick up items that they shouldn't by most means, expands itempicky component functionality (#86714)

## About The Pull Request

Xenos can apparently use shenanigans such as
https://github.com/tgstation/tgstation/issues/86703 to put some items in
their hand, and there are likely methods like this dotted around the
codebase. However, the signal to put something in their hand is called
consistently across any process that would cause them to pick up or
otherwise have something to put in their hand, so instead I added
/datum/component/itempicky to xenos.

While I was in there, I expanded the functionality of itempicky; it can
run a callback to determine a condition that needs to be met now.

## Why It's Good For The Game

Fixes https://github.com/tgstation/tgstation/issues/86703
Expands a component's usefulness
## Changelog
🆑 Bisar
fix: Xenomorph restrictions on items they can pick up have had their
determining logic made more _robust_.
code: The itempicky component (restricts what can be picked up via a
whitelist) can now, optionally, have a callback fed to it to determine
cases of bypassing that whitelist.
/🆑

---------

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
This commit is contained in:
Joshua Kidder
2024-09-18 17:38:07 -04:00
committed by GitHub
parent 9af9189615
commit 240e397b95
8 changed files with 26 additions and 11 deletions

View File

@@ -5,13 +5,21 @@
var/whitelist var/whitelist
/// Message shown if you try to pick up an item not in the whitelist /// Message shown if you try to pick up an item not in the whitelist
var/message = "You don't like %TARGET, why would you hold it?" var/message = "You don't like %TARGET, why would you hold it?"
/// An optional callback we check for overriding our whitelist
var/datum/callback/tertiary_condition = null
/datum/component/itempicky/Initialize(whitelist, message) /datum/component/itempicky/Initialize(whitelist, message, tertiary_condition)
if(!ismob(parent)) if(!ismob(parent))
return COMPONENT_INCOMPATIBLE return COMPONENT_INCOMPATIBLE
src.whitelist = whitelist src.whitelist = whitelist
if(message) if(message)
src.message = message src.message = message
if(tertiary_condition)
src.tertiary_condition = tertiary_condition
/datum/component/itempicky/Destroy(force)
tertiary_condition = null
return ..()
/datum/component/itempicky/RegisterWithParent() /datum/component/itempicky/RegisterWithParent()
RegisterSignal(parent, COMSIG_LIVING_TRY_PUT_IN_HAND, PROC_REF(particularly)) RegisterSignal(parent, COMSIG_LIVING_TRY_PUT_IN_HAND, PROC_REF(particularly))
@@ -30,6 +38,7 @@
/datum/component/itempicky/proc/particularly(datum/source, obj/item/pickingup) /datum/component/itempicky/proc/particularly(datum/source, obj/item/pickingup)
SIGNAL_HANDLER SIGNAL_HANDLER
if(!is_type_in_typecache(pickingup, whitelist)) // if we were passed the output of a callback, check against that
if(!tertiary_condition?.Invoke() && !is_type_in_typecache(pickingup, whitelist))
to_chat(source, span_warning("[replacetext(message, "%TARGET", pickingup)]")) to_chat(source, span_warning("[replacetext(message, "%TARGET", pickingup)]"))
return COMPONENT_LIVING_CANT_PUT_IN_HAND return COMPONENT_LIVING_CANT_PUT_IN_HAND

View File

@@ -633,7 +633,7 @@
/obj/item/attack_alien(mob/user, list/modifiers) /obj/item/attack_alien(mob/user, list/modifiers)
var/mob/living/carbon/alien/ayy = user var/mob/living/carbon/alien/ayy = user
if(!user.can_hold_items(src)) if(!ayy.can_hold_items(src))
if(src in ayy.contents) // To stop Aliens having items stuck in their pockets if(src in ayy.contents) // To stop Aliens having items stuck in their pockets
ayy.dropItemToGround(src) ayy.dropItemToGround(src)
to_chat(user, span_warning("Your claws aren't capable of such fine manipulation!")) to_chat(user, span_warning("Your claws aren't capable of such fine manipulation!"))

View File

@@ -25,7 +25,7 @@
throw_range = 3 throw_range = 3
pressure_resistance = 0 pressure_resistance = 0
item_flags = NOBLUDGEON | XENOMORPH_HOLDABLE //funny ~Jimmyl item_flags = NOBLUDGEON
w_class = WEIGHT_CLASS_TINY w_class = WEIGHT_CLASS_TINY
/// `list` or `null`, contains possible alternate `icon_states`. /// `list` or `null`, contains possible alternate `icon_states`.

View File

@@ -1134,7 +1134,6 @@
name = "xenomorph action figure" name = "xenomorph action figure"
desc = "MEGA presents the new Xenos Isolated action figure! Comes complete with realistic sounds! Pull back string to use." desc = "MEGA presents the new Xenos Isolated action figure! Comes complete with realistic sounds! Pull back string to use."
w_class = WEIGHT_CLASS_SMALL w_class = WEIGHT_CLASS_SMALL
item_flags = XENOMORPH_HOLDABLE
var/cooldown = 0 var/cooldown = 0
/obj/item/toy/toy_xeno/attack_self(mob/user) /obj/item/toy/toy_xeno/attack_self(mob/user)

View File

@@ -8,7 +8,6 @@
inhand_icon_state = "basketball" inhand_icon_state = "basketball"
desc = "Here's your chance, do your dance at the Space Jam." desc = "Here's your chance, do your dance at the Space Jam."
w_class = WEIGHT_CLASS_BULKY //Stops people from hiding it in their bags/pockets w_class = WEIGHT_CLASS_BULKY //Stops people from hiding it in their bags/pockets
item_flags = XENOMORPH_HOLDABLE // playing ball against a xeno is rigged since they cannot be disarmed
/// The person dribbling the basketball /// The person dribbling the basketball
var/mob/living/wielder var/mob/living/wielder
/// So the basketball doesn't make sound every step /// So the basketball doesn't make sound every step

View File

@@ -23,6 +23,13 @@
unique_name = TRUE unique_name = TRUE
var/static/regex/alien_name_regex = new("alien (larva|sentinel|drone|hunter|praetorian|queen)( \\(\\d+\\))?") var/static/regex/alien_name_regex = new("alien (larva|sentinel|drone|hunter|praetorian|queen)( \\(\\d+\\))?")
var/static/list/xeno_allowed_items = typecacheof(list(
/obj/item/clothing/mask/facehugger,
/obj/item/toy/basketball, // playing ball against a xeno is rigged since they cannot be disarmed, their game is out of this world
/obj/item/toy/toy_xeno,
/obj/item/sticker, //funny ~Jimmyl
/obj/item/toy/plush/rouny,
))
/mob/living/carbon/alien/Initialize(mapload) /mob/living/carbon/alien/Initialize(mapload)
add_verb(src, /mob/living/proc/mob_sleep) add_verb(src, /mob/living/proc/mob_sleep)
@@ -37,6 +44,11 @@
. = ..() . = ..()
if(alien_speed) if(alien_speed)
update_alien_speed() update_alien_speed()
LoadComponent( \
/datum/component/itempicky, \
xeno_allowed_items, \
span_alien("Your claws lack the dexterity to hold %TARGET."), \
CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_has_trait), src, TRAIT_ADVANCEDTOOLUSER))
/mob/living/carbon/alien/create_internal_organs() /mob/living/carbon/alien/create_internal_organs()
organs += new /obj/item/organ/internal/brain/alien organs += new /obj/item/organ/internal/brain/alien
@@ -154,9 +166,6 @@ Des: Removes all infected images from the alien.
set_name() set_name()
/mob/living/carbon/alien/can_hold_items(obj/item/I)
return (I && (I.item_flags & XENOMORPH_HOLDABLE || ISADVANCEDTOOLUSER(src)) && ..())
/mob/living/carbon/alien/on_lying_down(new_lying_angle) /mob/living/carbon/alien/on_lying_down(new_lying_angle)
. = ..() . = ..()
update_icons() update_icons()

View File

@@ -23,7 +23,6 @@
flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH flags_cover = MASKCOVERSEYES | MASKCOVERSMOUTH
layer = MOB_LAYER layer = MOB_LAYER
max_integrity = 100 max_integrity = 100
item_flags = XENOMORPH_HOLDABLE
slowdown = 2 slowdown = 2
var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case

View File

@@ -181,7 +181,7 @@
/obj/item/modular_computer/pda/proc/remove_pen(mob/user) /obj/item/modular_computer/pda/proc/remove_pen(mob/user)
if(issilicon(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) //TK doesn't work even with this removed but here for readability if(issilicon(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH | NEED_DEXTERITY)) //TK doesn't work even with this removed but here for readability
return return
if(inserted_item) if(inserted_item)