mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-25 22:19:30 +01:00
Horse bridles (#5162)
## About The Pull Request This has been more or less in the works for a bit. This PR adds a horse bridle to the game. It's worn on the face/mask slot, and can be found in the loadout menu (under Masks) or in the lustwish vendor (under Restraints). It includes blinders and a bit, which will blind and gag the wearer, respectively. By default both are inactive. Interacting with it by alt clicking will cycle through a few modes: Blinders + Bit, Blinders, Bit, None. When worn you can also set them individually (though the alt click cycling still works). The blinders and the bit can also be cycled by others with the strip menu; this will take 4 seconds. To avoid this from happening, you can interact with the bridle in your hand to secure the straps. This will also prevent you from setting them yourself; you will have to unsecure the straps for it. ## Why It's Good For The Game It's a very neat addition for equine characters and for people into horse stuff. It's not necessarily an ERP item (in my opinion as much of an ERP item as the collars) so I haven't set it as an ERP item specifically, but I can change it if you think that would be better. ## Proof Of Testing File is too big for github https://files.catbox.moe/31vy7y.mp4 ## Changelog 🆑 add: Added horse bridles to the loadout menu and the lustwish vendors. They come equipped with settable blinders and bit. /🆑
This commit is contained in:
@@ -0,0 +1,340 @@
|
||||
|
||||
/obj/item/clothing/mask/bridle
|
||||
name = "bridle"
|
||||
desc = "A Sunny Stables design of a leather horse bridle, complete with blinders and a bit. It's made of several leather straps and metal fittings. You can tighten or loosen the straps to make sure that the blinders and the bit stay in place."
|
||||
icon_state = "bridle"
|
||||
inhand_icon_state = "sechailer"
|
||||
icon = 'modular_zubbers/icons/obj/clothing/mask/mask.dmi'
|
||||
worn_icon = 'modular_zubbers/icons/mob/clothing/mask/mask.dmi'
|
||||
worn_icon_state = "bridle"
|
||||
throwforce = 0
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
flags_cover = NONE
|
||||
actions_types = list(
|
||||
/datum/action/item_action/bridle_toggle_blinders,
|
||||
/datum/action/item_action/bridle_toggle_gag,
|
||||
)
|
||||
action_slots = ITEM_SLOT_MASK
|
||||
var/blinders_enabled = FALSE
|
||||
var/gag_enabled = FALSE
|
||||
var/blinders_tint = 2
|
||||
var/last_blinders_enabled = FALSE
|
||||
var/last_gag_enabled = FALSE
|
||||
var/straps_locked = FALSE
|
||||
var/strip_adjust_delay = 4 SECONDS
|
||||
|
||||
/obj/item/clothing/mask/bridle/Initialize(mapload)
|
||||
. = ..()
|
||||
update_bridle_state()
|
||||
|
||||
/obj/item/clothing/mask/bridle/Destroy()
|
||||
var/mob/living/carbon/wearer = get_wearer()
|
||||
if(wearer)
|
||||
remove_gag(wearer)
|
||||
wearer.update_tint()
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/mask/bridle/equipped(mob/living/carbon/user, slot)
|
||||
. = ..()
|
||||
if(!(slot & ITEM_SLOT_MASK))
|
||||
return
|
||||
playsound(user, 'sound/items/equip/toolbelt_equip.ogg', 50, TRUE)
|
||||
update_bridle_state(user)
|
||||
user.update_action_buttons()
|
||||
|
||||
/obj/item/clothing/mask/bridle/dropped(mob/living/carbon/user)
|
||||
. = ..()
|
||||
if(gag_enabled)
|
||||
remove_gag(user)
|
||||
if(blinders_enabled)
|
||||
user.update_tint()
|
||||
user.update_worn_mask()
|
||||
user.update_action_buttons()
|
||||
|
||||
/obj/item/clothing/mask/bridle/click_alt(mob/user)
|
||||
if(!istype(user) || user.incapacitated)
|
||||
return CLICK_ACTION_BLOCKING
|
||||
cycle_mode(user)
|
||||
return CLICK_ACTION_SUCCESS
|
||||
|
||||
/obj/item/clothing/mask/bridle/attack_self(mob/user)
|
||||
. = ..()
|
||||
if(!istype(user) || user.incapacitated)
|
||||
return
|
||||
straps_locked = !straps_locked
|
||||
if(straps_locked)
|
||||
to_chat(user, span_notice("You secure the bridle's straps."))
|
||||
else
|
||||
to_chat(user, span_notice("You loosen the bridle's straps."))
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/get_wearer()
|
||||
var/mob/living/carbon/wearer = istype(loc, /mob/living/carbon) ? loc : null
|
||||
if(wearer && wearer.get_item_by_slot(ITEM_SLOT_MASK) == src)
|
||||
return wearer
|
||||
return null
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/should_show_user_message(mob/user)
|
||||
if(!user)
|
||||
return FALSE
|
||||
return user.get_item_by_slot(ITEM_SLOT_MASK) != src
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/locked_message(mob/user)
|
||||
if(!user)
|
||||
return
|
||||
if(should_show_user_message(user))
|
||||
to_chat(user, span_notice("The straps are too secure to adjust."))
|
||||
else
|
||||
to_chat(user, span_warning("The straps are too secure!"))
|
||||
|
||||
/obj/item/clothing/mask/bridle/examine(mob/user)
|
||||
. = ..()
|
||||
var/blinders_state_text = blinders_enabled ? "down" : "up"
|
||||
var/gag_state_text = gag_enabled ? "set" : "unset"
|
||||
. += span_notice("The blinders are [blinders_state_text], and the bit is [gag_state_text].")
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/update_bridle_state(mob/user, notify_wearer = TRUE)
|
||||
var/mob/living/carbon/wearer = get_wearer()
|
||||
worn_icon_state = blinders_enabled ? "bridle_blinders" : "bridle"
|
||||
tint = blinders_enabled ? blinders_tint : 0
|
||||
flags_cover = gag_enabled ? MASKCOVERSMOUTH : NONE
|
||||
if(wearer)
|
||||
if(blinders_enabled != last_blinders_enabled)
|
||||
if(notify_wearer)
|
||||
var/blinders_action
|
||||
var/blinders_action_self
|
||||
var/blinders_effect
|
||||
var/blinders_self
|
||||
if(blinders_enabled)
|
||||
blinders_action = "lowers"
|
||||
blinders_action_self = "lower"
|
||||
blinders_effect = "obscuring your vision"
|
||||
blinders_self = "lower, obscuring your vision"
|
||||
else
|
||||
blinders_action = "raises"
|
||||
blinders_action_self = "raise"
|
||||
blinders_effect = "restoring your sight"
|
||||
blinders_self = "raise, restoring your sight"
|
||||
if(user && user != wearer)
|
||||
to_chat(wearer, span_userdanger("[user] [blinders_action] the bridle's blinders, [blinders_effect]."))
|
||||
else if(user)
|
||||
to_chat(wearer, span_notice("You [blinders_action_self] the bridle's blinders, [blinders_effect]."))
|
||||
else
|
||||
to_chat(wearer, span_notice("The bridle's blinders [blinders_self]."))
|
||||
last_blinders_enabled = blinders_enabled
|
||||
if(gag_enabled != last_gag_enabled)
|
||||
if(notify_wearer)
|
||||
var/gag_action
|
||||
var/gag_action_self
|
||||
var/gag_effect
|
||||
var/gag_self
|
||||
if(gag_enabled)
|
||||
gag_action = "sets"
|
||||
gag_action_self = "set"
|
||||
gag_effect = "muffling your speech"
|
||||
gag_self = "fits in your mouth, muffling your speech"
|
||||
else
|
||||
gag_action = "loosens"
|
||||
gag_action_self = "loosen"
|
||||
gag_effect = "letting you speak freely"
|
||||
gag_self = "loosens, allowing you to speak freely"
|
||||
if(user && user != wearer)
|
||||
to_chat(wearer, span_userdanger("[user] [gag_action] the bridle's bit, [gag_effect]."))
|
||||
else if(user)
|
||||
to_chat(wearer, span_notice("You [gag_action_self] the bridle's bit, [gag_effect]."))
|
||||
else
|
||||
to_chat(wearer, span_notice("The bridle's bit [gag_self]."))
|
||||
last_gag_enabled = gag_enabled
|
||||
wearer.update_tint()
|
||||
wearer.update_worn_mask()
|
||||
if(gag_enabled)
|
||||
apply_gag(wearer)
|
||||
else
|
||||
remove_gag(wearer)
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/toggle_blinders(mob/user)
|
||||
if(straps_locked)
|
||||
locked_message(user)
|
||||
return
|
||||
blinders_enabled = !blinders_enabled
|
||||
if(should_show_user_message(user))
|
||||
var/blinders_action
|
||||
if(blinders_enabled)
|
||||
blinders_action = "lower"
|
||||
else
|
||||
blinders_action = "raise"
|
||||
to_chat(user, span_notice("You [blinders_action] the bridle's blinders."))
|
||||
update_bridle_state(user)
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/toggle_gag(mob/user)
|
||||
if(straps_locked)
|
||||
locked_message(user)
|
||||
return
|
||||
gag_enabled = !gag_enabled
|
||||
if(should_show_user_message(user))
|
||||
var/gag_action
|
||||
if(gag_enabled)
|
||||
gag_action = "secure"
|
||||
else
|
||||
gag_action = "loosen"
|
||||
to_chat(user, span_notice("You [gag_action] the bridle's bit."))
|
||||
update_bridle_state(user)
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/cycle_mode(mob/user)
|
||||
if(straps_locked)
|
||||
locked_message(user)
|
||||
return
|
||||
if(!blinders_enabled && !gag_enabled)
|
||||
set_mode(TRUE, FALSE, user)
|
||||
return
|
||||
if(blinders_enabled && !gag_enabled)
|
||||
set_mode(FALSE, TRUE, user)
|
||||
return
|
||||
if(!blinders_enabled && gag_enabled)
|
||||
set_mode(TRUE, TRUE, user)
|
||||
return
|
||||
set_mode(FALSE, FALSE, user)
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/set_mode(new_blinders, new_gag, mob/user, notify_wearer = TRUE)
|
||||
if(straps_locked)
|
||||
locked_message(user)
|
||||
return
|
||||
blinders_enabled = new_blinders
|
||||
gag_enabled = new_gag
|
||||
if(user)
|
||||
var/balloon_state
|
||||
if(blinders_enabled && gag_enabled)
|
||||
balloon_state = "blinders + bit"
|
||||
else if(blinders_enabled)
|
||||
balloon_state = "blinders"
|
||||
else if(gag_enabled)
|
||||
balloon_state = "bit"
|
||||
else
|
||||
balloon_state = "none"
|
||||
if(should_show_user_message(user))
|
||||
balloon_alert(user, "mode: [balloon_state]")
|
||||
if(should_show_user_message(user))
|
||||
var/state_text
|
||||
if(blinders_enabled && gag_enabled)
|
||||
state_text = "blinders and bit"
|
||||
else if(blinders_enabled)
|
||||
state_text = "blinders"
|
||||
else if(gag_enabled)
|
||||
state_text = "bit"
|
||||
else
|
||||
state_text = "none"
|
||||
to_chat(user, span_notice("Bridle set to: [state_text]."))
|
||||
update_bridle_state(user, notify_wearer)
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/strip_adjust(mob/living/carbon/wearer, mob/living/stripper)
|
||||
if(!wearer || !stripper)
|
||||
return
|
||||
if(straps_locked)
|
||||
locked_message(stripper)
|
||||
return
|
||||
if(wearer.get_item_by_slot(ITEM_SLOT_MASK) != src)
|
||||
return
|
||||
if(!stripper.Adjacent(wearer))
|
||||
wearer.balloon_alert(stripper, "can't reach!")
|
||||
return
|
||||
if(!do_after(stripper, strip_adjust_delay, wearer))
|
||||
return
|
||||
var/old_blinders = blinders_enabled
|
||||
var/old_gag = gag_enabled
|
||||
var/new_blinders
|
||||
var/new_gag
|
||||
if(!blinders_enabled && !gag_enabled)
|
||||
new_blinders = TRUE
|
||||
new_gag = FALSE
|
||||
else if(blinders_enabled && !gag_enabled)
|
||||
new_blinders = FALSE
|
||||
new_gag = TRUE
|
||||
else if(!blinders_enabled && gag_enabled)
|
||||
new_blinders = TRUE
|
||||
new_gag = TRUE
|
||||
else
|
||||
new_blinders = FALSE
|
||||
new_gag = FALSE
|
||||
var/list/parts = list()
|
||||
if(old_blinders != new_blinders)
|
||||
parts += (new_blinders ? "lower the bridle's blinders" : "raise the bridle's blinders")
|
||||
if(old_gag != new_gag)
|
||||
parts += (new_gag ? "set the bridle's bit" : "loosen the bridle's bit")
|
||||
var/action_text = parts.len ? jointext(parts, " and ") : "adjust the bridle"
|
||||
to_chat(stripper, span_notice("You [action_text]."))
|
||||
set_mode(new_blinders, new_gag, stripper, TRUE)
|
||||
|
||||
/datum/strippable_item/mob_item_slot/mask/get_alternate_actions(atom/source, mob/user, obj/item/item)
|
||||
. = ..()
|
||||
var/obj/item/clothing/mask/bridle/bridle = item
|
||||
if(!istype(bridle))
|
||||
return
|
||||
. += "adjust_bridle"
|
||||
|
||||
/datum/strippable_item/mob_item_slot/mask/perform_alternate_action(atom/source, mob/user, action_key, obj/item/item)
|
||||
if(!..())
|
||||
return
|
||||
var/obj/item/clothing/mask/bridle/bridle = item
|
||||
if(!istype(bridle))
|
||||
return
|
||||
if(action_key == "adjust_bridle")
|
||||
bridle.strip_adjust(source, user)
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/apply_gag(mob/living/carbon/wearer)
|
||||
if(!wearer || wearer.get_item_by_slot(ITEM_SLOT_MASK) != src)
|
||||
return
|
||||
UnregisterSignal(wearer, list(COMSIG_MOB_SAY, COMSIG_MOB_PRE_EMOTED))
|
||||
RegisterSignal(wearer, COMSIG_MOB_SAY, PROC_REF(muzzle_talk))
|
||||
RegisterSignal(wearer, COMSIG_MOB_PRE_EMOTED, PROC_REF(emote_override))
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/remove_gag(mob/living/carbon/wearer)
|
||||
if(!wearer)
|
||||
return
|
||||
UnregisterSignal(wearer, list(COMSIG_MOB_SAY, COMSIG_MOB_PRE_EMOTED))
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/emote_override(mob/living/source, key, params, type_override, intentional, datum/emote/emote)
|
||||
SIGNAL_HANDLER
|
||||
if(emote.muzzle_ignore)
|
||||
return NONE
|
||||
if(emote.key in list("snort", "neigh", "neigh2")) //Can still do horse emotes because DUH
|
||||
return NONE
|
||||
if(!emote.hands_use_check && (emote.emote_type & EMOTE_AUDIBLE))
|
||||
source.audible_message("makes a [pick("strong ", "weak ", "")]noise.", audible_message_flags = EMOTE_MESSAGE|ALWAYS_SHOW_SELF_MESSAGE)
|
||||
return COMPONENT_CANT_EMOTE
|
||||
return NONE
|
||||
|
||||
/obj/item/clothing/mask/bridle/proc/muzzle_talk(datum/source, list/speech_args)
|
||||
SIGNAL_HANDLER
|
||||
if(HAS_TRAIT(source, TRAIT_SIGN_LANG))
|
||||
return
|
||||
var/spoken_message = speech_args[SPEECH_MESSAGE]
|
||||
if(spoken_message)
|
||||
var/list/words = splittext(spoken_message, " ")
|
||||
var/yell_suffix = copytext(spoken_message, findtext(spoken_message, "!"))
|
||||
spoken_message = ""
|
||||
|
||||
for(var/ind = 1 to length(words))
|
||||
var/new_word = ""
|
||||
for(var/i = 1 to length(words[ind]) + rand(-1,1))
|
||||
new_word += "m"
|
||||
new_word += "f"
|
||||
words[ind] = yell_suffix ? uppertext(new_word) : new_word
|
||||
spoken_message = "[jointext(words, " ")][yell_suffix]"
|
||||
speech_args[SPEECH_MESSAGE] = spoken_message
|
||||
|
||||
/datum/action/item_action/bridle_toggle_blinders
|
||||
name = "Toggle blinders"
|
||||
desc = "Adjust the bridle blinders."
|
||||
|
||||
/datum/action/item_action/bridle_toggle_blinders/Trigger(trigger_flags)
|
||||
var/obj/item/clothing/mask/bridle/bridle = target
|
||||
if(istype(bridle))
|
||||
bridle.toggle_blinders(owner)
|
||||
|
||||
/datum/action/item_action/bridle_toggle_gag
|
||||
name = "Toggle gag"
|
||||
desc = "Adjust the bridle bit."
|
||||
|
||||
/datum/action/item_action/bridle_toggle_gag/Trigger(trigger_flags)
|
||||
var/obj/item/clothing/mask/bridle/bridle = target
|
||||
if(istype(bridle))
|
||||
bridle.toggle_gag(owner)
|
||||
@@ -218,6 +218,10 @@
|
||||
item_path = /obj/item/clothing/mask/whistle
|
||||
restricted_roles = list(ALL_JOBS_SEC)
|
||||
|
||||
/datum/loadout_item/mask/utility/bridle
|
||||
name = "Bridle"
|
||||
item_path = /obj/item/clothing/mask/bridle
|
||||
|
||||
/*
|
||||
* COSTUMES
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
/obj/item/clothing/neck/human_petcollar/locked/ringbell = 8,
|
||||
/obj/item/clothing/neck/inferno_collar = 8,
|
||||
/obj/item/clothing/neck/flower_collar = 8,
|
||||
/obj/item/clothing/mask/bridle = 8,
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 956 B After Width: | Height: | Size: 1.1 KiB |
@@ -9514,6 +9514,7 @@
|
||||
#include "modular_zubbers\code\modules\languages\siikmaas.dm"
|
||||
#include "modular_zubbers\code\modules\languages\uncommon.dm"
|
||||
#include "modular_zubbers\code\modules\languages\vampiric.dm"
|
||||
#include "modular_zubbers\code\modules\lewd_machinery\bridle.dm"
|
||||
#include "modular_zubbers\code\modules\lewd_machinery\clicker.dm"
|
||||
#include "modular_zubbers\code\modules\lewd_machinery\lustwish.dm"
|
||||
#include "modular_zubbers\code\modules\lewd_machinery\sex_barrier.dm"
|
||||
|
||||
@@ -93,6 +93,11 @@ const ALTERNATE_ACTIONS: Record<string, AlternateAction> = {
|
||||
icon: 'ribbon',
|
||||
text: 'Strip accessory',
|
||||
},
|
||||
|
||||
adjust_bridle: {
|
||||
icon: 'mask',
|
||||
text: 'Adjust bridle',
|
||||
},
|
||||
};
|
||||
|
||||
const SLOTS: Record<
|
||||
|
||||
Reference in New Issue
Block a user