From 4f36062120a254b92b651abc94dcbd97f133e06f Mon Sep 17 00:00:00 2001 From: Aeri Date: Sun, 14 Jun 2026 10:21:23 -0400 Subject: [PATCH] Ball Mittens: Expanded and Enhanced (#5664) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit image ## 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. image image image ## Changelog :cl: 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 /:cl: --- .../__DEFINES/~skyrat_defines/lewd_defines.dm | 17 + code/game/machinery/_machinery.dm | 4 + code/game/objects/items.dm | 14 + code/modules/mob/living/carbon/inventory.dm | 4 + code/modules/surgery/operations/_operation.dm | 2 +- icons/map_icons/clothing/_clothing.dmi | Bin 3690 -> 5061 bytes .../modules/GAGS/greyscale_configs.dm | 12 + .../modules/GAGS/icons/catglove.dmi | Bin 452 -> 1168 bytes .../modules/GAGS/icons/catglove_worn.dmi | Bin 453 -> 930 bytes modular_skyrat/modules/GAGS/icons/credit.md | 1 + modular_skyrat/modules/GAGS/icons/magpaws.dmi | Bin 0 -> 3022 bytes .../GAGS/json_configs/gloves/catgloves.json | 16 +- .../GAGS/json_configs/gloves/magpaws.json | 28 + .../json_configs/gloves/magpaws_worn.json | 28 + .../lewd_items/code/clothing_pref_check.dm | 11 +- .../code/lewd_clothing/lewd_gloves.dm | 568 +++++++++++++++++- .../lewd_items/code/lewd_helpers/human.dm | 9 - .../_erp_disabled_item_enforcement.dm | 8 +- .../code/lewd_machinery/lustwish.dm | 1 + .../code/_globalvars/lists/erp_items.dm | 2 +- .../code/modules/clothing/gloves/misc.dm | 73 ++- .../code/modules/loadout/categories/gloves.dm | 8 + .../code/modules/loadout/categories/toys.dm | 5 + 23 files changed, 761 insertions(+), 50 deletions(-) create mode 100644 modular_skyrat/modules/GAGS/icons/credit.md create mode 100644 modular_skyrat/modules/GAGS/icons/magpaws.dmi create mode 100644 modular_skyrat/modules/GAGS/json_configs/gloves/magpaws.json create mode 100644 modular_skyrat/modules/GAGS/json_configs/gloves/magpaws_worn.json diff --git a/code/__DEFINES/~skyrat_defines/lewd_defines.dm b/code/__DEFINES/~skyrat_defines/lewd_defines.dm index 90711768d36..93d54149799 100644 --- a/code/__DEFINES/~skyrat_defines/lewd_defines.dm +++ b/code/__DEFINES/~skyrat_defines/lewd_defines.dm @@ -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" diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 70cb1811034..b6e46ff6976 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -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 ..() diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index bfcf2ab4e59..301bfcc57d2 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -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() diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index fcf292496f2..e5ebe9cb4fc 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -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) diff --git a/code/modules/surgery/operations/_operation.dm b/code/modules/surgery/operations/_operation.dm index 26d647f2472..12a3fe54988 100644 --- a/code/modules/surgery/operations/_operation.dm +++ b/code/modules/surgery/operations/_operation.dm @@ -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 diff --git a/icons/map_icons/clothing/_clothing.dmi b/icons/map_icons/clothing/_clothing.dmi index 8dd4f7952e014bc0ad705663f2b1c21e7c5ba7f5..45438b8734955d0231b31aae0bf1c69c35045e7f 100644 GIT binary patch literal 5061 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 diff --git a/modular_skyrat/modules/GAGS/icons/catglove_worn.dmi b/modular_skyrat/modules/GAGS/icons/catglove_worn.dmi index 2b5d8708c2e69b5ab17e40fce2d5389bfa5bf61b..c7c0cec7b06cfd291dd8be8d2d476377fdaa5b15 100644 GIT binary patch literal 930 zcmeAS@N?(olHy`uVBq!ia0vp^4M3d0!3HF+R#kZdslKX^h!U67;^d;tf|AVqJO+je z#@_yoT!$P4TwdQ@A2BJeXW7Z{7DTTFYNZMKvX*u(PtZSs{HDyJVEdnWf;iS>}gq-QJKcBuDlddao_ zz{8WP|M|X7cvE*#ptx{K=IxL~&)oZa?DsH)HCZo~U0d~-fr06~r;B4q#jUq<4Eqil z2r$f5Z#crPv7oi9OKu;dsSR7!54JBMAs3tuvQK!xX(@Jc($wY$rE?xnIb)(Q_wm-f zkGHPp=xmIdyn%&-0T(P4N!WaI$=kBqCA(v{YAnC3xi>~H%|?#hJMFiC$=?$@o*I|D zsr<{w#$3EN?*2FJqo*{PRyxlhLEPC~nWX<(Dh#t{?lhieXmli+B4ZL>=s$A9JUMHtgByxm)S; zwQrf9MYb~CI4Zu`seHkkNf%UZOj5g+y>{Df*LkP4uP=1Eb$8p{yn5ZTi zk8bT8^F^1R*-(aWL>dN%)`%=4{c zL-M6C>-XNFC-x^AiY@kF)l`;zcl1Z-|5UFJ>)!h(YpF1VNV7OFkP266>SkvqtDmKV~QXSmT0> z_N>QRY(nQ{r>m%5+Y|rvkZ*-qSqbAOAN^Z?&Cen(%7ky6EU&CsFFSejre_KaOvFQn zudEZyi%s%xW!z?F`t$n7R&jzopr0D-P_%K!iX literal 453 zcmV;$0XqJPP)NMiDCOS}&mV0;cK(s_ELqxF=nB|0C3npyLnK zq}|laTkvIY-rx!tBZx!e1vvHy7YJ^J=WiE=boZ;s<`Wb2Er%r)YlK{Ete!$sJ z5Crj`%$|U4xI%&+7T5Uh0ccUZDez8sIvZq*12{2OK1M;J^?j7qC@gjBy#A%cVe#qu vCkTT0G3~A`gj{avkHX5=l^NfhKpdVIt|S-njTx1@00000NkvXXu0mjfQpv;( diff --git a/modular_skyrat/modules/GAGS/icons/credit.md b/modular_skyrat/modules/GAGS/icons/credit.md new file mode 100644 index 00000000000..9b9846c2139 --- /dev/null +++ b/modular_skyrat/modules/GAGS/icons/credit.md @@ -0,0 +1 @@ +catglove.cmi and catglove_worn.dmi by Online! (Discord) 🩵 \ No newline at end of file diff --git a/modular_skyrat/modules/GAGS/icons/magpaws.dmi b/modular_skyrat/modules/GAGS/icons/magpaws.dmi new file mode 100644 index 0000000000000000000000000000000000000000..13ed07e5f197aa8d78fb94bf68997eff0526de6a GIT binary patch literal 3022 zcmV;<3o-PGP)XLP`R5c*j_j5{Zt(K>rc^}C>#nY@+1c5BeSPlk z?lCbjQBhIS($bBMjqB^{M@L7ZqN3E))UmO#z`(#H49O$_0004WQchCV=-0C=38lgkc*Fc3x8^eY1;S6LBn%hnqWF1LCJVg>OMdXnwevm zLUDp7Btgy_WWOds$g!@gm-tc8RX8O|*6a9v&R!y%Q%f+{LY#bQ4+IW^Om;@gOUyJQ!@D zf8KZw)b*jR8ZW9}-`DDRHQASXOwyNYSH`8P0bOOw?ib$xcVHm-A4bt&000UlNkl4K`f5+n&Ahtb0#`f;51f6v?9VM#(*9TDet{ZN8UNYR}I%8(#nFc=I5V=07? zQoXwnFN6rgD2j>U>6G{lL@@sI;UU8~`tv76h9@D06o6kCl8Y1R`T4lOz{Fz9FpZ)# zl?vDiX)sVaazlbh68Keq5J4d^FctDh<5;4TgjDjYqo5jt1bz!uqQVduetir>Au%vx z9hg!gi4YimeYF%+W1tlHj`)Q#>3=>vgoMD1V<8koVkpn&SV*Cy`jWaqLB~cBPy_P# zgRY38`}yz?7?=uL4G~8%5QJt%V32lQhEi!7C&Ub@9@Rr2YWFCK>CVLC+gStHxhN$3 zW|P@tS)p0MK#b6X=W|Lfl%0=6f|mfH68gf+Aq^KM7inZDFM~29%Iseu*ga*m@)(6D z^Xc>J$V<-&24V!&4+zGdD-5e&ce2-~L2IFg~3mRx}7#iIuE9SX+R>8J(>tpq&td1H$eMiNHJp z*T5n;FmUpi;5W>C`ur4_QpFIL>IAK+XnOO`fZEVlf&pd&tqeNPDF|jM(msiH2+5Wq$&YKZ{rYMc62CSu^Bf44WkEYvGTbU}H3VDzk@lc?6?D(n zNuO-Z&vVa4TeKc*2xeJP0K1&_WCgUQd1jYuEYa<}EYanYfxM+76a_cT$r0KoY(KR%3E50MAu>psvmw?`Xd6L)uId(5W_VU5_k}khG0ov1Lu(w zJF5ly-9~v!VS-{2w@81~{YIxh>cGS(Z63I<IYz~aTq-b5K@*p8%c+GP?Wb+m)ok~vZ zoVB6>s2)0K{c&)F6PQynkOwpX4XTPZp)$JB`En>HFeMFaOba(K*EKbT6PP&-Y&I8n z1CXIn@jNommcZ-+Ku{r956yZ{)OtE=9> zf1kq;0<-trm_&t%@mdCSZ4(bO*DiB15t1IO9 z_xEUOTOQAv8PI`=QCe$a>-inpgS8IK`-%?Yv!Da>PI39s1GU=u?tjpva0CO*3?#lk zZ7`#Quk8xVgbNs_ksoiL#qf^NS2s<^9s7X0)s7f}NzrBtt2+4& z?84zpaF<|NUX95s*MUKR^X9G#T;s_cF?{Ch?wOR`X05Ek71!pK1#1j~b{gaiMvf(c ztxJ)>=2%!7+$cQaoTqSwC)8#QmcoB532c4J71%nH`4IIUdjL!eY!iF8S-k<%0^7vi zZB`5hgTY`h7z_r3!C){L3C;Y(dwQZC7cEV50Km7F`dTCMtjKjm%z~K-CMLg4FEHH?G%>6qW>EF0 z9s+qyHItxbM2jDqU%1SL1AgsdV%WyuQoiIsIOE77TqAhyS?deu7wR@N*PFN=EXL-# z8Jc&ff{!U54(1oS*Y4-$7kWNT+ zaAGfbe@uu5eOgE#tJ6so`^cLtz!DGSvLMyp_exVP#mBB?rk(rLu zjaiN2$EFW%Ky$hZ9a(K#qw3giWNn9{U3zQ{!%^T1yz2vxzKe;485iMJ*Ff-gyB(Dy z`s}Io@9nnc`MqXd}i?FkH#b7WP3= 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 [lights_on ? "ON" : "OFF"]. \[Toggle\]") + +/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." diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm index a7253d276ef..0d842d7f221 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_helpers/human.dm @@ -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)) diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm index 0b5155e6cd3..fd68b0c3118 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm @@ -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 diff --git a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm index bf075cf3e9e..34ec651693e 100644 --- a/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm +++ b/modular_skyrat/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm @@ -124,6 +124,7 @@ //hands /obj/item/clothing/gloves/ball_mittens = 8, + /obj/item/clothing/gloves/ball_mittens/loadout_paw = 5, ), ), list( diff --git a/modular_zubbers/code/_globalvars/lists/erp_items.dm b/modular_zubbers/code/_globalvars/lists/erp_items.dm index 20a9a4be496..cd9795ad789 100644 --- a/modular_zubbers/code/_globalvars/lists/erp_items.dm +++ b/modular_zubbers/code/_globalvars/lists/erp_items.dm @@ -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, diff --git a/modular_zubbers/code/modules/clothing/gloves/misc.dm b/modular_zubbers/code/modules/clothing/gloves/misc.dm index 7eb04b29d49..215d6ccd81f 100644 --- a/modular_zubbers/code/modules/clothing/gloves/misc.dm +++ b/modular_zubbers/code/modules/clothing/gloves/misc.dm @@ -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 [lights_on ? "ON" : "OFF"]. \[Toggle\]") + +/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. diff --git a/modular_zubbers/code/modules/loadout/categories/gloves.dm b/modular_zubbers/code/modules/loadout/categories/gloves.dm index 1c4e067803d..5e7534286dd 100644 --- a/modular_zubbers/code/modules/loadout/categories/gloves.dm +++ b/modular_zubbers/code/modules/loadout/categories/gloves.dm @@ -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 */ diff --git a/modular_zubbers/code/modules/loadout/categories/toys.dm b/modular_zubbers/code/modules/loadout/categories/toys.dm index 59b3907e29d..21073b5d61e 100644 --- a/modular_zubbers/code/modules/loadout/categories/toys.dm +++ b/modular_zubbers/code/modules/loadout/categories/toys.dm @@ -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