Rags as ghetto muzzles & muzzle tweaks (#32628)

* Biting and kicking while handcuffed.

* Rags as ghetto muzzles and vampires not being able to bloodsuck while muzzled.

* Update click.dm

revert from another PR

* Update other_mobs.dm

* Update footprints_and_rag.dm

* Update human_defense.dm

* Update stripping.dm

* Update items.dm

* Update examine.dm

* Update examine.dm

* Update items.dm

* Rag in the mouth sprite.

* Change ingestion rate.

* .

* Muffled speaking with a rag in the mouth.

* Fix capitalization bug.

* Rags can't be equipped by mouthless creatures.

* Fix radio bug.

* Non-oral languages not being muzzled.

* Lollipops.

* No eating while muzzled.

* Update snacks.dm

* Check for slot for message when putting a goes_in_mouth item on someone.
This commit is contained in:
Hinaichigo
2022-05-23 02:24:16 -04:00
committed by GitHub
parent c2ac86e9e4
commit 43cea7901f
23 changed files with 120 additions and 34 deletions

View File

@@ -162,6 +162,8 @@
#define isfood(A) istype(A, /obj/item/weapon/reagent_containers/food)
#define ismuzzle(A) A.is_muzzle
#define iswirecutter(A) istype(A, /obj/item/tool/wirecutters)
#define iswiretool(A) (iswirecutter(A) || ismultitool(A) || issignaler(A))

View File

@@ -1065,9 +1065,10 @@ var/default_colour_matrix = list(1,0,0,0,\
//Language flags.
#define WHITELISTED 1 // Language is available if the speaker is whitelisted.
#define RESTRICTED 2 // Language can only be accquired by spawning or an admin.
#define CAN_BE_SECONDARY_LANGUAGE 4 // Language is available on character setup as secondary language.
#define WHITELISTED (1<<0) // Language is available if the speaker is whitelisted.
#define RESTRICTED (1<<1) // Language can only be accquired by spawning or an admin.
#define CAN_BE_SECONDARY_LANGUAGE (1<<2) // Language is available on character setup as secondary language.
#define NONORAL (1<<3) //Language is spoken without using the mouth, so can be spoken while muzzled.
// Hairstyle flags
#define HAIRSTYLE_CANTRIP 1 // 5% chance of tripping your stupid ass if you're running.
@@ -1824,3 +1825,7 @@ var/list/weekend_days = list("Friday", "Saturday", "Sunday")
#define COIN_HEADS "heads-up."
#define COIN_TAILS "tails-up."
#define COIN_SIDE "on the side!"
//Muzzles
#define MUZZLE_SOFT 1 //Muzzle causes muffled speech.
#define MUZZLE_HARD 2 //Muzzle prevents speech.

View File

@@ -368,7 +368,7 @@ var/list/rune_appearances_cache = list()
return
if(!user.checkTattoo(TATTOO_SILENT))
if(user.is_wearing_item(/obj/item/clothing/mask/muzzle, slot_wear_mask))
if(ismuzzle(user.wear_mask))
to_chat(user, "<span class='danger'>You are unable to speak the words of the rune because of \the [user.wear_mask].</span>")
return

View File

@@ -83,7 +83,7 @@ var/runedec = 0 // Rune cap ?
if(!islegacycultist(user))
to_chat(user, "You can't mouth the arcane scratchings without fumbling over them.")
return
if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle))
if(ismuzzle(user.wear_mask))
to_chat(user, "You are unable to speak the words of the rune.")
return
if(!word1 || !word2 || !word3 || prob(user.getBrainLoss()))

View File

