diff --git a/code/__DEFINES/clothing.dm b/code/__DEFINES/clothing.dm index 1d87f8845c8..69561ee97ef 100644 --- a/code/__DEFINES/clothing.dm +++ b/code/__DEFINES/clothing.dm @@ -88,3 +88,8 @@ #define BLOCKHAIR 32768 // temporarily removes the user's hair, facial and otherwise. #define ONESIZEFITSALL 1 // determines if something can be worn by a fatty or not. + +//flags for muzzle speech blocking +#define MUTE_NONE 0 // Does not mute you. +#define MUTE_MUFFLE 1 // Muffles everything you say "MHHPHHMMM!!! +#define MUTE_ALL 2 // Completely mutes you. \ No newline at end of file diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm index 94b75646bf5..1923a0e1321 100644 --- a/code/game/gamemodes/vampire/vampire.dm +++ b/code/game/gamemodes/vampire/vampire.dm @@ -275,6 +275,10 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha var/blood = 0 var/old_bloodtotal = 0 //used to see if we increased our blood total var/old_bloodusable = 0 //used to see if we increased our blood usable + var/muzzle = H.is_muzzled() + if(muzzle) + to_chat(owner, "[muzzle] prevents you from biting [H]!") + return owner.create_attack_log("Bit [H] ([H.ckey]) in the neck and draining their blood") H.create_attack_log("Has been bit in the neck by [owner] ([owner.ckey])") log_attack("[owner] ([owner.ckey]) bit [H] ([H.ckey]) in the neck") diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 5b1211a7394..dadfad2985a 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -951,7 +951,8 @@ icon_deny = "sec-deny" req_access_txt = "1" products = list(/obj/item/weapon/restraints/handcuffs = 8,/obj/item/weapon/restraints/handcuffs/cable/zipties = 8,/obj/item/weapon/grenade/flashbang = 4,/obj/item/device/flash = 5, - /obj/item/weapon/reagent_containers/food/snacks/donut = 12,/obj/item/weapon/storage/box/evidence = 6,/obj/item/device/flashlight/seclite = 4,/obj/item/weapon/restraints/legcuffs/bola/energy = 7) + /obj/item/weapon/reagent_containers/food/snacks/donut = 12,/obj/item/weapon/storage/box/evidence = 6,/obj/item/device/flashlight/seclite = 4,/obj/item/weapon/restraints/legcuffs/bola/energy = 7, + /obj/item/clothing/mask/muzzle/safety = 4) contraband = list(/obj/item/clothing/glasses/sunglasses = 2,/obj/item/weapon/storage/fancy/donut_box = 2,/obj/item/device/hailer = 5) /obj/machinery/vending/hydronutrients diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index 8b0bb40597e..fffd9453f7a 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -8,7 +8,9 @@ gas_transfer_coefficient = 0.90 put_on_delay = 20 var/resist_time = 0 //deciseconds of how long you need to gnaw to get rid of the gag, 0 to make it impossible to remove - var/mute = 1 // 1 - completely mutes you, 0 - muffles everything you say "MHHPHHMMM!!!" + var/mute = MUTE_ALL + var/security_lock = FALSE // Requires brig access to remove 0 - Remove as normal + var/locked = FALSE //Indicates if a mask is locked, should always start as 0. species_fit = list("Vox") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi' @@ -18,7 +20,65 @@ /obj/item/clothing/mask/muzzle/attack_hand(mob/user as mob) if(user.wear_mask == src && !user.IsAdvancedToolUser()) return 0 + else if(security_lock && locked) + if(do_unlock(user)) + visible_message("[user] unlocks their [src.name].", \ + "[user] unlocks their [src.name].") ..() + return 1 + +/obj/item/clothing/mask/muzzle/proc/do_break() + if(security_lock) + security_lock = FALSE + locked = FALSE + flags &= ~NODROP + desc += " This one appears to be broken." + return TRUE + else + return FALSE + +/obj/item/clothing/mask/muzzle/proc/do_unlock(mob/living/carbon/human/user) + if(istype(user.get_inactive_hand(), /obj/item/weapon/card/emag)) + to_chat(user, "The lock vibrates as the card forces its locking system open.") + do_break() + return TRUE + else if(access_brig in user.get_access()) + to_chat(user, "The muzzle unlocks with a click.") + locked = FALSE + flags &= ~NODROP + return TRUE + + to_chat(user, "You must be wearing a security ID card or have one in your inactive hand to remove the muzzle.") + return FALSE + +/obj/item/clothing/mask/muzzle/proc/do_lock(mob/living/carbon/human/user) + if(security_lock) + locked = TRUE + flags |= NODROP + return TRUE + return FALSE + +/obj/item/clothing/mask/muzzle/Topic(href, href_list) + ..() + if(href_list["locked"]) + var/mob/living/carbon/wearer = locate(href_list["locked"]) + var/success = 0 + if(ishuman(usr)) + visible_message("[usr] tries to [locked ? "unlock" : "lock"] [wearer]'s [name].", \ + "[usr] tries to [locked ? "unlock" : "lock"] [wearer]'s [name].") + if(do_mob(usr, wearer, POCKET_STRIP_DELAY)) + if(locked) + success = do_unlock(usr) + else + success = do_lock(usr) + if(success) + visible_message("[usr] [locked ? "locks" : "unlocks"] [wearer]'s [name].", \ + "[usr] [locked ? "locks" : "unlocks"] [wearer]'s [name].") + if(usr.machine == wearer && in_range(src, usr)) + wearer.show_inv(usr) + else + to_chat(usr, "You lack the ability to manipulate the lock.") + /obj/item/clothing/mask/muzzle/gag name = "gag" @@ -33,7 +93,7 @@ item_state = null w_class = WEIGHT_CLASS_TINY resist_time = 150 - mute = 0 + mute = MUTE_MUFFLE species_fit = list("Vox", "Unathi", "Tajaran", "Vulpkanin", "Grey") sprite_sheets = list( "Vox" = 'icons/mob/species/vox/mask.dmi', @@ -53,6 +113,14 @@ qdel(src) // This makes sure it gets deleted AFTER all that has to be done is done. user.emote("scream") +/obj/item/clothing/mask/muzzle/safety + name = "safety muzzle" + desc = "A muzzle designed to prevent biting." + mute = MUTE_NONE + security_lock = TRUE + locked = FALSE + + /obj/item/clothing/mask/surgical name = "sterile mask" desc = "A sterile mask designed to help prevent the spread of diseases." diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 2f489f3ea2d..5294e3bda91 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -135,6 +135,11 @@ var/const/MAX_ACTIVE_TIME = 400 if(target.wear_mask) if(prob(20)) return 0 + if(istype(target.wear_mask, /obj/item/clothing/mask/muzzle)) + var/obj/item/clothing/mask/muzzle/S = target.wear_mask + if(S.do_break()) + target.visible_message("[src] spits acid onto [S] melting the lock!", \ + "[src] spits acid onto [S] melting the lock!") var/obj/item/clothing/W = target.wear_mask if(W.flags & NODROP) return 0 diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index bdb9a359a09..be24a51e027 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -625,6 +625,13 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, dat += "Mask:[(wear_mask && !(wear_mask.flags&ABSTRACT)) ? wear_mask : "Empty"]" + if(istype(wear_mask, /obj/item/clothing/mask/muzzle)) + var/obj/item/clothing/mask/muzzle/M = wear_mask + if(M.security_lock) + dat += " [M.locked ? "Disable Lock" : "Set Lock"]" + + dat += " " + if(handcuffed) dat += "Handcuffed: Remove" if(legcuffed) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index a2235b3811c..23061d2a285 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -455,7 +455,14 @@ if(slot_wear_mask in obscured) dat += "Mask:Obscured" else - dat += "Mask:[(wear_mask && !(wear_mask.flags&ABSTRACT)) ? wear_mask : "Empty"]" + dat += "Mask:[(wear_mask && !(wear_mask.flags&ABSTRACT)) ? wear_mask : "Empty"]" + + if(istype(wear_mask, /obj/item/clothing/mask/muzzle)) + var/obj/item/clothing/mask/muzzle/M = wear_mask + if(M.security_lock) + dat += " [M.locked ? "Disable Lock" : "Set Lock"]" + + dat += " " if(!issmall(src)) if(slot_glasses in obscured) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 81664f631d4..aab36c844ec 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -163,10 +163,10 @@ proc/get_radio_key_from_channel(var/channel) if(is_muzzled()) var/obj/item/clothing/mask/muzzle/G = wear_mask - if(G.mute) //if the mask is supposed to mute you completely or just muffle you + if(G.mute == MUTE_ALL) //if the mask is supposed to mute you completely or just muffle you to_chat(src, "You're muzzled and cannot speak!") return - else + else if(G.mute == MUTE_MUFFLE) message = muffledspeech(message) verb = "mumbles" diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm index c1c3191c5ba..13f825d589d 100644 --- a/code/modules/reagents/chemistry/reagents/water.dm +++ b/code/modules/reagents/chemistry/reagents/water.dm @@ -357,22 +357,46 @@ M.SetConfused(0) return if(ishuman(M) && M.mind && M.mind.vampire && !M.mind.vampire.get_ability(/datum/vampire_passive/full) && prob(80)) - switch(current_cycle) - if(1 to 4) - to_chat(M, "Something sizzles in your veins!") - M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) - if(5 to 12) - to_chat(M, "You feel an intense burning inside of you!") - M.adjustFireLoss(1) - M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) - if(13 to INFINITY) - to_chat(M, "You suddenly ignite in a holy fire!") - for(var/mob/O in viewers(M, null)) - O.show_message(text("[] suddenly bursts into flames!", M), 1) - M.fire_stacks = min(5,M.fire_stacks + 3) - M.IgniteMob() //Only problem with igniting people is currently the commonly availible fire suits make you immune to being on fire - M.adjustFireLoss(3) //Hence the other damages... ain't I a bastard? - M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) + var/mob/living/carbon/V = M + if(M.mind.vampire.bloodusable) + M.Stuttering(1) + M.Jitter(30) + M.adjustStaminaLoss(5) + if(prob(20)) + M.emote("scream") + M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) + M.mind.vampire.bloodusable = max(M.mind.vampire.bloodusable - 20,0) + if(M.mind.vampire.bloodusable) + V.vomit(0,1) + else + holder.remove_reagent(id, volume) + V.vomit(0,0) + return + else + switch(current_cycle) + if(1 to 4) + to_chat(M, "Something sizzles in your veins!") + M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) + if(5 to 12) + to_chat(M, "You feel an intense burning inside of you!") + M.adjustFireLoss(1) + M.Stuttering(1) + M.Jitter(20) + if(prob(20)) + M.emote("scream") + M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) + if(13 to INFINITY) + to_chat(M, "You suddenly ignite in a holy fire!") + for(var/mob/O in viewers(M, null)) + O.show_message(text("[] suddenly bursts into flames!", M), 1) + M.fire_stacks = min(5,M.fire_stacks + 3) + M.IgniteMob() //Only problem with igniting people is currently the commonly availible fire suits make you immune to being on fire + M.adjustFireLoss(3) //Hence the other damages... ain't I a bastard? + M.Stuttering(1) + M.Jitter(30) + if(prob(40)) + M.emote("scream") + M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) ..()