diff --git a/code/datums/looping_sounds/item_sounds.dm b/code/datums/looping_sounds/item_sounds.dm index 282f422bdf..5c7cb9679e 100644 --- a/code/datums/looping_sounds/item_sounds.dm +++ b/code/datums/looping_sounds/item_sounds.dm @@ -134,3 +134,16 @@ mid_length = 2 volume = 35 +/datum/looping_sound/hairbrush + mid_sounds = list( + SOUND_LOOP_ENTRY('sound/f13ambience/hairbrush/hairbrush_01.ogg', 3 SECONDS, 1), + SOUND_LOOP_ENTRY('sound/f13ambience/hairbrush/hairbrush_02.ogg', 3 SECONDS, 1), + SOUND_LOOP_ENTRY('sound/f13ambience/hairbrush/hairbrush_03.ogg', 3 SECONDS, 1), + SOUND_LOOP_ENTRY('sound/f13ambience/hairbrush/hairbrush_04.ogg', 3 SECONDS, 1), + SOUND_LOOP_ENTRY('sound/f13ambience/hairbrush/hairbrush_05.ogg', 3 SECONDS, 1), + SOUND_LOOP_ENTRY('sound/f13ambience/hairbrush/hairbrush_06.ogg', 3 SECONDS, 1), + SOUND_LOOP_ENTRY('sound/f13ambience/hairbrush/hairbrush_07.ogg', 8 SECONDS, 1), + SOUND_LOOP_ENTRY('sound/f13ambience/hairbrush/hairbrush_08.ogg', 8 SECONDS, 1), + ) + volume = 80 + diff --git a/code/game/objects/hand_items.dm b/code/game/objects/hand_items.dm index 64831ba581..e995c1a4d7 100644 --- a/code/game/objects/hand_items.dm +++ b/code/game/objects/hand_items.dm @@ -226,7 +226,15 @@ .[LICK_INTENT] = "aggressively" if(INTENT_HARM) .[LICK_INTENT] = "very aggressively" +/* +You take the item in hand. +The item + the intent + direction of click = outcome. +Example +Touch + Help + facing each other = Hug +Touch + help + facing their side = pat shoulder +touch + help + facing their rear = pat back +*/ #undef LICK_LOCATION #undef LICK_INTENT @@ -651,6 +659,12 @@ damtype = BURN attack_verb = list("seared", "zapped", "fried", "shocked") +/* * + * + */ + + + // /obj/item/hand_item/healable/licker/proc/bandage_wound(mob/living/licked, mob/living/carbon/user) // if(!iscarbon(licked)) // return FALSE diff --git a/fortune13.dme b/fortune13.dme index 34f8132b35..0d691151e1 100644 --- a/fortune13.dme +++ b/fortune13.dme @@ -3916,6 +3916,7 @@ #include "modular_coyote\code\creature_procs.dm" #include "modular_coyote\code\creature_species.dm" #include "modular_coyote\code\flora_coyote.dm" +#include "modular_coyote\code\hairbrush.dm" #include "modular_coyote\code\lewd.dm" #include "modular_coyote\code\mailbird.dm" #include "modular_coyote\code\mam_ears_coyote.dm" diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm index 55bfffcb50..c2912ebace 100644 --- a/modular_citadel/code/modules/client/loadout/backpack.dm +++ b/modular_citadel/code/modules/client/loadout/backpack.dm @@ -9,6 +9,11 @@ path = /obj/item/flashlight cost = 0 +/datum/gear/backpack/hairbrush + name = "hairbrush" + path = /obj/item/hairbrush + cost = 0 + /datum/gear/backpack/torch name = "torch" path = /obj/item/flashlight/flare/torch diff --git a/modular_coyote/code/hairbrush.dm b/modular_coyote/code/hairbrush.dm new file mode 100644 index 0000000000..77ffe55c07 --- /dev/null +++ b/modular_coyote/code/hairbrush.dm @@ -0,0 +1,195 @@ +// Hairbrushes + +/obj/item/hairbrush + name = "hairbrush" + desc = "A small, circular brush with an ergonomic grip for efficient brush application." + icon = 'modular_coyote/icons/objects/hairbrush/hairbrush.dmi' + icon_state = "brush" + item_state = "inhand" + lefthand_file = 'modular_coyote/icons/objects/hairbrush/inhand_left.dmi' + righthand_file = 'modular_coyote/icons/objects/hairbrush/inhand_right.dmi' + w_class = WEIGHT_CLASS_TINY + var/brush_speed = 3 SECONDS + var/am_brushing = FALSE + var/datum/looping_sound/hairbrush/fwhuush + var/last_brushed + var/vis_dist = 3 + + +/obj/item/hairbrush/Initialize() + . = ..() + fwhuush = new(list(src), FALSE) + +/obj/item/hairbrush/Destroy() + QDEL_NULL(fwhuush) + . = ..() + +/obj/item/hairbrush/attack(mob/target, mob/user) + . = COMPONENT_ITEM_NO_ATTACK + if(am_brushing) + to_chat(user, span_alert("You're already brushing!")) + return + brush(target, user) + +/obj/item/hairbrush/proc/abort(mob/target, mob/user) + am_brushing = FALSE + if(target && user) + to_chat(user, span_notice("You stop brushing.")) + to_chat(target, ("[user] stops brushing.")) + fwhuush.stop() + last_brushed = null + +/// Brushes someone, giving them a small mood boost +/obj/item/hairbrush/proc/brush(mob/living/target, mob/user, silent) + if(!ishuman(target)) + return abort() + var/mob/living/carbon/human/human_target = target + var/brush_where = user.zone_selected + var/brush_what = "hair" + var/through = "through" + switch(brush_where) + if(BODY_ZONE_HEAD) + var/obj/item/bodypart/head = human_target.get_bodypart(BODY_ZONE_HEAD) + if(!head) + to_chat(user, span_warning("[human_target] has no head!")) + return abort() + if(human_target.hair_style == "Bald" || human_target.hair_style == "Skinhead" && is_species(human_target, /datum/species/human)) //It can be assumed most anthros have hair on them! + brush_what = "scalp" + else + brush_what = "hair" + if(BODY_ZONE_PRECISE_EYES) + var/obj/item/bodypart/head = human_target.get_bodypart(BODY_ZONE_HEAD) + if(!head) + to_chat(user, span_warning("[human_target] has no head!")) + return abort() + brush_what = "ears" + through = "along" + if(BODY_ZONE_PRECISE_MOUTH) + var/obj/item/bodypart/head = human_target.get_bodypart(BODY_ZONE_HEAD) + if(!head) + to_chat(user, span_warning("[human_target] has no head!")) + return abort() + if(human_target.dna.features["snout"]) + brush_what = pick("muzzle", "snout", "cheeks") + else + brush_what = "cheeks" + through = "across" + if(BODY_ZONE_PRECISE_GROIN) + through = "across" + if(user.a_intent == INTENT_HARM) + smack_em_on_the_butt(user, human_target) + return abort() + else if(user.a_intent == INTENT_GRAB) + brush_what = "crotch" + else if(user.a_intent == INTENT_DISARM) + brush_what = "belly" + else if(human_target.dna.features["tail_lizard"] \ + || human_target.dna.features["tail_mam"] \ + || human_target.dna.features["tails_list_human"]) // FUCK YOU POOJ WHY DO WE HAVE THREE FUCKIN TAILS THATA ARE THE EXACT SAME FUCKING THING AFUIUCK YOU FUCK YOU (🐾 teehee) + brush_what = pick("tail") + through = "along" + else + brush_what = "tummy" + if(BODY_ZONE_CHEST) + through = "down" + var/obj/item/organ/genital/b00bz = human_target.getorganslot(ORGAN_SLOT_BREASTS) + if(b00bz && b00bz.is_exposed() && wielded) + switch(user.a_intent) + if(INTENT_HELP) + brush_what = "breasts, softly" + if(INTENT_DISARM) + brush_what = "breasts, sensually" + if(INTENT_GRAB) + brush_what = "breasts, firmly" + if(INTENT_HARM) + brush_what = "breasts, vigorously" + else + if(wielded) + brush_what = "back" + else + brush_what = "chest" + if(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) + through = "along" + switch(user.a_intent) + if(INTENT_HELP) + brush_what = "arm" + if(INTENT_DISARM) + brush_what = "wrist" + if(INTENT_GRAB) + brush_what = "shoulder" + if(INTENT_HARM) + brush_what = prob(1) ? "weenis" : "hand" + if(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + through = "along" + switch(user.a_intent) + if(INTENT_HELP) + brush_what = "hip" + if(INTENT_DISARM) + brush_what = "thigh" + if(INTENT_GRAB) + brush_what = "knee" + if(INTENT_HARM) + brush_what = prob(50) ? "foot" : "ankle" + am_brushing = TRUE + fwhuush.start() + if(last_brushed != brush_what) + if(user == human_target) + user.visible_message( + span_notice("[user] starts to run [src] [through] [user.p_their()] [brush_what]..."), + span_notice("You start running [src] [through] your [brush_what]..."), + span_notice("[user] starts to run [src] [through] [user.p_their()] [brush_what]..."), + vis_dist, + ) + else + user.visible_message( + span_notice("[user] starts to run [src] [through] [human_target]'s [brush_what]..."), + span_notice("You start running [src] [through] [human_target]'s [brush_what]..."), + span_notice("[user] starts to run [src] [through] [human_target]'s [brush_what]..."), + vis_dist, + ) + if(!do_after(user, brush_speed, TRUE, human_target)) + return abort(human_target, user) + if(last_brushed != brush_what) + if(human_target == user) + user.visible_message( + span_notice("[user] brushes [user.p_their()] [brush_what]!"), + span_notice("You brush your [brush_what]!"), + span_notice("[user] brushes [user.p_their()] [brush_what]!"), + vis_dist, + ) + else + user.visible_message( + span_notice("[user] brushes [human_target]'s [brush_what]!"), + span_notice("You brush [human_target]'s [brush_what]!"), + span_notice("[user] brushes [human_target]'s [brush_what]!"), + vis_dist, + ) + last_brushed = brush_what + brush(target, user, TRUE) + +/obj/item/hairbrush/proc/smack_em_on_the_butt(mob/user, mob/target) + if(target.stat == DEAD) + to_chat(user, span_alert("They're already dead!")) + return + if(user == target) + user.visible_message( + span_alert("[user] WHAPS [user.p_their()] ass with the back of [src]!"), + span_userdanger("You WHAP yourself on the ass with the back of your [src.name]!"), + span_alert("[user] WHAPS [user.p_their()] ass with the back of [src]!"), + vis_dist, + ) + else + user.visible_message( + span_alert("[user] WHAPS [target] on the ass with the back of [src]!"), + span_alert("You WHAP [user] on the ass with the back of your [src.name]!"), + span_alert("[user] WHAPS [target] on the ass with the back of [src]!"), + vis_dist, + ignored_mobs = list(target),//k + ) + var/thespan = "userdanger" + if(HAS_TRAIT(target, TRAIT_MASO)) + thespan = "love" + else //i helped, fenny, 2024 + thespan = "userdanger" + to_chat(target, "[user] WHAPS you on the ass with the hard end of [user.p_their()] [src.name]!!") + playsound(target.loc, 'sound/weapons/slap.ogg', 25, FALSE, -1) // deep bassy ass diff --git a/modular_coyote/icons/objects/hairbrush/hairbrush.dmi b/modular_coyote/icons/objects/hairbrush/hairbrush.dmi new file mode 100644 index 0000000000..f44763ce5a Binary files /dev/null and b/modular_coyote/icons/objects/hairbrush/hairbrush.dmi differ diff --git a/modular_coyote/icons/objects/hairbrush/inhand_left.dmi b/modular_coyote/icons/objects/hairbrush/inhand_left.dmi new file mode 100644 index 0000000000..fb1ad0b7f2 Binary files /dev/null and b/modular_coyote/icons/objects/hairbrush/inhand_left.dmi differ diff --git a/modular_coyote/icons/objects/hairbrush/inhand_right.dmi b/modular_coyote/icons/objects/hairbrush/inhand_right.dmi new file mode 100644 index 0000000000..cc77470c7c Binary files /dev/null and b/modular_coyote/icons/objects/hairbrush/inhand_right.dmi differ diff --git a/modular_coyote/icons/objects/pillow/pillow.dm b/modular_coyote/icons/objects/pillow/pillow.dm new file mode 100644 index 0000000000..f699dd34b3 --- /dev/null +++ b/modular_coyote/icons/objects/pillow/pillow.dm @@ -0,0 +1,223 @@ +//Pillow and pillow related items +/obj/item/pillow + name = "pillow" + desc = "A soft and fluffy pillow. You can smack someone with this!" + icon = 'icons/obj/bed.dmi' + icon_state = "pillow_1_t" + inhand_icon_state = "pillow_t" + lefthand_file = 'icons/mob/inhands/items/pillow_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items/pillow_righthand.dmi' + force = 5 + w_class = WEIGHT_CLASS_NORMAL + damtype = STAMINA + ///change the description based on the pillow tag + var/static/tag_desc = "This one seems to have its tag removed." + ///pillow tag is attached to it + var/obj/item/clothing/neck/pillow_tag/pillow_trophy + ///whoever last use this pillow + var/last_fighter + ///for selecting the various sprite variation, defaults to the blank white pillow + var/variation = 1 + ///for alternating between hard hitting sound vs soft hitting sound + var/hit_sound + ///if we have a brick inside us + var/bricked = FALSE + +/obj/item/pillow/Initialize(mapload) + . = ..() + if(!pillow_trophy) + pillow_trophy = new(src) + AddComponent(/datum/component/two_handed, \ + force_unwielded = 5, \ + force_wielded = 10, \ + ) + AddElement(/datum/element/disarm_attack) + + var/static/list/slapcraft_recipe_list = list(\ + /datum/crafting_recipe/pillow_suit, /datum/crafting_recipe/pillow_hood,\ + ) + + AddElement( + /datum/element/slapcrafting,\ + slapcraft_recipes = slapcraft_recipe_list,\ + ) + +/obj/item/pillow/Destroy(force) + . = ..() + QDEL_NULL(pillow_trophy) + +/obj/item/pillow/attack(mob/living/carbon/target_mob, mob/living/user, params) + . = ..() + if(!iscarbon(target_mob)) + return + if(bricked || HAS_TRAIT(src, TRAIT_WIELDED)) + hit_sound = 'sound/items/pillow_hit2.ogg' + else + hit_sound = 'sound/items/pillow_hit.ogg' + user.apply_damage(5, STAMINA) //Had to be done so one person cannot keep multiple people stam critted + last_fighter = user + playsound(user, hit_sound, 80) //the basic 50 vol is barely audible + +/obj/item/pillow/attack_secondary(mob/living/carbon/victim, mob/living/user, params) + . = ..() + if(!istype(victim)) + return + if(victim.is_mouth_covered() || !victim.get_bodypart(BODY_ZONE_HEAD)) + return + if(HAS_TRAIT(user, TRAIT_PACIFISM)) + to_chat(user, span_notice("You can't bring yourself to harm [victim]")) + return + if((victim.body_position == LYING_DOWN) || ((user.grab_state >= GRAB_AGGRESSIVE) && (user.pulling == victim))) + user.visible_message("[user] starts to smother [victim]", span_notice("You begin smothering [victim]"), vision_distance = COMBAT_MESSAGE_RANGE) + INVOKE_ASYNC(src, PROC_REF(smothering), user, victim) + +/obj/item/pillow/attackby(obj/item/attacking_item, mob/user, params) + if(!bricked && istype(attacking_item, /obj/item/stack/sheet/mineral/sandstone)) + var/obj/item/stack/sheet/mineral/sandstone/brick = attacking_item + balloon_alert(user, "inserting brick...") + if(!do_after(user, 2 SECONDS, src)) + return + if(!brick.use(1)) + balloon_alert(user, "not enough bricks!") + return + balloon_alert(user, "bricked!") + become_bricked() + return + if(istype(attacking_item, /obj/item/clothing/neck/pillow_tag)) + if(!pillow_trophy) + user.transferItemToLoc(attacking_item, src) + pillow_trophy = attacking_item + balloon_alert(user, "honor reclaimed!") + update_appearance() + return + else + balloon_alert(user, "tag is intact.") + return + return ..() + +/obj/item/pillow/examine(mob/user) + . = ..() + if(bricked) + . += span_info("[p_They()] feel[p_s()] unnaturally heavy.") + if(pillow_trophy) + . += span_notice("Alt-click to remove the tag!") + +/obj/item/pillow/click_alt(mob/user) + if(!user.can_hold_items(src)) + return CLICK_ACTION_BLOCKING + if(!pillow_trophy) + balloon_alert(user, "no tag!") + return CLICK_ACTION_BLOCKING + balloon_alert(user, "removing tag...") + if(!do_after(user, 2 SECONDS, src)) + return CLICK_ACTION_BLOCKING + if(last_fighter) + pillow_trophy.desc = "A pillow tag taken from [last_fighter] after a gruesome pillow fight." + user.put_in_hands(pillow_trophy) + pillow_trophy = null + balloon_alert(user, "tag removed") + playsound(user,'sound/items/poster_ripped.ogg', 50) + update_appearance() + return CLICK_ACTION_SUCCESS + +/obj/item/pillow/update_appearance(updates) + . = ..() + if(!pillow_trophy) + desc = "A soft and fluffy pillow. You can smack someone with this! [tag_desc]" + icon_state = "pillow_[variation]" + inhand_icon_state = "pillow_no_t" + else + desc = "A soft and fluffy pillow. You can smack someone with this!" + icon_state = "pillow_[variation]_t" + inhand_icon_state = "pillow_t" + +/// Puts a brick inside the pillow, increasing it's damage +/obj/item/pillow/proc/become_bricked() + bricked = TRUE + var/datum/component/two_handed/two_handed = GetComponent(/datum/component/two_handed) + if(two_handed) + AddComponent(/datum/component/two_handed, force_unwielded = two_handed.force_unwielded + 5, force_wielded = two_handed.force_wielded + 10) + force += 5 + update_appearance() + +/// Smothers the victim while the do_after succeeds and the victim is laying down or being strangled +/obj/item/pillow/proc/smothering(mob/living/carbon/user, mob/living/carbon/victim) + while(victim) + if((victim.body_position != LYING_DOWN) && ((user.grab_state < GRAB_AGGRESSIVE) || (user.pulling != victim))) + break + if(!do_after(user, 1 SECONDS, victim)) + break + victim.losebreath += 1 + victim.visible_message("[victim] manages to escape being smothered!", span_notice("You break free!"), vision_distance = COMBAT_MESSAGE_RANGE) + +/obj/item/pillow/random + +/obj/item/pillow/random/Initialize(mapload) + . = ..() + variation = rand(1, 4) + icon_state = "pillow_[variation]_t" + //random pillows spawn bricked sometimes, fuck you + if(prob(1)) + become_bricked() + +/obj/item/clothing/suit/pillow_suit + name = "pillow suit" + desc = "Part man, part pillow. All CARNAGE!" + body_parts_covered = CHEST|GROIN|ARMS|LEGS|FEET + cold_protection = CHEST|GROIN|ARMS|LEGS //a pillow suit must be hella warm + allowed = list(/obj/item/pillow) //moar pillow carnage + icon = 'icons/obj/bed.dmi' + worn_icon = 'icons/mob/clothing/suits/pillow.dmi' + icon_state = "pillow_suit" + armor_type = /datum/armor/suit_pillow_suit + var/obj/item/pillow/unstoppably_plushed + +/datum/armor/suit_pillow_suit + melee = 5 + acid = 75 + +/obj/item/clothing/suit/pillow_suit/Initialize(mapload) + . = ..() + unstoppably_plushed = new(src) + AddComponent(/datum/component/bumpattack, proxy_weapon = unstoppably_plushed, valid_inventory_slot = ITEM_SLOT_OCLOTHING) + +/obj/item/clothing/suit/pillow_suit/Destroy() + . = ..() + QDEL_NULL(unstoppably_plushed) + +/obj/item/clothing/head/pillow_hood + name = "pillow hood" + desc = "The final piece of the pillow juggernaut" + body_parts_covered = HEAD + icon = 'icons/obj/bed.dmi' + worn_icon = 'icons/mob/clothing/suits/pillow.dmi' + icon_state = "pillowcase_hat" + body_parts_covered = HEAD + flags_inv = HIDEHAIR|HIDEEARS + armor_type = /datum/armor/head_pillow_hood + +/datum/armor/head_pillow_hood + melee = 5 + acid = 75 + +/obj/item/clothing/neck/pillow_tag + name = "pillow tag" + desc = "A price tag for the pillow. It appears to have space to fill names in." + icon = 'icons/obj/bed.dmi' + icon_state = "pillow_tag" + worn_icon = 'icons/mob/clothing/neck.dmi' + worn_icon_state = "pillow_tag" + body_parts_covered = NECK + +/obj/item/pillow/clown + name = "clown pillow" + desc = "Daww look at that little clown!" + icon_state = "pillow_5_t" + variation = 5 + +/obj/item/pillow/mime + name = "mime pillow" + desc = "Daww look at that little mime!" + icon_state = "pillow_6_t" + variation = 6 + diff --git a/modular_coyote/icons/objects/pillow/pillow_lefthand.dmi b/modular_coyote/icons/objects/pillow/pillow_lefthand.dmi new file mode 100644 index 0000000000..af23abae63 Binary files /dev/null and b/modular_coyote/icons/objects/pillow/pillow_lefthand.dmi differ diff --git a/modular_coyote/icons/objects/pillow/pillow_righthand.dmi b/modular_coyote/icons/objects/pillow/pillow_righthand.dmi new file mode 100644 index 0000000000..3508e9e3e0 Binary files /dev/null and b/modular_coyote/icons/objects/pillow/pillow_righthand.dmi differ diff --git a/sound/effects/comfyfire.ogg b/sound/effects/comfyfire.ogg index 1bc7fc02d0..7f51644cae 100644 Binary files a/sound/effects/comfyfire.ogg and b/sound/effects/comfyfire.ogg differ diff --git a/sound/f13ambience/hairbrush/hairbrush_01.ogg b/sound/f13ambience/hairbrush/hairbrush_01.ogg new file mode 100644 index 0000000000..75607d69fa Binary files /dev/null and b/sound/f13ambience/hairbrush/hairbrush_01.ogg differ diff --git a/sound/f13ambience/hairbrush/hairbrush_02.ogg b/sound/f13ambience/hairbrush/hairbrush_02.ogg new file mode 100644 index 0000000000..a3fe547602 Binary files /dev/null and b/sound/f13ambience/hairbrush/hairbrush_02.ogg differ diff --git a/sound/f13ambience/hairbrush/hairbrush_03.ogg b/sound/f13ambience/hairbrush/hairbrush_03.ogg new file mode 100644 index 0000000000..94a19a3f95 Binary files /dev/null and b/sound/f13ambience/hairbrush/hairbrush_03.ogg differ diff --git a/sound/f13ambience/hairbrush/hairbrush_04.ogg b/sound/f13ambience/hairbrush/hairbrush_04.ogg new file mode 100644 index 0000000000..44fbb2e840 Binary files /dev/null and b/sound/f13ambience/hairbrush/hairbrush_04.ogg differ diff --git a/sound/f13ambience/hairbrush/hairbrush_05.ogg b/sound/f13ambience/hairbrush/hairbrush_05.ogg new file mode 100644 index 0000000000..2aa8815c39 Binary files /dev/null and b/sound/f13ambience/hairbrush/hairbrush_05.ogg differ diff --git a/sound/f13ambience/hairbrush/hairbrush_06.ogg b/sound/f13ambience/hairbrush/hairbrush_06.ogg new file mode 100644 index 0000000000..6dbc64ee35 Binary files /dev/null and b/sound/f13ambience/hairbrush/hairbrush_06.ogg differ diff --git a/sound/f13ambience/hairbrush/hairbrush_07.ogg b/sound/f13ambience/hairbrush/hairbrush_07.ogg new file mode 100644 index 0000000000..13912a0cf7 Binary files /dev/null and b/sound/f13ambience/hairbrush/hairbrush_07.ogg differ diff --git a/sound/f13ambience/hairbrush/hairbrush_08.ogg b/sound/f13ambience/hairbrush/hairbrush_08.ogg new file mode 100644 index 0000000000..8ed18a05ac Binary files /dev/null and b/sound/f13ambience/hairbrush/hairbrush_08.ogg differ