@@ -1078,7 +1078,7 @@
possible_targets += cultistarget
else if (cultistarget.legcuffed)
possible_targets += cultistarget
else if (istype(cultistarget.wear_mask, /obj/item/clothing/mask/muzzle))
else if (ismuzzle(cultistarget.wear_mask))
possible_targets += cultistarget
else if (istype(cultistarget.loc, /obj/structure/closet))
var/obj/structure/closet/closet = cultistarget.loc
@@ -1105,7 +1105,7 @@
return
if(!(cultist.locked_to || \
cultist.handcuffed || \
istype(cultist.wear_mask, /obj/item/clothing/mask/muzzle) || \
ismuzzle(cultist.wear_mask) || \
(istype(cultist.loc, /obj/structure/closet)&&cultist.loc:welded) || \
(istype(cultist.loc, /obj/structure/closet/secure_closet)&&cultist.loc:locked) || \
(istype(cultist.loc, /obj/machinery/dna_scannernew)&&cultist.loc:locked) \
@@ -1117,7 +1117,7 @@
cultist.drop_from_inventory(cultist.handcuffed)
if (cultist.legcuffed)
cultist.drop_from_inventory(cultist.legcuffed)
if (istype(cultist.wear_mask, /obj/item/clothing/mask/muzzle))
if (ismuzzle(cultist.wear_mask))
cultist.u_equip(cultist.wear_mask, 1)
if(istype(cultist.loc, /obj/structure/closet))
var/obj/structure/closet/closet = cultist.loc

View File

@@ -164,8 +164,14 @@
if(ishuman(M))
var/mob/living/carbon/human/vamp_H = M
if(vamp_H.is_muzzled())
to_chat(M, "<span class='warning'> The [vamp_H.wear_mask] prevents you from biting!</span>")
return FALSE
if(vamp_H.check_body_part_coverage(MOUTH))
to_chat(M, "<span class='notice'>With practiced ease, you shift aside your mask for each gulp of blood.</span>")
return TRUE

View File

@@ -63,6 +63,8 @@
var/restraint_resist_time = 0 //When set, allows the item to be applied as restraints, which take this amount of time to resist out of
var/restraint_apply_time = 3 SECONDS
var/icon/wear_override = null //Worn state override used when wearing this object on your head/uniform/glasses/etc slot, for making a more procedurally generated icon
var/goes_in_mouth //Whether or not the item is described as "on his/her face" or "in his/her mouth" when worn on the face slot.
var/is_muzzle //Whether or not the item is a muzzle, and how strong the muzzling effect is. See setup.dm.
var/hides_identity = HIDES_IDENTITY_DEFAULT
var/datum/daemon/daemon
@@ -493,6 +495,11 @@
return CAN_EQUIP_BUT_SLOT_TAKEN
else
return CANNOT_EQUIP
if(goes_in_mouth && !H.hasmouth()) //Item is equipped to the mouth but the species has no mouth.
to_chat(H, "<span class='warning'>You have no mouth.</span>")
return CANNOT_EQUIP
return CAN_EQUIP
if(slot_back)
if( !(slot_flags & SLOT_BACK) )

View File

@@ -181,6 +181,7 @@ MATCHBOXES ARE ALSO IN FANCY.DM
source_temperature = TEMPERATURE_FLAME
light_color = LIGHT_COLOR_FIRE
slot_flags = SLOT_MASK|SLOT_EARS
goes_in_mouth = TRUE
var/lit = 0
var/overlay_on = "ciglit" //Apparently not used
var/type_butt = /obj/item/trash/cigbutt
@@ -558,13 +559,6 @@ MATCHBOXES ARE ALSO IN FANCY.DM
// CIGARS //
////////////
/obj/item/clothing/mask/cigarette/mob_can_equip(mob/M, slot, disable_warning = 0, automatic = 0)
var/mob/living/carbon/C = M
if(!istype(C) || !C.hasmouth())
to_chat(C, "<span class='warning'>You have no mouth.</span>")
return CANNOT_EQUIP
. = ..()
/obj/item/clothing/mask/cigarette/cigar
name = "Premium Cigar"
desc = "A large roll of tobacco and... well, you're not quite sure. This thing's huge!"

View File

@@ -27,11 +27,11 @@ LINEN BINS
if(I.is_sharp())
cut_time = 60 / I.sharpness
if(cut_time)
to_chat(user, "<span class='notice'>You begin cutting the [src].</span>")
to_chat(user, "<span class='notice'>You begin cutting up [src].</span>")
if(do_after(user, src, cut_time))
if(!src)
return
to_chat(user, "<span class='notice'>You have cut the [src] into rags.</span>")
to_chat(user, "<span class='notice'>You finish cutting [src] into rags.</span>")
var/turf/location = get_turf(src)
for(var/x=0; x<=8; x++)
var/obj/item/weapon/reagent_containers/glass/rag/S = new/obj/item/weapon/reagent_containers/glass/rag/(location)
@@ -45,7 +45,6 @@ LINEN BINS
//todo: more cutting tools?
//todo: sharp thing code/game/objects/objs.dm
/obj/item/weapon/bedsheet/blue
icon_state = "sheetblue"
_color = "blue"

View File

@@ -10,6 +10,7 @@
species_fit = list(VOX_SHAPED, INSECT_SHAPED, GREY_SHAPED)
origin_tech = Tc_BIOTECH + "=2"
body_parts_covered = MOUTH
is_muzzle = MUZZLE_HARD
//Monkeys can not take the muzzle off of themself! Call PETA!
/obj/item/clothing/mask/muzzle/attack_paw(mob/user as mob)

View File

@@ -15,10 +15,15 @@
w_class = W_CLASS_TINY
icon = 'icons/obj/toy.dmi'
icon_state = "rag"
item_state = new/icon("icon" = 'icons/mob/mask.dmi', "icon_state" = "rag")
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(5)
volume = 5
can_be_placed_into = null
slot_flags = SLOT_MASK
body_parts_covered = MOUTH
goes_in_mouth = TRUE
is_muzzle = MUZZLE_SOFT
var/mob/current_target = null
/obj/item/weapon/reagent_containers/glass/rag/attack_self(mob/user as mob)
@@ -99,3 +104,25 @@
qdel(O)
reagents.remove_any(1)
user.visible_message("<span class='notice'>[user] finishes wiping down \the [target].</span>", "<span class='notice'>You have finished wiping down \the [target]!</span>")
/obj/item/weapon/reagent_containers/glass/rag/process()
//Reagents in the rag gradually get transferred into the wearer. Copied from cigs_lighters.dm.
var/mob/living/M = get_holder_of_type(src, /mob/living)
if(reagents && reagents.total_volume) //Check if it has any reagents at all
if(iscarbon(M) && ((src == M.wear_mask) || (loc == M.wear_mask))) //If it's in the human/monkey mouth, transfer reagents to the mob
if(M.reagents.has_any_reagents(LEXORINS) || istype(M.loc, /obj/machinery/atmospherics/unary/cryo_cell))
reagents.remove_any(REAGENTS_METABOLISM)
else
reagents.reaction(M, INGEST)
reagents.trans_to(M, 0.5)
else
processing_objects.Remove(src)
/obj/item/weapon/reagent_containers/glass/rag/equipped(mob/living/carbon/human/H, equipped_slot)
..()
if(istype(H) && H.get_item_by_slot(slot_wear_mask) == src && equipped_slot != null && equipped_slot == slot_wear_mask)
processing_objects.Add(src)
/obj/item/weapon/reagent_containers/glass/rag/unequipped(mob/living/carbon/human/user, from_slot = null)
..()
processing_objects.Remove(src)

View File

@@ -138,6 +138,7 @@
exclaim_verb = "rustles"
colour = "soghun"
key = "q"
flags = NONORAL
syllables = list("hs","zt","kr","st","sh")
/datum/language/common
@@ -221,6 +222,7 @@
colour = "sinister"
native=1
space_chance = 95
flags = NONORAL
syllables = list("CLICK", "CLACK")
/datum/language/golem
@@ -233,6 +235,7 @@
colour = "golem"
native = 1
key = "8"
flags = NONORAL
syllables = list("oa","ur","ae","um","tu","gor","an","lo","ag","oon","po")
/datum/language/slime
@@ -245,6 +248,7 @@
colour = "slime"
native = 1
key = "f"
flags = NONORAL
syllables = list("ba","ab","be","eb","bi","ib","bo","ob","bu","ub")
/datum/language/skellington/say_misunderstood(mob/M, message)

View File

@@ -462,8 +462,8 @@
return borers_in_mob
/mob/living/carbon/is_muzzled()
return(istype(get_item_by_slot(slot_wear_mask), /obj/item/clothing/mask/muzzle))
var/obj/item/M = get_item_by_slot(slot_wear_mask)
return M?.is_muzzle
/mob/living/carbon/proc/isInCrit()
// Health is in deep shit and we're not already dead

View File

@@ -131,9 +131,9 @@
//mask
if(wear_mask && !(slot_wear_mask in obscured) && wear_mask.is_visible())
if(wear_mask.blood_DNA && wear_mask.blood_DNA.len)
msg += "<span class='warning'>[t_He] [t_has] [bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] blood-stained [wear_mask.name] on [t_his] face! [format_examine(wear_mask, "Examine")][wear_mask.description_accessories()]</span>\n"
msg += "<span class='warning'>[t_He] [t_has] [bicon(wear_mask)] [wear_mask.gender==PLURAL?"some":"a"] blood-stained [wear_mask.name] [wear_mask.goes_in_mouth ? "in" : "on"] [t_his] [wear_mask.goes_in_mouth ? "mouth" : "face"]! [format_examine(wear_mask, "Examine")][wear_mask.description_accessories()]</span>\n"
else
msg += "[t_He] [t_has] [bicon(wear_mask)] \a [wear_mask] on [t_his] face. [format_examine(wear_mask, "Examine")][wear_mask.description_accessories()]\n"
msg += "[t_He] [t_has] [bicon(wear_mask)] \a [wear_mask] [wear_mask.goes_in_mouth ? "in" : "on"] [t_his] [wear_mask.goes_in_mouth ? "mouth" : "face"]. [format_examine(wear_mask, "Examine")][wear_mask.description_accessories()]\n"
//eyes
if(glasses && !(slot_glasses in obscured) && glasses.is_visible())

View File

@@ -90,7 +90,7 @@ emp_act
var/siemens_coefficient = 1.0
var/list/clothing_items = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) // What all are we checking?
for(var/obj/item/clothing/C in clothing_items)
for(var/obj/item/C in clothing_items)
if(istype(C) && (C.body_parts_covered & def_zone.body_part)) // Is that body part being targeted covered?
siemens_coefficient *= C.siemens_coefficient
@@ -136,7 +136,7 @@ emp_act
if(!body_part_flags)
return 0
var/parts_to_check = body_part_flags
for(var/obj/item/clothing/C in get_clothing_items())
for(var/obj/item/C in get_clothing_items())
if(!C)
continue
if(ignored && C == ignored)
@@ -151,7 +151,7 @@ emp_act
/mob/living/carbon/human/proc/get_body_part_coverage(var/body_part_flags=0)
if(!body_part_flags)
return null
for(var/obj/item/clothing/C in get_clothing_items())
for(var/obj/item/C in get_clothing_items())
if(!C)
continue
//Check if this piece of clothing contains ALL of the flags we want to check.
@@ -163,7 +163,7 @@ emp_act
//Because get_body_part_coverage(FULL_BODY) would only return true if the human has one piece of clothing that covers their whole body by itself.
var/body_coverage = FULL_BODY | FULL_HEAD
for(var/obj/item/clothing/C in get_clothing_items())
for(var/obj/item/C in get_clothing_items())
if(!C)
continue
body_coverage &= ~(C.body_parts_covered)

View File

@@ -11,7 +11,7 @@
return 2
/mob/living/carbon/monkey/unarmed_attack_mob(mob/living/)
if(istype(wear_mask, /obj/item/clothing/mask/muzzle))
if(ismuzzle(wear_mask))
to_chat(src, "<span class='notice'>You can't do this with \the [wear_mask] on!</span>")
return

View File

@@ -7,7 +7,8 @@
if (src.hat && hat.is_visible())
msg += "It is wearing [bicon(src.hat)] \a [src.hat] on its head.[hat.description_accessories()][hat.description_hats()]\n"
if (src.wear_mask && !(wear_mask.invisibility || wear_mask.alpha <= 1))
msg += "It has [bicon(src.wear_mask)] \a [src.wear_mask] over its face.\n"
msg += "It has [bicon(src.wear_mask)] \a [src.wear_mask] [wear_mask.goes_in_mouth ? "in" : "over"] its [wear_mask.goes_in_mouth ? "mouth" : "face"].\n"
if (src.glasses && glasses.is_visible())
msg += "It is wearing [bicon(src.glasses)] \a [src.glasses] over its eyes.\n"

View File

@@ -104,7 +104,10 @@
return
if(!pickpocket)
visible_message("<span class='danger'>\The [user] is trying to put \a [held] on \the [src]!</span>")
if(held.goes_in_mouth && slot == SLOT_MASK)
visible_message("<span class='danger'>\The [user] is trying to put \a [held] in \the [src]'s mouth!</span>")
else
visible_message("<span class='danger'>\The [user] is trying to put \a [held] on \the [src]!</span>")
if(reversestrip_into_slot(user, slot, pickpocket))
user.attack_log += text("\[[time_stamp()]\] <font color='red'>Has put \a [held] into [src.name]'s [src.slotID2slotname(slot)] ([src.ckey])</font>")

View File

@@ -163,6 +163,7 @@ var/list/headset_modes = list(
speech.language = parse_language(speech.message)
say_testing(src, "Getting speaking language, got [istype(speech.language) ? speech.language.name : "null"]")
if(istype(speech.language))
#ifdef SAY_DEBUG
var/oldmsg = message
#endif
@@ -180,6 +181,17 @@ var/list/headset_modes = list(
speech.language = get_default_language()
say_testing(src, "Didnt have a language, get_default_language() gave us [speech.language ? speech.language.name : "null"]")
speech.message = trim_left(speech.message)
//Handle speech muffling by muzzles.
if(!(speech?.language?.flags & NONORAL))
var/mob/living/carbon/C = src
switch(C.is_muzzled())
if(MUZZLE_SOFT)
speech.message = muffle(speech.message)
if(MUZZLE_HARD)
qdel(speech)
return
if(handle_inherent_channels(speech, message_mode))
say_testing(src, "Handled by inherent channel")
qdel(speech)
@@ -377,9 +389,6 @@ var/list/headset_modes = list(
if(is_mute())
return
if(is_muzzled())
return
if(!IsVocal())
return
@@ -727,3 +736,30 @@ var/list/headset_modes = list(
/obj/effect/speech_bubble
var/mob/parent
//Muffles a message for when muzzled.
/proc/muffle(var/message)
var/muffle_syllables = list("mh","mph","mm","mgh","mg")
var/unmuffled = list(" ", "-", ",", ".", "!", "?")
var/output = ""
var/i = 1
var/current_char
while(i <= length(message))
current_char = message[i]
if(current_char in unmuffled)
output += current_char
i += 1
else
var/length_to_add = 1
var/allcaps = uppertext(message[i]) == message[i]
while((i + length_to_add <= length(message)) && (length_to_add < 3))
if(message[i + length_to_add] in unmuffled)
break
allcaps &= uppertext(message[i + length_to_add]) == message[i + length_to_add]
length_to_add += 1
i += length_to_add
if(allcaps)
output += uppertext(pick(muffle_syllables))
else
output += pick(muffle_syllables)
return output

View File

@@ -189,4 +189,4 @@ var/list/global_deadchat_listeners = list()
temp += pick(append)
say(temp)
winset(client, "input", "text=[null]")
winset(client, "input", "text=[null]")

View File

@@ -5243,6 +5243,7 @@
icon = 'icons/obj/candymachine.dmi'
bitesize = 5
slot_flags = SLOT_MASK //No, really, suck on this.
goes_in_mouth = TRUE
attack_verb = list("taps", "pokes")
eatverb = "crunch"
valid_utensils = 0

View File

@@ -401,7 +401,7 @@ var/list/spells = typesof(/spell) //needed for the badmin verb for now
return 0
if((ishuman(user) || ismonkey(user)) && !(invocation_type in list(SpI_EMOTE, SpI_NONE)))
if(istype(user.wear_mask, /obj/item/clothing/mask/muzzle))
if(ismuzzle(user.wear_mask))
to_chat(user, "Mmmf mrrfff!")
return 0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB