Skip to content

Commit

Permalink
Item Strip changes (#4153)
Browse files Browse the repository at this point in the history
# About the pull request
Makes it so when stripping someone's items their skills are taken into
consideration. Each level of policing and CQC skills adds half a second
to the base delay. The skills are not taken into consideration if the
target is dead, unconscious or restrained.
Also adds an unstrippable trait, preventing items being forced onto or
removed from a mob. This also does not apply if dead, knocked out or
restrained.

<!-- Remove this text and explain what the purpose of your PR is.

Mention if you have tested your changes. If you changed a map, make sure
you used the mapmerge tool.
If this is an Issue Correction, you can type "Fixes Issue #169420" to
link the PR to the corresponding Issue number #169420.

Remember: something that is self-evident to you might not be to others.
Explain your rationale fully, even if you feel it goes without saying.
-->

# Explain why it's good for the game
It makes a bit more sense for people trained in policing or CQC to be
better at resisting having their equipment stolen.
# Testing Photographs and Procedure
<details>
<summary>Screenshots & Videos</summary>

Put screenshots and videos here with an empty line between the
screenshots and the `<details>` tags.

</details>

# Changelog
:cl:
add: Added a proc to calculate item strip delay, taking into account the
target's skills and adding 0.5s per level in Policing and CQC.
add: Added an unstrippable mob trait to prevent inventory manipulation.
Gave this trait to Working Joes.
/:cl:
  • Loading branch information
realforest2001 authored Aug 14, 2023
1 parent c8b16bd commit 8f97b15
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 54 deletions.
3 changes: 3 additions & 0 deletions code/__DEFINES/traits.dm
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@
#define TRAIT_INTENT_EYES "t_intent_eyes"
/// Masked synthetic biology. Basic medHUDs will percieve the mob as human. (Infiltrator Synths)
#define TRAIT_INFILTRATOR_SYNTH "t_infiltrator_synth"
/// Makes it impossible to strip the inventory of this mob.
#define TRAIT_UNSTRIPPABLE "t_unstrippable"

// HIVE TRAITS
/// If the Hive is a Xenonid Hive
Expand Down Expand Up @@ -251,6 +253,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_FOREIGN_BIO" = TRAIT_FOREIGN_BIO,
"TRAIT_INTENT_EYES" = TRAIT_INTENT_EYES,
"TRAIT_INFILTRATOR_SYNTH" = TRAIT_INFILTRATOR_SYNTH,
"TRAIT_UNSTRIPPABLE" = TRAIT_UNSTRIPPABLE,
"TRAIT_NESTED" = TRAIT_NESTED,
"TRAIT_CRAWLER" = TRAIT_CRAWLER,
"TRAIT_SIMPLE_DESC" = TRAIT_SIMPLE_DESC,
Expand Down
7 changes: 5 additions & 2 deletions code/modules/mob/living/carbon/human/human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -509,8 +509,11 @@
if(U == w_uniform)
U.remove_accessory(usr, A)
else
if(HAS_TRAIT(src, TRAIT_UNSTRIPPABLE) && !is_mob_incapacitated()) //Can't strip the unstrippable!
to_chat(usr, SPAN_DANGER("[src] has an unbreakable grip on their equipment!"))
return
visible_message(SPAN_DANGER("<B>[usr] is trying to take off \a [A] from [src]'s [U]!</B>"), null, null, 5)
if(do_after(usr, HUMAN_STRIP_DELAY, INTERRUPT_ALL, BUSY_ICON_GENERIC, src, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
if(do_after(usr, get_strip_delay(usr, src), INTERRUPT_ALL, BUSY_ICON_GENERIC, src, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
if(U == w_uniform)
U.remove_accessory(usr, A)

Expand All @@ -529,7 +532,7 @@
else
var/oldsens = U.has_sensor
visible_message(SPAN_DANGER("<B>[usr] is trying to modify [src]'s sensors!</B>"), null, null, 4)
if(do_after(usr, HUMAN_STRIP_DELAY, INTERRUPT_ALL, BUSY_ICON_GENERIC, src, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
if(do_after(usr, get_strip_delay(usr, src), INTERRUPT_ALL, BUSY_ICON_GENERIC, src, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
if(U == w_uniform)
if(U.has_sensor >= UNIFORM_FORCED_SENSORS)
to_chat(usr, "The controls are locked.")
Expand Down
121 changes: 70 additions & 51 deletions code/modules/mob/living/carbon/human/inventory.dm
Original file line number Diff line number Diff line change
Expand Up @@ -486,63 +486,82 @@
return WEAR_LEGCUFFS
return ..()



/mob/living/carbon/human/stripPanelUnequip(obj/item/I, mob/M, slot_to_process)
if(I.flags_item & ITEM_ABSTRACT)
/mob/living/carbon/human/proc/get_strip_delay(mob/living/carbon/human/user, mob/living/carbon/human/target)
/// Default delay
var/target_delay = HUMAN_STRIP_DELAY
/// Multiplier for how quickly the user can strip things.
var/user_speed = user.get_skill_duration_multiplier(SKILL_CQC)
/// The total skill level of CQC & Police
var/target_skills = (target.skills.get_skill_level(SKILL_CQC) + target.skills.get_skill_level(SKILL_POLICE))

/// Delay then gets + 0.5s per skill level, so long as not dead or cuffed.
if(!(target.stat || target.handcuffed))
target_delay += (target_skills * 5)

/// Final result is overall delay * speed multiplier
return target_delay * user_speed

/mob/living/carbon/human/stripPanelUnequip(obj/item/interact_item, mob/target_mob, slot_to_process)
if(HAS_TRAIT(target_mob, TRAIT_UNSTRIPPABLE) && !target_mob.is_mob_incapacitated()) //Can't strip the unstrippable!
to_chat(src, SPAN_DANGER("[target_mob] has an unbreakable grip on their equipment!"))
return
if(interact_item.flags_item & ITEM_ABSTRACT)
return
if(interact_item.flags_item & NODROP)
to_chat(src, SPAN_WARNING("You can't remove \the [interact_item.name], it appears to be stuck!"))
return
if(I.flags_item & NODROP)
to_chat(src, SPAN_WARNING("You can't remove \the [I.name], it appears to be stuck!"))
if(interact_item.flags_inventory & CANTSTRIP)
to_chat(src, SPAN_WARNING("You're having difficulty removing \the [interact_item.name]."))
return
if(I.flags_inventory & CANTSTRIP)
to_chat(src, SPAN_WARNING("You're having difficulty removing \the [I.name]."))
target_mob.attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their [interact_item.name] ([slot_to_process]) attempted to be removed by [key_name(src)]</font>"
attack_log += "\[[time_stamp()]\] <font color='red'>Attempted to remove [key_name(target_mob)]'s [interact_item.name] ([slot_to_process])</font>"
log_interact(src, target_mob, "[key_name(src)] tried to remove [key_name(target_mob)]'s [interact_item.name] ([slot_to_process]).")

src.visible_message(SPAN_DANGER("[src] tries to remove [target_mob]'s [interact_item.name]."), \
SPAN_DANGER("You are trying to remove [target_mob]'s [interact_item.name]."), null, 5)
interact_item.add_fingerprint(src)
if(do_after(src, get_strip_delay(src, target_mob), INTERRUPT_ALL, BUSY_ICON_GENERIC, target_mob, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
if(interact_item && Adjacent(target_mob) && interact_item == target_mob.get_item_by_slot(slot_to_process))
target_mob.drop_inv_item_on_ground(interact_item)
log_interact(src, target_mob, "[key_name(src)] removed [key_name(target_mob)]'s [interact_item.name] ([slot_to_process]) successfully.")

if(target_mob)
if(interactee == target_mob && Adjacent(target_mob))
target_mob.show_inv(src)


/mob/living/carbon/human/stripPanelEquip(obj/item/interact_item, mob/target_mob, slot_to_process)
if(HAS_TRAIT(target_mob, TRAIT_UNSTRIPPABLE) && !target_mob.is_mob_incapacitated())
to_chat(src, SPAN_DANGER("[target_mob] is too strong to force [interact_item.name] onto them!"))
return
M.attack_log += "\[[time_stamp()]\] <font color='orange'>Has had their [I.name] ([slot_to_process]) attempted to be removed by [key_name(src)]</font>"
attack_log += "\[[time_stamp()]\] <font color='red'>Attempted to remove [key_name(M)]'s [I.name] ([slot_to_process])</font>"
log_interact(src, M, "[key_name(src)] tried to remove [key_name(M)]'s [I.name] ([slot_to_process]).")

src.visible_message(SPAN_DANGER("[src] tries to remove [M]'s [I.name]."), \
SPAN_DANGER("You are trying to remove [M]'s [I.name]."), null, 5)
I.add_fingerprint(src)
if(do_after(src, HUMAN_STRIP_DELAY * src.get_skill_duration_multiplier(SKILL_CQC), INTERRUPT_ALL, BUSY_ICON_GENERIC, M, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
if(I && Adjacent(M) && I == M.get_item_by_slot(slot_to_process))
M.drop_inv_item_on_ground(I)
log_interact(src, M, "[key_name(src)] removed [key_name(M)]'s [I.name] ([slot_to_process]) successfully.")

if(M)
if(interactee == M && Adjacent(M))
M.show_inv(src)


/mob/living/carbon/human/stripPanelEquip(obj/item/I, mob/M, slot_to_process)
if(I && !(I.flags_item & ITEM_ABSTRACT))
if(I.flags_item & NODROP)
to_chat(src, SPAN_WARNING("You can't put \the [I.name] on [M], it's stuck to your hand!"))
if(interact_item && !(interact_item.flags_item & ITEM_ABSTRACT))
if(interact_item.flags_item & NODROP)
to_chat(src, SPAN_WARNING("You can't put \the [interact_item.name] on [target_mob], it's stuck to your hand!"))
return
if(I.flags_inventory & CANTSTRIP)
to_chat(src, SPAN_WARNING("You're having difficulty putting \the [I.name] on [M]."))
if(interact_item.flags_inventory & CANTSTRIP)
to_chat(src, SPAN_WARNING("You're having difficulty putting \the [interact_item.name] on [target_mob]."))
return
if(I.flags_item & WIELDED)
I.unwield(src)
if(!I.mob_can_equip(M, slot_to_process, TRUE))
to_chat(src, SPAN_WARNING("You can't put \the [I.name] on [M]!"))
if(interact_item.flags_item & WIELDED)
interact_item.unwield(src)
if(!interact_item.mob_can_equip(target_mob, slot_to_process, TRUE))
to_chat(src, SPAN_WARNING("You can't put \the [interact_item.name] on [target_mob]!"))
return
visible_message(SPAN_NOTICE("[src] tries to put \the [I.name] on [M]."), null, null, 5)
if(do_after(src, HUMAN_STRIP_DELAY * src.get_skill_duration_multiplier(SKILL_CQC), INTERRUPT_ALL, BUSY_ICON_GENERIC, M, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
if(I == get_active_hand() && !M.get_item_by_slot(slot_to_process) && Adjacent(M))
if(I.flags_item & WIELDED) //to prevent re-wielding it during the do_after
I.unwield(src)
if(I.mob_can_equip(M, slot_to_process, TRUE))//Placing an item on the mob
drop_inv_item_on_ground(I)
if(I && !QDELETED(I)) //Might be self-deleted?
M.equip_to_slot_if_possible(I, slot_to_process, 1, 0, 1, 1)
if(ishuman(M) && M.stat == DEAD)
var/mob/living/carbon/human/H = M
H.disable_lights() // take that powergamers -spookydonut

if(M)
if(interactee == M && Adjacent(M))
M.show_inv(src)
visible_message(SPAN_NOTICE("[src] tries to put \the [interact_item.name] on [target_mob]."), null, null, 5)
if(do_after(src, get_strip_delay(src, target_mob), INTERRUPT_ALL, BUSY_ICON_GENERIC, target_mob, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
if(interact_item == get_active_hand() && !target_mob.get_item_by_slot(slot_to_process) && Adjacent(target_mob))
if(interact_item.flags_item & WIELDED) //to prevent re-wielding it during the do_after
interact_item.unwield(src)
if(interact_item.mob_can_equip(target_mob, slot_to_process, TRUE))//Placing an item on the mob
drop_inv_item_on_ground(interact_item)
if(interact_item && !QDELETED(interact_item)) //Might be self-deleted?
target_mob.equip_to_slot_if_possible(interact_item, slot_to_process, 1, 0, 1, 1)
if(ishuman(target_mob) && target_mob.stat == DEAD)
var/mob/living/carbon/human/human_target = target_mob
human_target.disable_lights() // take that powergamers -spookydonut

if(target_mob)
if(interactee == target_mob && Adjacent(target_mob))
target_mob.show_inv(src)

/mob/living/carbon/human/drop_inv_item_on_ground(obj/item/I, nomoveupdate, force)
remember_dropped_object(I)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
death_message = "violently gargles fluid and seizes up, the glow in their eyes dimming..."
uses_ethnicity = FALSE
burn_mod = 0.65 // made for hazardous environments, withstanding temperatures up to 1210 degrees
mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_EMOTE_CD_EXEMPT, TRAIT_CANNOT_EAT)
mob_inherent_traits = list(TRAIT_SUPER_STRONG, TRAIT_INTENT_EYES, TRAIT_EMOTE_CD_EXEMPT, TRAIT_CANNOT_EAT, TRAIT_UNSTRIPPABLE)

slowdown = 0.45
hair_color = "#000000"
Expand Down

0 comments on commit 8f97b15

Please sign in to comment.