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 /🆑
@@ -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"
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
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
|
||||
|
||||
|
Before Width: | Height: | Size: 452 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 453 B After Width: | Height: | Size: 930 B |
@@ -0,0 +1 @@
|
||||
catglove.cmi and catglove_worn.dmi by Online! (Discord) 🩵
|
||||
|
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
|
||||
|
||||