Ball Mittens: Expanded and Enhanced (#5664)

<img width="830" height="45" alt="image"
src="https://github.com/user-attachments/assets/dc76c74d-7a97-4cd7-ab91-df8ffefa392e"
/>

## About The Pull Request

**YOU!** [Have you ever wanted to be a strange, round, rubbery little
creature with absolutely no fine motor control? No? Well you should have
thought of that before you went to sleep somewhere which gave me the
AMPLE opportunity to slide my EXTRAORDINARY new creation right onto your
FORMER HANDS!](https://www.youtube.com/watch?v=OjdgFSoQ00w)

Introducing Ball Mittens and Latex Paw Mittens: inflatable latex gloves
that, once on, become your hands for the foreseeable future! Big
shoutout to **Onule** for the sprites!

Ball Mittens are now a new equip-able lewd item available in the loadout
(Toys > Lewd Toys) or found in the Lustwish vendor.

They can be reskinned mid-round into Latex Paw Mittens, which are ALSO
available directly as an _incredible_ loadout item in the Gloves tab
with full GAGS color customization across three extraordinary color
groups! All for only four easy payments of no money at all!

While wearing either variant, the wearer experiences a suite of
DELIGHTFUL fumble mechanics representing a meteoric rise above the old
versions which just meant you could do basically nothing!

Here's what they do:
- Item pickup requires getting down on your knees and wrestling with the
item for a variable delay, with a small chance of you struggling even
longer because of how hard it is.
- Inventory retrieval from pockets, ID slot, belt, suit storage, and
_many more_ has a brief delay to represent fishing it out of your
pockets with your clumsy mitts! NOTE: This functionality is limited by
core aspects of the game engine, certain items are not subject to this
delay such as any item which is a container including but not limited to
toolbelts, backpacks and more. I tried but eventually gave up.
- Clothing has an extended timer. Have you ever tried unbuttoning a
jacket with paws the size of your face?
- Machine and console interaction requires a 1.5-second delay (skipped
when in combat mode, where you are presumably STRIKING DOWN the EVIL
machine)!
- Self-removal takes a full minute via the resist key or clicking the
item in the HUD. I was thinking of just making it impossible to remove
them on your own outright, but I changed my mind, aren't I swell?
- Throwing has a 5% chance of the item simply tumbling to the floor
instead. I thought about monekying with strength or like half a dozen
other things which I scrapped in the prototype phase when I realized how
_VIOLENTLY ANNOYING_ they would get over time!
- Guns suffer a serious spread penalty! It's hard to use guns when your
beans won't even fit inside the trigger guard!
- Restraint escape time is tripled! How the hell do you escape handcuffs
with your bare hands, let alone paws?!
- Stripping other players is much harder, I think it speaks for itself,
you're a cat, have you ever seen a cat steal your shoes? Absurd!
- The items are fire-proof because they're supposed to play into the
fantasy of having paws so it'd be lame if they could be trivially burned
off you and you can also use insulated gloves on them to witness the
absolute peak of comedy in the form of a funny easter egg!
- Surgery on the wearer is not blocked in order to play into the fantasy
that you actually have paws, wow! The mittens are considered transparent
to surgical operations! This means you don't have to have your hands
ripped off to get arm surgery! This was **obscenely** challenging to
implement! This and the ability to add insulation are very small
concessions to make it not pure agony to play with these on as say, an
engineer. They are heavily outweighed by the downsides.
- Another player can strip them off normally. The OOC safeword removes
them instantly if you decide the fun really has to end! Remember that
this function exists boys and girls!
- The items make appropriate rubber squeaking sounds, play flavor
messages for the wearer, and have visible bystander messages so the
whole crew can enjoy the endless novelty afforded by your predicament.


Also since this changes the appearance of the Cat Gloves, I've decided
to just go ahead and add the light QOL functions to these too, they
don't provide any gameplay advantage whatsoever. Arguably they make your
life harder.

## Why It's Good For The Game

You have been granted a GIFT. A BLESSING. An entirely voluntary and
opt-in set of squishy latex paws that make everything slightly harder in
ways that are charming rather than punishing.
More seriously: this adds a significant level of functionality to an
item which is otherwise a dead end
It also adds SKINS which you can sell on the Steam Market for PENNIES ON
THE DOLLAR!†

What's more, many manhours have been expended testing these to get the
balance just right!

†Disclaimer, you cannot actually sell the skins 

Also I have already gotten approval from maintainers so I'm just writing
this for fun.

## Proof Of Testing

There are 30 to 50 copies of Tgstation.dmb in my recycle bin because I
meticulously compiled and tested every feature with every change to this
code that I made because I am **NOT GUILTY BY REASON OF INSANITY!** And
also I don't know how to use VSC. I think that's adequate and I don't
want to download OBS again. Oh and there are like a bajillion commits of
my dumb ass trying to fix this.

<img width="425" height="414" alt="image"
src="https://github.com/user-attachments/assets/806f4c6d-81ee-4143-be1c-91db94b6efdf"
/>
<img width="1626" height="832" alt="image"
src="https://github.com/user-attachments/assets/327581d2-e593-443a-8cde-053b7d0de80a"
/>
<img width="496" height="1177" alt="image"
src="https://github.com/user-attachments/assets/12fc408b-b2d1-43e5-b220-f207cac8ef1d"
/>



</details>

## Changelog
🆑
add: Added vast amounts of functionality to Ball Mittens, inflatable
latex gloves with fumble mechanics for item pickup, inventory retrieval,
clothing removal, machine interaction, and more !
add: Added Latex Paw Mittens, a GAGS-colorable paw-form variant
available in the Gloves loadout tab with full three-color customization!
image: Added GAGS sprite layers for Latex Paw Mittens
/🆑
This commit is contained in:
Aeri
2026-06-14 10:21:23 -04:00
committed by GitHub
parent a60076115e
commit 4f36062120
23 changed files with 761 additions and 50 deletions
@@ -78,3 +78,20 @@
/area/centcom/holding/cafe/ruin/xenonest,\
/area/centcom/holding/cafe/beach,\
)
/// Applied to a mob wearing gloves that should be passable for hand surgery (e.g. ball mittens).
#define TRAIT_GLOVE_SURGERY_PASSTHROUGH "glove_surgery_passthrough"
/// Trait source for ball_mittens_fumble component.
#define MITTENS_FUMBLE_TRAIT "ball_mittens_fumble"
/// Fired on a mob in attempt_pickup after mobility checks. Handler can set pickup_mods["delay"] or return COMPONENT_BLOCK_ITEM_PICKUP.
#define COMSIG_LIVING_ITEM_ATTEMPT_PICKUP "living_item_attempt_pickup"
#define COMPONENT_BLOCK_ITEM_PICKUP (1<<0)
/// Fired on a mob when they interact with machinery, before interact() runs. Return COMPONENT_BLOCK_MACHINERY_INTERACT to block.
#define COMSIG_MOB_MACHINERY_INTERACT "mob_machinery_interact"
#define COMPONENT_BLOCK_MACHINERY_INTERACT (1<<1)
/// Fired on a mob when attempt_pickup fails due to fail_chance in pickup_mods. (obj/item/item)
#define COMSIG_LIVING_ITEM_PICKUP_FAILED "living_item_pickup_failed"
+4
View File
@@ -704,6 +704,10 @@
//Return a non FALSE value to interrupt attack_hand propagation to subtypes.
/obj/machinery/interact(mob/user)
// BUBBER EDIT ADDITION - allow components on the user to intercept or delay machinery interaction
if(SEND_SIGNAL(user, COMSIG_MOB_MACHINERY_INTERACT, src) & COMPONENT_BLOCK_MACHINERY_INTERACT)
return FALSE
// BUBBER EDIT ADDITION END
update_last_used(user)
return ..()
+14
View File
@@ -420,6 +420,8 @@
lefthand_file = SSgreyscale.GetColoredIconByType(greyscale_config_inhand_left, greyscale_colors)
if(greyscale_config_inhand_right)
righthand_file = SSgreyscale.GetColoredIconByType(greyscale_config_inhand_right, greyscale_colors)
// BUBBER EDIT ADDITION - Fire COMSIG_ATOM_UPDATED_ICON after all GAGS icons update so update_icon_updates_onmob can refresh worn overlays
SEND_SIGNAL(src, COMSIG_ATOM_UPDATED_ICON)
/obj/item/verb/move_to_top()
set name = "Move To Top"
@@ -574,6 +576,18 @@
if(!(user.mobility_flags & MOBILITY_PICKUP))
return
// BUBBER EDIT ADDITION - allow components on the user to inject a pickup delay or fail chance (e.g. ball mittens fumble)
var/list/pickup_mods = list("delay" = 0, "fail_chance" = 0)
if(SEND_SIGNAL(user, COMSIG_LIVING_ITEM_ATTEMPT_PICKUP, src, pickup_mods) & COMPONENT_BLOCK_ITEM_PICKUP)
return
if(pickup_mods["delay"])
if(!do_after(user, pickup_mods["delay"], src, timed_action_flags = IGNORE_HELD_ITEM))
return
if(pickup_mods["fail_chance"] && prob(pickup_mods["fail_chance"]))
SEND_SIGNAL(user, COMSIG_LIVING_ITEM_PICKUP_FAILED, src)
return
// BUBBER EDIT ADDITION END
if(!skip_grav)
//Heavy gravity makes picking up things very slow.
var/grav = user.has_gravity()
@@ -443,6 +443,10 @@
return covered_flags
/mob/living/carbon/is_location_accessible(location, exluded_equipment_slots = NONE)
// BUBBER EDIT ADDITION - ball mittens surgery passthrough
if(HAS_TRAIT(src, TRAIT_GLOVE_SURGERY_PASSTHROUGH))
exluded_equipment_slots |= ITEM_SLOT_GLOVES
// BUBBER EDIT ADDITION END
switch(location)
// Snowflake checks for these precise zones
if(BODY_ZONE_PRECISE_EYES)
@@ -470,7 +470,7 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
/datum/surgery_operation/proc/check_availability(mob/living/patient, atom/movable/operating_on, mob/living/surgeon, tool, operated_zone)
SHOULD_NOT_OVERRIDE(TRUE)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
// BUBBER EDIT REMOVAL - SHOULD_BE_PURE(TRUE) removed to allow clothing items to override is_location_accessible
if(isnull(operating_on))
return FALSE
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

@@ -1403,6 +1403,18 @@ TREK
name = "Catgloves Worn"
icon_file = 'modular_skyrat/modules/GAGS/icons/catglove_worn.dmi'
/datum/greyscale_config/magpaws
name = "Magpaws"
icon_file = 'modular_skyrat/modules/GAGS/icons/magpaws.dmi'
json_config = 'modular_skyrat/modules/GAGS/json_configs/gloves/magpaws.json'
/datum/greyscale_config/magpaws/worn
name = "Magpaws Worn"
icon_file = 'modular_skyrat/modules/GAGS/icons/magpaws.dmi'
json_config = 'modular_skyrat/modules/GAGS/json_configs/gloves/magpaws_worn.json'
// MISC SHOES
/datum/greyscale_config/heels
Binary file not shown.

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 B

After

Width:  |  Height:  |  Size: 930 B

@@ -0,0 +1 @@
catglove.cmi and catglove_worn.dmi by Online! (Discord) 🩵
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

@@ -4,13 +4,25 @@
"type": "icon_state",
"icon_state": "catglove",
"blend_mode": "overlay",
"color_ids": [ 1 ]
"color_ids": [
1
]
},
{
"type": "icon_state",
"icon_state": "catglove_paws",
"blend_mode": "overlay",
"color_ids": [ 2 ]
"color_ids": [
2
]
},
{
"type": "icon_state",
"icon_state": "catgloves_tag",
"blend_mode": "overlay",
"color_ids": [
3
]
}
]
}
@@ -0,0 +1,28 @@
{
"magpaws": [
{
"type": "icon_state",
"icon_state": "GAGSpawnsMainOBJ",
"blend_mode": "overlay",
"color_ids": [
1
]
},
{
"type": "icon_state",
"icon_state": "GAGgumdropsOBJ",
"blend_mode": "overlay",
"color_ids": [
2
]
},
{
"type": "icon_state",
"icon_state": "GAGsymbolOBJ",
"blend_mode": "overlay",
"color_ids": [
3
]
}
]
}
@@ -0,0 +1,28 @@
{
"magpaws_worn": [
{
"type": "icon_state",
"icon_state": "GAGspawsMainMOB",
"blend_mode": "overlay",
"color_ids": [
1
]
},
{
"type": "icon_state",
"icon_state": "GAGpawscolorMainMOB",
"blend_mode": "overlay",
"color_ids": [
2
]
},
{
"type": "icon_state",
"icon_state": "GaGsymbolMainMOB",
"blend_mode": "overlay",
"color_ids": [
3
]
}
]
}
@@ -13,7 +13,7 @@ GLOBAL_LIST_INIT(pref_checked_clothes, list(
/obj/item/clothing/suit/straight_jacket/kinky_sleepbag,
/obj/item/clothing/suit/straight_jacket/latex_straight_jacket,
/obj/item/clothing/gloves/ball_mittens,
/obj/item/clothing/gloves/ball_mittens_reinforced,
/obj/item/clothing/gloves/ball_mittens/loadout_paw,
/obj/item/clothing/suit/straight_jacket/shackles,
/obj/item/clothing/suit/straight_jacket/shackles/reinforced,
/obj/item/clothing/gloves/shibari_hands,
@@ -23,7 +23,10 @@ GLOBAL_LIST_INIT(pref_checked_clothes, list(
/obj/item/clothing/mob_can_equip(mob/living/user, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE, indirect_action)
if((slot_flags & slot) && (src.type in GLOB.pref_checked_clothes))
if(!(user.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)))
return FALSE
// indirect_action = TRUE means this is an outfit/loadout equip, not a player action.
// Allow it through - the player selected this item in their loadout deliberately.
// Also allow when there is no client yet (round start character transfer not complete).
if(!indirect_action && user.client)
if(!(user.client?.prefs?.read_preference(/datum/preference/toggle/erp/sex_toy)))
return FALSE
return ..()
@@ -1,40 +1,558 @@
//normal ball mittens
/datum/component/ball_mittens_fumble
dupe_mode = COMPONENT_DUPE_UNIQUE
var/struggle_delay_min = 0.8 SECONDS
var/interact_delay = 1.5 SECONDS
var/max_item_size = WEIGHT_CLASS_HUGE
var/cuff_resist_multiplier = 3
var/gun_spread_penalty = 12
var/is_interacting = FALSE
var/obj/item/tracked_cuffs = null
/datum/component/ball_mittens_fumble/Initialize()
. = ..()
if(!istype(parent, /obj/item/clothing/gloves/ball_mittens))
return COMPONENT_INCOMPATIBLE
RegisterSignal(parent, COMSIG_ITEM_PRE_UNEQUIP, PROC_REF(on_pre_unequip))
/datum/component/ball_mittens_fumble/proc/register_wearer(mob/living/wearer)
var/obj/item/clothing/gloves/ball_mittens/mittens = parent
if(mittens.is_paw_skin && isliving(wearer))
wearer.add_mood_event("paw_mittens", /datum/mood_event/wearing_paw_mittens)
if(!mittens.spawn_flavor_shown && mittens.loadout_created)
mittens.spawn_flavor_shown = TRUE
INVOKE_ASYNC(mittens, TYPE_PROC_REF(/obj/item/clothing/gloves/ball_mittens, deferred_spawn_flavor), wearer)
ADD_TRAIT(wearer, TRAIT_GLOVE_SURGERY_PASSTHROUGH, MITTENS_FUMBLE_TRAIT)
RegisterSignal(wearer, COMSIG_LIVING_ITEM_ATTEMPT_PICKUP, PROC_REF(on_attempt_pickup))
RegisterSignal(wearer, COMSIG_LIVING_ITEM_PICKUP_FAILED, PROC_REF(on_pickup_failed))
RegisterSignal(wearer, COMSIG_MOB_MACHINERY_INTERACT, PROC_REF(on_machinery_interact))
RegisterSignal(wearer, COMSIG_MOB_CLICKON, PROC_REF(on_clickon))
RegisterSignal(wearer, COMSIG_MOB_REMOVING_CUFFS, PROC_REF(on_removing_cuffs))
RegisterSignal(wearer, COMSIG_MOB_FIRED_GUN, PROC_REF(on_fired_gun))
RegisterSignal(wearer, COMSIG_TRY_STRIP, PROC_REF(on_try_strip))
RegisterSignal(wearer, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(on_mousedrop_receive))
RegisterSignal(wearer, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack))
/datum/component/ball_mittens_fumble/proc/unregister_wearer(mob/living/wearer)
if(!isliving(wearer))
return
wearer.clear_mood_event("paw_mittens")
REMOVE_TRAIT(wearer, TRAIT_GLOVE_SURGERY_PASSTHROUGH, MITTENS_FUMBLE_TRAIT)
UnregisterSignal(wearer, list(
COMSIG_LIVING_ITEM_ATTEMPT_PICKUP,
COMSIG_LIVING_ITEM_PICKUP_FAILED,
COMSIG_MOB_MACHINERY_INTERACT,
COMSIG_MOB_CLICKON,
COMSIG_MOB_REMOVING_CUFFS,
COMSIG_MOB_FIRED_GUN,
COMSIG_TRY_STRIP,
COMSIG_LIVING_UNARMED_ATTACK,
COMSIG_MOUSEDROPPED_ONTO,
))
/datum/component/ball_mittens_fumble/proc/on_pre_unequip(datum/source, force)
SIGNAL_HANDLER
if(force)
return
var/obj/item/clothing/gloves/ball_mittens/mittens = parent
var/mob/living/wearer = mittens.loc
if(!isliving(wearer))
return
to_chat(wearer, span_purple("You struggle furiously with [mittens], but you're not even sure if these can come off."))
return COMPONENT_ITEM_BLOCK_UNEQUIP
/datum/component/ball_mittens_fumble/proc/get_hand_descriptor(mob/living/wearer)
if(!iscarbon(wearer))
return "chunky mitts"
var/mob/living/carbon/human/human_wearer = wearer
var/obj/item/clothing/gloves/ball_mittens/mittens = human_wearer.gloves
if(istype(mittens) && mittens.is_paw_skin)
return "paws"
return "chunky mitts"
/// Intercepts item pickups via attempt_pickup. Enforces the one-item limit and injects a short pickup delay.
/datum/component/ball_mittens_fumble/proc/on_attempt_pickup(mob/living/wearer, obj/item/item, list/pickup_mods)
SIGNAL_HANDLER
if(!isgun(item) && item.w_class >= max_item_size)
pickup_mods["delay"] = struggle_delay_min * (item.w_class - max_item_size + 2)
pickup_mods["fail_chance"] = min(75, (item.w_class - max_item_size) * 25)
to_chat(wearer, span_warning("You wrestle with [item], trying to get it between your [get_hand_descriptor(wearer)]..."))
return
var/hand_desc = get_hand_descriptor(wearer)
var/player_msgs = list(
"You awkwardly wedge the [item] between your [hand_desc]...",
"You clumsily pin the [item] between your [hand_desc]...",
"You struggle to secure the [item] in your [hand_desc] before finally succeeding.",
"You carefully balance the [item] between your unwieldy [hand_desc]..."
)
to_chat(wearer, span_purple(pick(player_msgs)))
var/public_msg
if(isgun(item))
var/gun_msgs = list(
"[wearer] takes hold of the [item] in defiance of common sense.",
"[wearer] awkwardly presses the [item] between [wearer.p_their()] [hand_desc].",
"[wearer] picks up the [item], awkwardly pressing [wearer.p_their()] pads against the trigger guard!"
)
public_msg = pick(gun_msgs)
else
var/general_msgs = list(
"[wearer] awkwardly secures the [item] in [wearer.p_their()] [hand_desc].",
"[wearer] carefully grips the [item] with [wearer.p_their()] [hand_desc].",
"[wearer] almost drops [item] before managing to press it between [wearer.p_their()] [hand_desc].",
"[wearer] carefully balances the [item] between [wearer.p_their()] [hand_desc]."
)
public_msg = pick(general_msgs)
wearer.visible_message(span_warning(public_msg))
pickup_mods["delay"] = struggle_delay_min
/datum/component/ball_mittens_fumble/proc/on_pickup_failed(mob/living/wearer, obj/item/item)
SIGNAL_HANDLER
var/hand_desc = get_hand_descriptor(wearer)
to_chat(wearer, span_warning("[item] slips out of your [hand_desc]!"))
playsound(wearer, 'modular_skyrat/modules/modular_items/lewd_items/sounds/latex.ogg', 30, TRUE)
/// Handles machinery interaction delay via COMSIG_MOB_MACHINERY_INTERACT.
/datum/component/ball_mittens_fumble/proc/on_machinery_interact(mob/living/wearer, obj/machinery/machine)
SIGNAL_HANDLER
if(is_interacting)
return
// Simple toggle/single-action machines trivial to operate with a paw - bypass delay
var/static/list/paw_passthrough = typecacheof(list(
/obj/machinery/button,
/obj/machinery/photobooth,
/obj/machinery/light_switch,
/obj/machinery/shower,
/obj/machinery/firealarm,
/obj/machinery/conveyor,
/obj/machinery/conveyor_switch,
/obj/machinery/grill,
/obj/machinery/oven,
/obj/machinery/food_cart,
))
if(is_type_in_typecache(machine, paw_passthrough))
return
INVOKE_ASYNC(src, PROC_REF(fumble_interact), wearer, machine)
return COMPONENT_BLOCK_MACHINERY_INTERACT
/datum/component/ball_mittens_fumble/proc/on_clickon(mob/living/wearer, atom/target, list/modifiers)
SIGNAL_HANDLER
if(wearer.throw_mode)
var/obj/item/held = wearer.get_active_held_item()
if(!held)
wearer.throw_mode_off(THROW_MODE_TOGGLE)
return COMSIG_MOB_CANCEL_CLICKON
if(prob(5))
to_chat(wearer, span_purple("You try to grip the [held] with your [get_hand_descriptor(wearer)] to throw it, but it clatters noisily to the floor instead."))
playsound(wearer, 'modular_skyrat/modules/modular_items/lewd_items/sounds/latex.ogg', 30, TRUE)
wearer.dropItemToGround(held)
wearer.throw_mode_off(THROW_MODE_TOGGLE)
return COMSIG_MOB_CANCEL_CLICKON
if(modifiers && (LAZYACCESS(modifiers, SHIFT_CLICK) || LAZYACCESS(modifiers, ALT_CLICK) || LAZYACCESS(modifiers, RIGHT_CLICK) || LAZYACCESS(modifiers, CTRL_CLICK)))
return
if(get_dist(wearer, target) > 1)
return
if(isclothing(target) && isliving(target.loc) && !wearer.get_active_held_item() && !wearer.combat_mode)
var/obj/item/clothing/cloth = target
var/mob/living/living_loc = target.loc
var/in_hand = (target in wearer.held_items)
var/truly_worn = (cloth.slot_flags && living_loc.get_item_by_slot(cloth.slot_flags) == cloth)
if(in_hand || truly_worn)
if(istype(cloth, /obj/item/clothing/gloves/ball_mittens))
INVOKE_ASYNC(cloth, TYPE_PROC_REF(/obj/item/clothing/gloves/ball_mittens, doStrip), wearer, wearer)
return COMSIG_MOB_CANCEL_CLICKON
INVOKE_ASYNC(src, PROC_REF(clothing_struggle), wearer, target)
return COMSIG_MOB_CANCEL_CLICKON
/datum/component/ball_mittens_fumble/proc/clothing_struggle(mob/living/wearer, obj/item/clothing/cloth)
var/delay = 12 SECONDS
var/hand_desc = get_hand_descriptor(wearer)
to_chat(wearer, span_purple("You struggle to remove [cloth]. It's extremely difficult with your [hand_desc]... (This will take around [DisplayTimeText(delay)] and you need to stand still.)"))
if(!do_after(wearer, delay, cloth, timed_action_flags = IGNORE_HELD_ITEM))
to_chat(wearer, span_warning("You give up on [cloth]."))
return
if(QDELETED(src) || QDELETED(wearer) || QDELETED(cloth))
return
wearer.dropItemToGround(cloth)
/datum/component/ball_mittens_fumble/proc/on_unarmed_attack(mob/living/wearer, atom/attack_target, proximity_flag, list/modifiers)
SIGNAL_HANDLER
if(!proximity_flag || !isliving(attack_target))
return
playsound(wearer, pick('sound/items/toy_squeak/toysqueak1.ogg', 'sound/items/toy_squeak/toysqueak2.ogg', 'sound/items/toy_squeak/toysqueak3.ogg'), 40, TRUE)
/datum/component/ball_mittens_fumble/proc/on_mousedrop_receive(mob/living/wearer, atom/from, mob/user, params)
SIGNAL_HANDLER
if(user != wearer || !isitem(from))
return
var/obj/item/dragged = from
var/slot = wearer.get_slot_by_item(dragged)
if(!(slot & (ITEM_SLOT_BELT|ITEM_SLOT_BACK)))
return
INVOKE_ASYNC(src, PROC_REF(delayed_drag_unequip), wearer, dragged)
return COMPONENT_CANCEL_MOUSEDROPPED_ONTO
/datum/component/ball_mittens_fumble/proc/delayed_drag_unequip(mob/living/wearer, obj/item/item)
var/hand_desc = get_hand_descriptor(wearer)
to_chat(wearer, span_purple("You carefully work at your [item] with your [hand_desc]..."))
if(!do_after(wearer, struggle_delay_min, item, timed_action_flags = IGNORE_HELD_ITEM))
to_chat(wearer, span_warning("You give up on [item]."))
return
if(QDELETED(src) || QDELETED(wearer) || QDELETED(item))
return
if(!wearer.get_slot_by_item(item))
return
wearer.put_in_hands(item)
/datum/component/ball_mittens_fumble/proc/on_try_strip(mob/living/wearer, atom/target, obj/item/item)
SIGNAL_HANDLER
// COMSIG_TRY_STRIP and COMSIG_BEING_STRIPPED share the same signal string "try_strip".
// When item IS on the wearer: signal fired via COMSIG_BEING_STRIPPED - someone acting on the wearer - allow.
// When item is NOT on the wearer but in target's held_items: equip action onto the wearer - allow.
// When item is NOT on the wearer and NOT in target's hands: wearer is stripping from target - delay.
if(wearer.get_slot_by_item(item))
return
if(isliving(target))
var/mob/living/living_target = target
if(item in living_target.held_items)
return // Item in target's hands = equip action, not a strip
if(!isliving(target) || !isitem(item))
return COMPONENT_CANT_STRIP
to_chat(wearer, span_purple("You fumble awkwardly at [target]'s gear with your [get_hand_descriptor(wearer)], trying to find a grip..."))
INVOKE_ASYNC(src, PROC_REF(delayed_strip), wearer, target, item)
return COMPONENT_CANT_STRIP
/datum/component/ball_mittens_fumble/proc/delayed_strip(mob/living/wearer, mob/living/target, obj/item/item)
if(!do_after(wearer, item.strip_delay * 2.5, target, timed_action_flags = IGNORE_HELD_ITEM))
to_chat(wearer, span_warning("You give up trying to remove [item] from [target]."))
return
if(QDELETED(src) || QDELETED(wearer) || QDELETED(target) || QDELETED(item))
return
item.doStrip(wearer, target)
/datum/component/ball_mittens_fumble/proc/on_removing_cuffs(mob/living/wearer, obj/item/cuffs)
SIGNAL_HANDLER
if(!cuffs)
return
if(cuffs == tracked_cuffs)
return
tracked_cuffs = cuffs
var/original = cuffs.breakouttime
cuffs.breakouttime = original * cuff_resist_multiplier
addtimer(CALLBACK(src, PROC_REF(restore_breakouttime), cuffs, original), 1, TIMER_UNIQUE | TIMER_OVERRIDE)
/datum/component/ball_mittens_fumble/proc/restore_breakouttime(obj/item/cuffs, original_time)
if(QDELETED(cuffs))
tracked_cuffs = null
return
cuffs.breakouttime = original_time
tracked_cuffs = null
/datum/component/ball_mittens_fumble/proc/on_fired_gun(mob/living/wearer, obj/item/gun/gun, atom/target, params, zone_override, list/bonus_spread_values)
SIGNAL_HANDLER
if(!isgun(gun) || !islist(bonus_spread_values))
return
bonus_spread_values[MAX_BONUS_SPREAD_INDEX] += gun_spread_penalty
/datum/component/ball_mittens_fumble/proc/fumble_interact(mob/living/wearer, obj/machinery/machine)
is_interacting = TRUE
var/hand_desc = get_hand_descriptor(wearer)
var/msg = istype(machine, /obj/machinery/vending) ? \
"You awkwardly mash your [hand_desc] against [machine]'s keypad..." : \
"You awkwardly paw at [machine] with your [hand_desc]..."
wearer.face_atom(machine)
to_chat(wearer, span_purple(msg))
wearer.visible_message(span_warning("[wearer] awkwardly paws at [machine] with [wearer.p_their()] [hand_desc], visibly struggling to use it."))
if(!do_after(wearer, interact_delay, machine))
to_chat(wearer, span_warning("You give up on [machine]."))
is_interacting = FALSE
return
if(QDELETED(src) || QDELETED(wearer) || QDELETED(machine) || get_dist(wearer, machine) > 1)
is_interacting = FALSE
return
machine.interact(wearer)
is_interacting = FALSE
// ============================================================
/datum/atom_skin/ball_mittens_skin
abstract_type = /datum/atom_skin/ball_mittens_skin
greyscale_item_path = /obj/item/clothing/gloves/ball_mittens/loadout_paw
/datum/atom_skin/ball_mittens_skin/default
preview_name = "Ball Mittens"
reset_missing = TRUE
/datum/atom_skin/ball_mittens_skin/cat_paws
preview_name = "Cat Paws"
new_name = "latex paw mittens"
new_desc = "A pair of inflatable latex mittens shaped like rounded paws. Helpless AND humiliating."
change_worn_icon_state = FALSE
greyscale_item_path = null
new_icon = 'icons/map_icons/clothing/_clothing.dmi'
new_icon_state = "/obj/item/clothing/gloves/ball_mittens/loadout_paw"
new_worn_icon = 'modular_skyrat/modules/GAGS/icons/catglove_worn.dmi'
/datum/atom_skin/ball_mittens_skin/cat_paws/get_preview_icon(atom/for_atom)
return image(icon = 'icons/map_icons/clothing/_clothing.dmi', icon_state = "/obj/item/clothing/gloves/ball_mittens/loadout_paw")
/datum/atom_skin/ball_mittens_skin/cat_paws/apply(atom/apply_to, mob/user)
var/obj/item/clothing/gloves/ball_mittens/mittens = apply_to
if(istype(mittens))
mittens.greyscale_config = /datum/greyscale_config/catgloves
mittens.greyscale_config_worn = /datum/greyscale_config/catgloves/worn
if(!mittens.greyscale_colors || mittens.greyscale_colors == "")
mittens.greyscale_colors = "#242329#7B48A6#15B1BF"
mittens.flags_1 |= IS_PLAYER_COLORABLE_1
. = ..()
if(istype(mittens))
mittens.is_paw_skin = TRUE
mittens.worn_icon = 'modular_skyrat/modules/GAGS/icons/catglove_worn.dmi'
mittens.icon_state = "catgloves"
mittens.worn_icon_state = "catgloves"
mittens.set_greyscale(mittens.greyscale_colors, /datum/greyscale_config/catgloves)
/datum/atom_skin/ball_mittens_skin/cat_paws/clear_skin(atom/clear_from)
var/obj/item/clothing/gloves/ball_mittens/mittens = clear_from
if(istype(mittens))
mittens.is_paw_skin = FALSE
mittens.greyscale_config = null
mittens.greyscale_config_worn = null
mittens.flags_1 &= ~IS_PLAYER_COLORABLE_1
mittens.icon_state = initial(mittens.icon_state)
mittens.worn_icon_state = initial(mittens.worn_icon_state)
mittens.worn_icon = initial(mittens.worn_icon)
. = ..()
if(istype(mittens))
mittens.update_appearance()
// ============================================================
/obj/item/clothing/gloves/ball_mittens
name = "ball mittens"
desc = "A nice, comfortable pair of inflatable ball gloves."
desc = "A pair of inflatable latex mittens. Adorable and comfortable, but completely useless for anything requiring fingers. Getting these off yourself is a serious ordeal — you'll probably want help."
icon_state = "ballmittens"
inhand_icon_state = null
inhand_icon_state = "" // Explicitly empty - null can cause BYOND to fall back to the main icon
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_clothing/lewd_gloves.dmi'
worn_icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_clothing/lewd_gloves.dmi'
breakouttime = 1 SECONDS
strip_delay = 8 SECONDS
resistance_flags = FIRE_PROOF
armor_type = /datum/armor/ball_mittens
equip_sound = 'modular_zubbers/sound/lewd/rubber1.ogg'
drop_sound = 'modular_zubbers/sound/lewd/rubber2.ogg'
pickup_sound = 'modular_zubbers/sound/lewd/rubber3.ogg'
var/is_paw_skin = FALSE
var/spawn_flavor_shown = FALSE
var/loadout_created = FALSE
var/lights_on = FALSE
//That part allows reinforcing this item with handcuffs
/obj/item/clothing/gloves/ball_mittens/attackby(obj/item/attacking_item, mob/user, params)
/obj/item/clothing/gloves/ball_mittens/Initialize(mapload)
. = ..()
if(.)
AddElement(/datum/element/update_icon_updates_onmob)
/obj/item/clothing/gloves/ball_mittens/equipped(mob/user, slot)
. = ..()
if(slot != ITEM_SLOT_GLOVES)
return
if(!istype(attacking_item, /obj/item/restraints/handcuffs))
if(is_paw_skin)
to_chat(user, span_purple("The [src] seal around your hands. You pull at them and find it completely impossible to remove them..."))
else
to_chat(user, span_purple("Your hands sink into [src]. Soft, round, and not particularly good at anything. As soon as you put them on, you hear them self inflate. Oh shit..."))
RegisterSignal(src, COMSIG_OBJ_RESKIN, PROC_REF(on_reskin))
var/datum/component/ball_mittens_fumble/comp = AddComponent(/datum/component/ball_mittens_fumble)
comp.register_wearer(user)
/obj/item/clothing/gloves/ball_mittens/dropped(mob/user)
. = ..()
UnregisterSignal(src, COMSIG_OBJ_RESKIN)
var/datum/component/ball_mittens_fumble/comp = GetComponent(/datum/component/ball_mittens_fumble)
comp?.unregister_wearer(user)
qdel(comp)
/obj/item/clothing/gloves/ball_mittens/proc/on_reskin(datum/source, skin_name)
SIGNAL_HANDLER
is_paw_skin = (skin_name == "Cat Paws")
var/mob/living/wearer = loc
if(!isliving(wearer))
return
var/obj/item/clothing/gloves/ball_mittens_reinforced/reinforced_muffs = new
remove_item_from_storage(user)
user.put_in_hands(reinforced_muffs)
to_chat(user, span_notice("You reinforced the belts on [src] with [attacking_item]."))
qdel(attacking_item)
qdel(src)
if(is_paw_skin)
wearer.add_mood_event("paw_mittens", /datum/mood_event/wearing_paw_mittens)
to_chat(wearer, span_purple("The nanite-infused rubber shifts your hands into soft, rounded paw shapes."))
else
wearer.clear_mood_event("paw_mittens")
to_chat(wearer, span_purple("The mittens ease back into their round ball shape. Still completely useless."))
/// Opens the GAGS recolor menu for spray can use on paw mittens.
/// gags_recolorable.open_ui() uses initial() on greyscale_config which returns null
/// for runtime-assigned configs, so we open the menu with the live config directly.
/obj/item/clothing/gloves/ball_mittens/proc/paw_spray_interact(mob/living/user, obj/item/tool, list/modifiers)
if(!istype(tool, /obj/item/toy/crayon/spraycan))
return NONE
var/obj/item/toy/crayon/spraycan/can = tool
if(can.is_capped)
user.balloon_alert(user, "take the cap off first!")
return ITEM_INTERACT_BLOCKING
if(can.check_empty())
user.balloon_alert(user, "empty!")
return ITEM_INTERACT_BLOCKING
if(!user.client)
return ITEM_INTERACT_BLOCKING
var/list/allowed = list("[/datum/greyscale_config/catgloves]", "[/datum/greyscale_config/catgloves/worn]")
var/datum/greyscale_modify_menu/spray_paint/menu = new(
src, user.client, allowed,
CALLBACK(src, PROC_REF(apply_spray_colors), can),
"catgloves",
/datum/greyscale_config/catgloves,
greyscale_colors,
can,
)
menu.ui_interact(user)
return ITEM_INTERACT_SUCCESS
/obj/item/clothing/gloves/ball_mittens/proc/apply_spray_colors(obj/item/toy/crayon/spraycan/can, datum/greyscale_modify_menu/menu)
if(QDELETED(src) || QDELETED(can) || QDELETED(menu))
return
if(can.is_capped || can.check_empty())
menu.ui_close()
return
can.use_charges()
if(can.pre_noise)
audible_message(span_hear("You hear spraying."))
playsound(loc, 'sound/effects/spray.ogg', 50, TRUE, 5)
set_greyscale(menu.split_colors)
/obj/item/clothing/gloves/ball_mittens/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(is_paw_skin && istype(tool, /obj/item/toy/crayon/spraycan))
return paw_spray_interact(user, tool, modifiers)
return ..()
/obj/item/clothing/gloves/ball_mittens/update_overlays()
. = ..()
if(lights_on && is_paw_skin)
. += emissive_appearance(icon, icon_state, src, alpha = 100)
/obj/item/clothing/gloves/ball_mittens/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
. = ..()
if(lights_on && is_paw_skin)
. += emissive_appearance(standing.icon, standing.icon_state, src, alpha = 100)
/obj/item/clothing/gloves/ball_mittens/examine(mob/user)
. = ..()
if(is_paw_skin)
. += span_notice("There's a paw-friendly switch on the cuff. It's currently <b>[lights_on ? "ON" : "OFF"]</b>. <a href='byond://?src=[REF(src)];toggle_lights=1'>\[Toggle\]</a>")
/obj/item/clothing/gloves/ball_mittens/Topic(href, href_list)
. = ..()
if(href_list["toggle_lights"])
if(!usr || !ishuman(usr))
return
var/mob/living/carbon/human/toggler = usr
if(toggler.gloves != src)
return
lights_on = !lights_on
playsound(src, 'sound/machines/click.ogg', 30, FALSE)
to_chat(usr, span_notice("You turn the accent lighting [lights_on ? "on" : "off"]."))
update_appearance()
/obj/item/clothing/gloves/ball_mittens/proc/deferred_spawn_flavor(mob/user)
if(user.client)
show_spawn_flavor(user)
return
RegisterSignal(user, COMSIG_MOB_LOGIN, PROC_REF(on_client_login_flavor))
/obj/item/clothing/gloves/ball_mittens/proc/on_client_login_flavor(mob/user)
SIGNAL_HANDLER
UnregisterSignal(user, COMSIG_MOB_LOGIN)
show_spawn_flavor(user)
/datum/armor/ball_mittens
bio = 1
/obj/item/clothing/gloves/ball_mittens/proc/show_spawn_flavor(mob/user)
if(!user?.client)
return
if(is_paw_skin)
to_chat(user, span_purple("You look down at your paws. Round and soft and utterly useless. You blush as you think about how difficult this is going to make your day at work."))
else
to_chat(user, span_purple("You look down at [src]. Why did I come to work like this?"))
/obj/item/clothing/gloves/ball_mittens/attackby(obj/item/item, mob/living/user, params)
if(!istype(item, /obj/item/clothing/gloves/color/yellow))
return ..()
if(siemens_coefficient == 0)
to_chat(user, span_warning("[src] are already insulated."))
return
user.visible_message(
span_notice("[user] holds [item] up to [src] with a look of intense concentration, then discards it with a sigh."),
span_notice("You press [item] against [src], attempting to combine them. Halfway through you realize latex is, in fact, already an insulator. You throw away the insulated gloves.")
)
siemens_coefficient = 0
name = "insulated [name]"
if(desc == initial(desc))
desc = "A pair of inflatable latex mittens. Someone has helpfully applied insulated gloves to them, only to realise too late that latex was already an insulator."
qdel(item)
update_appearance()
return TRUE
//ball_mittens reinforced
/obj/item/clothing/gloves/ball_mittens_reinforced //We getting this item by using handcuffs on normal ball mittens
name = "reinforced ball mittens"
desc = "Do not put these on, it's REALLY hard to take them off! But they look so comfortable..."
icon_state = "ballmittens"
inhand_icon_state = null
icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/obj/lewd_clothing/lewd_gloves.dmi'
worn_icon = 'modular_skyrat/modules/modular_items/lewd_items/icons/mob/lewd_clothing/lewd_gloves.dmi'
clothing_flags = DANGEROUS_OBJECT
breakouttime = 100 SECONDS //do not touch this, i beg you.
/obj/item/clothing/gloves/ball_mittens/doStrip(mob/stripper, mob/owner)
if(stripper != owner)
if(!owner.dropItemToGround(src, force = TRUE))
return FALSE
if(HAS_TRAIT(stripper, TRAIT_STICKY_FINGERS))
stripper.put_in_hands(src)
return TRUE
var/delay = 1 MINUTES
to_chat(owner, span_purple("You attempt to remove [src]... (This will take around [DisplayTimeText(delay)] and you need to stand still.)"))
to_chat(owner, span_purple("You struggle furiously with [src], but you're not even sure if these can come off."))
playsound(owner, pick('modular_zubbers/sound/lewd/rubber1.ogg', 'modular_zubbers/sound/lewd/rubber2.ogg', 'modular_zubbers/sound/lewd/rubber3.ogg'), 40, TRUE)
if(!do_after(owner, delay, src, timed_action_flags = IGNORE_HELD_ITEM))
to_chat(owner, span_purple("You give up trying to escape [src]. Maybe having [src] isn't so bad..."))
return FALSE
if(QDELETED(src) || !isliving(loc))
return FALSE
if(!owner.dropItemToGround(src, force = TRUE))
return FALSE
if(HAS_TRAIT(stripper, TRAIT_STICKY_FINGERS))
stripper.put_in_hands(src)
return TRUE
// ============================================================
// Loadout subtype for paw mittens.
// ============================================================
/obj/item/clothing/gloves/ball_mittens/loadout_paw
name = "latex paw mittens"
desc = "A pair of inflatable latex mittens shaped like rounded paws. Helpless AND humiliating."
greyscale_config = /datum/greyscale_config/catgloves
greyscale_config_worn = /datum/greyscale_config/catgloves/worn
greyscale_colors = "#242329#7B48A6#15B1BF"
flags_1 = IS_PLAYER_COLORABLE_1
worn_icon = 'modular_skyrat/modules/GAGS/icons/catglove_worn.dmi'
worn_icon_state = "catgloves"
icon_state = "BasePaws"
post_init_icon_state = "catgloves"
icon_preview = 'icons/map_icons/clothing/_clothing.dmi'
icon_state_preview = "/obj/item/clothing/gloves/ball_mittens/loadout_paw"
is_paw_skin = TRUE
inhand_icon_state = "greyscale_gloves"
alternate_worn_layer = SHOES_LAYER // Ensures paws render above mech_suit which claims GLOVES_LAYER
/obj/item/clothing/gloves/ball_mittens/loadout_paw/Initialize(mapload)
. = ..()
loadout_created = TRUE
for(var/datum/component/reskinable_item/reskin_comp in GetComponents(/datum/component/reskinable_item))
qdel(reskin_comp)
/obj/item/clothing/gloves/ball_mittens/loadout_paw/equipped(mob/user, slot)
. = ..()
if(slot != ITEM_SLOT_GLOVES)
return
update_greyscale()
// ============================================================
/datum/mood_event/wearing_paw_mittens
description = span_purple("So-ft... Ro-und... Use-less... Lo-ve it!\n")
//latex gloves
/obj/item/clothing/gloves/latex_gloves
name = "latex gloves"
desc = "Awesome looking gloves that are satisfying to the touch."
@@ -357,15 +357,6 @@
* MISC LOGIC
*/
// Handles breaking out of gloves that restrain people.
/mob/living/carbon/human/resist_restraints()
if(gloves?.breakouttime)
changeNext_move(CLICK_CD_BREAKOUT)
last_special = world.time + CLICK_CD_BREAKOUT
cuff_resist(gloves)
else
..()
/// Checks if the human is wearing a condom, and also hasn't broken it.
/mob/living/carbon/human/proc/is_wearing_condom()
if(!penis || !istype(penis, /obj/item/clothing/sextoy/condom))
@@ -77,8 +77,9 @@
. = ..()
if(CONFIG_GET(flag/disable_lewd_items))
return INITIALIZE_HINT_QDEL
AddComponent(/datum/component/reskinable_item, /datum/atom_skin/ball_mittens_skin, FALSE)
/obj/item/clothing/gloves/ball_mittens_reinforced/Initialize(mapload)
/obj/item/clothing/gloves/ball_mittens/loadout_paw/Initialize(mapload)
. = ..()
if(CONFIG_GET(flag/disable_lewd_items))
return INITIALIZE_HINT_QDEL
@@ -237,8 +238,3 @@
. = ..()
if(CONFIG_GET(flag/disable_lewd_items))
return INITIALIZE_HINT_QDEL
/obj/item/toy/plush/aeri/Initialize(mapload)
. = ..()
if(CONFIG_GET(flag/disable_lewd_items))
return INITIALIZE_HINT_QDEL
@@ -124,6 +124,7 @@
//hands
/obj/item/clothing/gloves/ball_mittens = 8,
/obj/item/clothing/gloves/ball_mittens/loadout_paw = 5,
),
),
list(
@@ -6,7 +6,7 @@ GLOBAL_LIST_INIT(erp_items, list(
/obj/item/clothing/glasses/blindfold/kinky,
/obj/item/clothing/glasses/hypno,
/obj/item/clothing/gloves/ball_mittens,
/obj/item/clothing/gloves/ball_mittens_reinforced,
/obj/item/clothing/gloves/ball_mittens/loadout_paw,
/obj/item/clothing/head/domina_cap,
/obj/item/clothing/mask/ballgag,
/obj/item/clothing/mask/gas/bdsm_mask,
@@ -15,17 +15,86 @@
//Cat Gloves seemingly by Taomayo of MonkeStation
/obj/item/clothing/gloves/cat
desc = "hewwo everynyaan!!"
desc = "\"High Tech\" paw shaped gloves perfect for cosplay enthusiasts, streamers and general weirdos. hewwo everynyaan!!"
name = "cat gloves"
icon = 'icons/map_icons/clothing/_clothing.dmi'
icon_state = "/obj/item/clothing/gloves/cat"
post_init_icon_state = "catgloves"
flags_1 = IS_PLAYER_COLORABLE_1
greyscale_colors = "#ffffff#FFC0CB"
greyscale_colors = "#ffffff#FFC0CB#B0EAF6"
greyscale_config_worn = /datum/greyscale_config/catgloves/worn
greyscale_config = /datum/greyscale_config/catgloves
greyscale_config_inhand_left = null
greyscale_config_inhand_right = null
resistance_flags = FIRE_PROOF
var/lights_on = FALSE
/obj/item/clothing/gloves/cat/Initialize(mapload)
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
/obj/item/clothing/gloves/cat/equipped(mob/user, slot)
. = ..()
if(slot == ITEM_SLOT_GLOVES)
ADD_TRAIT(user, TRAIT_GLOVE_SURGERY_PASSTHROUGH, "cat_gloves")
/obj/item/clothing/gloves/cat/dropped(mob/user)
. = ..()
REMOVE_TRAIT(user, TRAIT_GLOVE_SURGERY_PASSTHROUGH, "cat_gloves")
/obj/item/clothing/gloves/cat/update_overlays()
. = ..()
if(lights_on)
. += emissive_appearance(icon, icon_state, src, alpha = 100)
/obj/item/clothing/gloves/cat/worn_overlays(mutable_appearance/standing, isinhands, icon_file)
. = ..()
if(lights_on)
. += emissive_appearance(standing.icon, standing.icon_state, src, alpha = 100)
/obj/item/clothing/gloves/cat/examine(mob/user)
. = ..()
. += span_notice("There's a small switch on the wrist. It's currently <b>[lights_on ? "ON" : "OFF"]</b>. <a href='byond://?src=[REF(src)];toggle_lights=1'>\[Toggle\]</a>")
/obj/item/clothing/gloves/cat/Topic(href, href_list)
. = ..()
if(href_list["toggle_lights"])
if(!usr || !ishuman(usr))
return
var/mob/living/carbon/human/toggler = usr
if(toggler.gloves != src)
return
lights_on = !lights_on
playsound(src, 'sound/machines/click.ogg', 30, FALSE)
to_chat(usr, span_notice("You turn the accent lighting [lights_on ? "on" : "off"]."))
update_appearance()
/obj/item/clothing/gloves/cat/attackby(obj/item/item, mob/living/user, params)
if(!istype(item, /obj/item/clothing/gloves/color/yellow))
return ..()
if(siemens_coefficient == 0)
to_chat(user, span_warning("[src] are already insulated."))
return
user.visible_message(
span_notice("[user] awkwardly crams [item] inside [src]."),
span_notice("You press [item] against [src], after some time you succeed at inserting [item] inside.")
)
siemens_coefficient = 0
name = "insulated [name]"
if(desc == initial(desc))
desc = "A pair of cat gloves with a pair of insulated gloves awkwardly crammed inside them. Somehow this works."
qdel(item)
update_appearance()
return TRUE
/obj/item/clothing/gloves/cat/equipped(mob/user, slot)
. = ..()
if(slot == ITEM_SLOT_GLOVES)
ADD_TRAIT(user, TRAIT_GLOVE_SURGERY_PASSTHROUGH, "cat_gloves")
/obj/item/clothing/gloves/cat/dropped(mob/user)
. = ..()
REMOVE_TRAIT(user, TRAIT_GLOVE_SURGERY_PASSTHROUGH, "cat_gloves")
//Metrocop Gloves by ... Dun dun dun, HL13 station.
@@ -157,6 +157,14 @@
name = "Charcoal Fingerless Gloves"
item_path = /obj/item/clothing/gloves/skyy
// Uses a loadout-only dummy type that holds the catgloves GAGS config at type level
// so the loadout color picker works, then swaps itself for real ball mittens in paw mode on spawn.
// i know this is probably dumb but I couldn't figure out a better way to do it :(
/datum/loadout_item/gloves/ball_mittens_paw
name = "Latex Paw Mittens"
item_path = /obj/item/clothing/gloves/ball_mittens/loadout_paw
erp_item = TRUE
/*
* RINGS
*/
@@ -209,6 +209,11 @@
name = "Strapon"
item_path = /obj/item/clothing/strapon
/datum/loadout_item/toys/lewd/ball_mittens
name = "Ball Mittens"
item_path = /obj/item/clothing/gloves/ball_mittens
erp_item = TRUE
/datum/loadout_item/toys/lewd/aeri
name = "Interdimensional Terrorist Plushie"
item_path = /obj/item/toy/plush/aeri